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.
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?
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.
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.
This question already has an answer here:
iOS Server Side Validation - receipt types
(1 answer)
Closed 3 years ago.
Right now, when I send a receipt to the sandbox server (sandbox.itunes.apple.com) for one transaction, I am returned information for all of the transactions associated with the Apple account. Is this expected behavior? Is anyone else experiencing this?
Yes, receipt contains information about all transactions that was made by app. But you should consider very important issue:
The in-app purchase receipt for a consumable product 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.
The in-app purchase receipt for a non-consumable product,
auto-renewable subscription, non-renewing subscription, or free
subscription remains in the receipt indefinitely.
https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html
I'm trying to work out the best mechanism to handle the auto renewing part so that it handles the continuation of the subscription into the next period.
What the best way of handling this?
Should I have an NSTimer set to check if the current expires_date has been reached .. and then try send a purchase request?
Apple iOS in-app purchases provides the product "Auto-renewable subscription". This product will be renewed automatically by Apple.
When you use this type of product, your app has to verify if the auto-renewable subscription is still valid, since the user might have cancelled the subscription. When an user cancel a subscription, the subscription remains valid until the end of the subscription period.
To validate an auto-renewable subscription, you have to use the purchase receipt and the shared secret generated for your app in-app purchases in iTunes Connect. You have to post this two things to the App Store. This will return a JSON and you have to get from this data the "
subscription's latest purchase date". From that date you have to calculate the expiration date and validate or invalidate the subscription.
You can do all this validation after application launch and/or when the model is updated.
Additional information
You can find information about auto-renewable subscription in Apple documentation. Also, you can check about MKStoreKit, which is a framework that reduces the amount of code that you have to write for the use of StoreKit, and supports Auto-renewable subscriptions.