We're using in-app purchases in our app and validating receipts on server side.
As a result of validation we get Receipt object described here. We store the transaction_id in our records as a unique identifier of the purchase.
Then, some time after the purchase a user who made a purchase in our app looks at Purchase History in the iTunes app and see this identifiers:
Question:
How can we match this identifiers with the validated receipt?
For example, it's useful in the case when users contact us via support channels and want to restore their accounts.
Related
What is the correct workflow to online validate the in-app purchase of non-consumable IAPs on iOS?
While I found a lot of information about in-app purchases in general I found no details on how to actually perform online validation.
Is the following workflow correct and complete or am I missing something?
General setup:
iOS app starts purchase by adding an SKPaymentQueue to the payment queue
iOS calls paymentQueue:updatedTransactions: with transaction.transactionState == SKPaymentTransactionStatePurchased when purchase is complete
At this time the app receipt has already been updated and the purchase of the non-consumable item was added.
The receipt data and transaction.transactionIdentifier are send via HTTP POST to my own web service
The web service POSTs the data to Apples /verifyReceipt endpoint
Apples server response with an error if the receipt is invalid or with detailed JSON data if receipt is valid
The JSON Data received from Apple includes information about all prior non-consumable and subscription purchases AND the current consumable purchase.
The information about the consumable purchase can be identified by the product_id field or by using the transaction.transactionIdentifier
The web service adds the purchase to the current user account and/or sends back an valid/invalid response to the iOS app.
If necessary (when the purchase is not stored/handled online) the iOS app can handle the purchase (add coins, or whatever)
The transaction is closed using [queue finishTransaction:transaction]
Additional Observations:
The receipt includes information about all prior non-consumable and subscription purchases AND the current/last consumable purchase.
The information about the current consumable purchase is available until the next purchase (no matter if consumable, non-consumable or subscription).
Restarting the app does not destroy the information about the current consumable purchase
When the app is deleted and re-installed the receipt is empty / does not exist. After restoring previous purchases the receipt only includes information about non-consumable and subscription purchases. No information about non-consumable purchases is restored (no surprise)
Conclusion:
If (for some reason) the receipt cannot send be to the web service (server down, no connection, etc.), this can be retry later. The purchase data will be available within the receipt until the next purchase.
To be able to access the receipt data even after the next purchase one has to implement a custom storage method (e.g. save receipt data to file).
This way the user can be informed about outstanding validations and a retry option can be offered.
Is this a complete and valid workflow to validate consumable in-app purchases online or am I missing some special cases?
I am implementing In-App Purchases first time in my application and new to In-app purchases Store Kit.
I have few doubts regarding In-app purchases:
What happens if a user purchased a subscription and logged out from the application and another user logs in and trying to purchase the same?
Does iTunes allow the second user to use the First user's purchased product?
If it allows how can we handle the second user's subscription?
What details we will get post Successful/Failed transactions from itunes to save in my database?
For a non-renewing subscription then it is entirely up to you to track expiration and determine what content a user has access to and when.
For example, say your subscription gave access to "the word of the day". If the subscription was active for the month of January, then the user would receive access to new words each day in January. The user should continue to be able to see January's words even after the subscription expires, but no new words.
If they resubscribe in March then they would now get new words throughout March.
You need to track all of this on your server against the user account.
Non-renewable subscription IAPs act much like consumable IAPs. The "Restore purchases" Store Kit function does not restore non-renewable IAP items.
To answer your specific questions:
If a new user logs in to your account system in the app (but the same iTunes account is still active on the device) then a second purchase will succeed and you need to update the subscription start and end dates for the new active account on your server.
You also need to cater for the following:
- The original account logs back in; In this case the original subscription entitlements need to be available
- The original or second account log in to another device; Again, the accounts subscription entitlements need to be available.
No, since non-renewing subscriptions are not restorable, the second user cannot "use" the first user's subscription.
You handle each account in your system independently.
Information about the mechanics of the purchase process are described in the In App Purchase Programming Guide
here's my straightforward question:
is it allowed for my iOS application to force users to log into my custom account management system, so I can link them to my backend when they want to purchase a non-renewing subscription?
Here's the backstory:
I have a non-renewing subscription. For a good amount of users I can see that the Apple receipt does not contain information about this subscription; the in_app array is empty. This is correct according to the API:
https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/Products.html
The in-app purchase receipt for a consumable product or non-renewing subscription is added to the receipt when the purchase is made. It is kept in the receipt until your app finishes that transaction. After that point, it is removed from the receipt the next time the receipt is updated—for example, when the user makes another purchase or if your app explicitly refreshes the receipt
For some users, I can still see the purchase in the receipt, but let's consider that a bug from Apple and follow their API documentation to the letter.
(More on why this is a bug here https://forums.developer.apple.com/thread/22345)
In order to restore the user's purchase, I'd need something to identify him with. I could create a unique token, store that on the iCloud keychain and use that across the devices to detect the purchase belongs to that Apple account, but since my application supports account creation, I'd rather just use that mechanism. Else I'm using two different methods of purchase detection side by side: iCloud keychain token or a user account.
Thing is, I'm not sure I am allowed to force users to make an account before making a purchase. Is this something Apple would reject the app submission for with a message like "Your users must be able to buy stuff without going through your lengthy account registration process" ?
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.
https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/Products.html
So its your app's responsibility to check that user has valid subscription or its over and let them purchase it again !
For this you will ask user to first make account or login into app so by this way you can track their subscriptions.
I have implemented the IAP for Consumable Products in my app. I have couple of queries regarding validating the receipt. I am going to use my own server which will communicate with apple server.
1.) Does the below url will contain the most recent receipt or all the receipts (even the old ones)?
NSBundle.mainBundle().appStoreReceiptURL
2.) If the above url stores all the receipts then do i need to verify all the receipts whenever user purchase a new product?
3.) Does the user will have access to these receipts if he chooses to reinstall the application?
Refer: In-App Purchase Programming Guide
https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/DeliverProduct.html#//apple_ref/doc/uid/TP40008267-CH5-SW16
Information about consumable products and non-renewing subscriptions
is added to the receipt when they’re paid for and remains in the
receipt until you finish the transaction. After you finish the
transaction, this information is removed the next time the receipt is
updated—for example, the next time the user makes a purchase.
Information about all other kinds of purchases is added to the receipt
when they’re paid for and remains in the receipt indefinitely.
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.