I've set up a non-consumable in app purchase for may app, it all works well except i haven't yet decided on the correct RestoreTransaction procedure.
Apple suggest storing a list of completed transactions in NSUserDefaults, but why?
If the customer resets the device then surely this list is lost so its a non starter?
Can anyone tell me from their experience, if I do need to list completed items and if I need to validate the receipt with apple for non-consumable purchase.
I can't see why either of these should be done for non-consumable products.
Doesn't Apple verify the purchase from OriginalTransaction when restoreCompletedTransactions is called?
Related
To be clear on my question, I am in the process of implementing a iOS IAP receipt validation (consumables) and I was not expecting more then just the item(s) the user 'currently' purchased in the 'current' transaction.
So lets say the user purchases one (1) $0.99USD item that gets them 100 coins I am expecting to see in the receipt using my validation code the one (1) transation detailing the one (1) product they purchased not an array of items from previous purchases which I found out that:
With iOS 7, Apple started using something they call the “Grand Unified Receipt”. Apps retain one receipt that contains information about the purchase of the app itself, as well as IAPs.
So my question is if anyone else has an issue with the receipt format and how have everyone been validating the purchases for consumables when the entire user purchase history is always present?
I have created Auto renewable products and testing in sandbox environment. My question is I have purchased one product, and If I try to purchase same product with same Apple account it is showing alert as already purchased as expected but I could not able to fetch that transaction details as it is executing failed state in updated transactions. How I can get that purchased details (atleast original receiptID) as we get in Initial transaction.
There is two way to get user purchased transaction details:
Refresh receipt
Restore completed transaction
To know more about difference between refreshing receipt & restore transaction in details, Please check:- SKReceiptRefreshRequest vs restoreCompletedTransactions
In Simply,
Refreshing the receipt asks the App Store for the latest copy of the receipt.
Restoring completed transactions creates a new transaction for every completed transaction the user made, essentially replaying history for your transaction queue observer.
Question:
How I can get that purchased details (atleast original receiptID) as we get in Initial transaction.
Answer: If you want to verify user with original receiptID every time each time than user SKReceiptRefreshRequest for validating user transaction.
Note: Anytime if you validating user with RestoreCompletedTransactions, Your transactionID will change.
Find list of parameter that change while restoreTransaction: https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html#//apple_ref/doc/uid/TP40010573-CH106-SW1
You have to implement a mechanism of restoring the purchased products in your app.
For more info about what exactly is restoring purchased products:
Restore Purchased Products
To get to the implementation part, you can follow this tutorial:
In App Purchase tutorial
The later part of the tutorial will guide you through the implementaiton of restore purchase.
By validating Receipts With the App Store you can able to find which products identifiers are already purchased. There are Cocoapods libraries you can use to find out the purchased products.
SwiftyStoreKit
DHAppleReceiptParser
IAPValidation
I hope it will helps to you.
I'm trying to add purchases to my application. But I don't know how to check if purchase is already bought. As far as I understand when somebody bought purchase I need to store this into UserDefaults or KeyChain and then check if it is already there (it mean that this purchase is already bought). But what about when user bought this purchase prom another device?
I have code that give me information about all purchases in iTunes.
func productsRequest(request: SKProductsRequest!, didReceiveResponse response: SKProductsResponse!) {
}
Response object have two variables: "products" and "invalidProductIdentifiers". But as I understand products contain all products from iTunes and invalidProductIdentifiers contain all identifiers that I was asking to check for but Apple can't recognise them. So where I can check if purchase was already bought or not.
Assuming iOS 7+, you should be validating the receipt, ala A complete solution to LOCALLY validate an in-app receipts and bundle receipts on iOS 7 to determine what's purchased, what's valid (in the case of subscriptions or consumables), and as noted in the other comment, offer a "Restore Purchases" UI element which allows users to cleanly propagate sharable purchases to a newly restored/acquired device.
AFA the response object, that is catalog (purchasable items) information, not info on what has been purchased. In order to have IAP work correctly, assets are to be approved by Apple similarly to the app itself as well as being under "ready for sale" control of your own in iTunes Connect. For that pass, you send Apple a complete list of the times you want to offer and Apple returns to you the list split into the "if your user tries to buy this, they will succeed" (the products) and "if your user tries to buy this, they will fail" (the invalidProductIdentifiers).
When you're testing with sandbox/iTunes Connect Test users, your products do not need to be approved by Apple, but for production code they do.
My app got rejected because of restore button on non-renewing in app purchase. Do i have to remove restore button ? If i have to do so then how user will restore his purchases.Please help.
Non-renewing subscriptions are consumable. Therefore they cannot be restored. A restore button therefore makes no sense. You also need some kind of authentication/login system for the user. (See below for detailed explanations.)
Sources:
consumable vs. non-consumable in app purchases
non-renewing subscriptions
Update from WWDC2017: In Session #303 App Store Engineer Pete Hare explains at 3:00 that a non-renewing-subscription can be seen as "a consumable product with an expiry date on it"
There has been some debates in the comments wether non-renewing subscriptions are consumable or not, so I want to say something about it. "Consumable" means that you can consume them multiple times. Like "30 minutes of talking" in a voice-over-IP telephony application. On the other hand, there are non-consumables that you can buy only once. Like when you unlock all levels in a game app. You buy it once, and when you reset the device and redownload the app, you should be able to restore the purchase, so that you don't have to pay twice to unlock all levels. Furthermore, if you don't tap the restore-button in this case but just buy the "unlock all levels" package again, it works, but you will not be charged by apple a second time. That's why it is called non-consumable. It's some kind of metapher. An apple is "consumable". Once it is consumed, it is gone. A chair is non-consumable. You have it as long as you don't destroy it or give it away.
So, it makes sense to regard a non-renewing subscription as non-consumable. If you buy it a second time, you shouldn't pay twice, you should just use the old subscription you already have. If you reset the device, you should be able to restore the subscription once you re-download the app. The restoration is just not done by Apple but by the app itself.
I still regard non-renewing subscriptions as consumable though. I use a simple definition of consumable vs. non-consumable: An in-app-purchase is consumable, when, from the point of view of the StoreKit API, it can be purchased multiple times in the same week by the same user. All consumable IAP-items cannot be restored through the StoreKit. All non-consumable IAP-items can be restored through the StoreKit.
So, the developer is himself responsible for restoring the in-app-purchase of a non-renewing subscription, right? No, sorry. How would the app restore the in-app-purchase of a non-renewing subscription? Suppose I have an iPod and I subscribe to 1 month of listening to the Foo-radio. Now I want to also listen to the Foo-Radio on my iPad. Soo, I install the Foo-App on my iPad and tap the "restore" button. Well... what is the "restore" button supposed to do? How can it know if I already have purchased a "Foo"-subscription or not, and how long it will still be valid? Answer: it can not. This approach does not work.
In order for a non-renewing subscription to work, you have to login the user first, to tie the subscription to some online account. Username/Password, Open-ID, Login via Gmail, Facebook, etc. all would work. Then, when the user purchases an n-r subscription you have to store the fact that he subscribed on some server and link it to his account on the server. You also have to prevent the user from buying the n-r subscription when he is not already logged in. Let's continue with my iPod/iPad-example above. I download the app on my iPad, I login with Facebook, and voila, I can use the "Foo"-subscription now. There is no need for a "restore" button, because the app should check at login-time which subscriptions the user has.
There will be some additional problems to deal with. (1) For example, nothing prevents the user from logging in into 200 devices. Here the problem is not a user with 200 devices, but a university with 1000 students where 180 students share the same account. (2) If the server crashes, some people will probably lose their subscriptions. Problem (1) can potentially lead to decreased income. Problem (2) can lead to angry and unhappy customers.
From Apple: "Non-renewable subscriptions. Subscriptions that don’t involve delivering episodic content. Examples include access to a database of historic photos or a collection of flight maps. It’s your app’s responsibility to make the subscription available on all of the user’s devices and to let users restore the purchase. This product type is often used when your users already have an account on your server that you can use to identify them when restoring content. Expiration and the duration of the subscription are also left to your app (or your server) to implement and enforce." [Italics and bold added] https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/Products.html
Apple Reviewer's current-similar response about Non-Renewing Subscriptions "Your app offers Non-Renewing Subscriptions and this purchasability type must have its own restoring function - if you have removed it please re-implement it. Furthermore, your app must also offer a function, such as account creation, such that purchases can be tracked across all of a user's devices. Please implement a login feature as well as a restore mechanism prior to resubmitting your revised binary for review."
I just wonder if there is anyway to check if a user(email) already buy an in app purchase item in my application.
For example I buy an item on my iPhone, then I log in on my iPad with same itune account. the application will know that this user did buy the item.
Thanks,
Huy
The same thing is happening when you use the restore purchased option in many applications.
SKPaymentTransactionStateRestored
is the constant retrieved from server when you tries to purchase an already purchased item.
Please check this nice tutorial about inApp purchase : inApp purchases
From the In-App Purchase Programming Guide:
Store Kit provides built-in functionality to restore transactions for
non-consumable products, auto-renewable subscriptions and free
subscriptions.
You can restore purchases with the StoreKit framework by calling the restoreCompletedTransactions method of the SKPaymentQueue. Your app will then receive a transaction for each product the user has previously purchased. Simply handle these transaction and unlock the features and/or download content on the new device.
If your product is a consumable (gold coins for your game, health packs etc.) this would not apply and you have to keep track of the purchases on your own.
You will need to set up a server that will keep track of each transaction. And you need to implement a method to authenticate the user across devices (signup via e-mail, Facebook login etc.). Once the user logs in on a new device, your server can tell the app what it should unlock/download.