Apple finally introduced the so called auto-renewable subscriptions yesterday. Since I only have few (sandbox-only) experiences with in-app-purchase, I’m not sure that I got it all right here. It seems one needs a server side verification of the receipts. It seems the only way to find out if the subscription is still valid, is to store the original transaction data on server side. Apples programming guide with respect to this topic is all cryptic to me.
My expectation was, that I can work with an iOS client only, by just asking iTunes via store kit api did he/she already buy this (subscription-)product and receiving a yes/no answer together with an expiration date.
Does anyone have experiences with auto-renewable subscriptions or (because they seem somehow similar) non-consumable products? Are there any good tutorials about this?
Thank you.
I have it running in the sandbox, almost going live…
One should use a server to verify the receipts.
On the server you can record the device udid with the receipt data, since receipts are always freshly generated, and it will work across multiple devices, since the receipts are always freshly generated.
On the device one does not need to store any sensitive data, and should not 🙂
One should check the last receipt with the store whenever the app comes up. The app calls the server and the server validates with the store. As long as the store returns a valid receipt app serves the feature.
I developed a Rails3.x app to handle the server side, the actual code for the verification looks like this:
UPDATE
My app got rejected, because the meta data was not clearly stating some info about the auto-renewable subscriptions.
UPDATE II
App got rejected again. The subscription receipt is not verified by the production AppStore verify url. I can not reproduce this problem in the sandbox, my app works flawless. The only way to debug this, is to submit the app again for review and look at the server log.
UPDATE III
Another rejection. Meanwhile Apple documented two more statuses:
Before one submits the app for review, one should not switch the server to production
receipt verify url. if one does, one gets status 21007 returned on verification.
This time the rejection reads like this:
I have no clue why this happens. Does the password dialog pop up because a previous transaction is being restored? or does it pop up at the point of requesting products information from the app store?
UPDATE IV
I got it right after 5 rejections. My code was doing the most obvious error. One should really make sure to always finish transactions when they are delivered to the app.
If transactions aren’t finished, they get delivered back to the app and things go strangely wrong.
One needs to initiate a payment first, like this:
Then the app will shortly resign its active state and this method on the app delegate is called:
While the app is inactive, the App Store pops up its dialogs. as the app becomes active again:
The OS delivers the transaction through:
And then one completes the transaction:
See, how one calls the method
finishTransactionright after passing the received transaction torecordTransaction, which then calls the apps server and does the subscription receipt verification with the App Store. Like this:Previously my code was trying to call
finishTransactiononly after my server verified the receipt, but by then the transaction was somehow lost already. so just make sure tofinishTransactionas soon as possible.Also another problem one can run into is the fact, that when the app is in the sandbox it calls the sandbox App Store verification url, but when it is in review, it is somehow between worlds. So i had to change my server code like this:
So basically one always verifies with the production URL, but if it returns 21007 code, then it means a sandbox receipt was sent to the production URL and then one simply tries again with the sandbox URL. This way your app works the same in sandbox and production mode.
And finally Apple wanted me to add a RESTORE button next to the subscription buttons, to handle the case of multiple devices owned by one user. This button then calls
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];and the app will be deliver with restored transactions (if any).Also, sometimes the test user accounts get contaminated somehow and things stop working and you may get a “Can not connect to iTunes store” message when subscribing. It helps to create a new test user.
Here is the rest of the relevant code:
}
I wish you a smooth InAppPurchase programming experience. 🙂