Non-Renewing Subscription Restoration - ios

Background:
Apple requires you to implement a restoration mechanism to this type of purchases to let users to get back their purchases after wiping the device or to view purchases from user's other device.
One accepted approach form apple for doing this is to do an optional user registration and handle it on your server to save the transaction receipts. since apple don't do that like other type of purchases as non-consumable. which allow you to get all the receipts of the users to restore them.
Apple say that the registration should be optional. but we must indicate to the user that registration is required to view purchases from other devices.
My Suggested Approach:
I am going to implement the restoration mechanism by saving the purchases receipts in iCloud. I will indicate that logging into iCloud is required to access the subscription content from user's other iOS devices.
On purchasing succeeded app. will check if iCloud is available to save the subscription details(Transaction Receipt) Otherwise, subscriptions will be saved to User Defaults. Every time the app. is launched it will check if iCloud available and iCloud will be synced with User Defaults. subscriptions details available on User Defaults and not on the iCloud will be copied to the iCloud and the subscriptions that are available on iCloud and not on User Defaults will be copied to User Defaults.
Thats provide users the flexibility to login to iCloud in a future time just to move their subscriptions to another devices or just before they decided to delete the app. to save their subscription. (That all will exactly perform as we had the user registration option). Is that accepted?
Another thing. My app. suppose to work on iOS 4.x too. which mean that iCloud is not available. Is that ok too? or I have to give up running app. on iOS 4.x if I want to use iCloud approach? what if I also indicated that restoration will not be available for iOS 4.x?

One way is that , the restoration of payment and other data should be handle by your application or by your side on the server. But i think it will increase your burden of coding. But registration is optional and if user wants that he will be able to use application on his other iOS devices also then u can make registration compulsory, otherwise the restoration of payment or data should be done using keychain.
If u have still doubt then let me know.

So, in this case what if a user makes a purchase without signing into his iCloud account? We won't be providing him the content access on his other device in that case, right?
Is there any way to handle that scenario? Are we allowed to store the user's id and password into the iCloud? This may help us, but won't be a good idea to store the credentials.

Related

iOS/macOS In app purchases - what to save in KeyChain

I am implementing In app purchases for one of my apps which is cross platform (iOS + macOS). The way I implemented non-consumable IAP, is to save a flag in keychain for a specific key after the purchase was made. (e.g value true for the key com.app.prodctId) and just check at runtime if that flag exists and what the value is. However, this seems very insecure because some users might just add the key with the specific value in keychain, thus gaining acces to the locked feature without purchasing it. A solution to this would be to encrypt(or hash the data using a salt) the flag before saving it, but I would need to have a separate key for each iCloud account (so the user can enjoy the produc ton all devices across his iCloud account) and I am not really sure what this can be.
Is there anything that can be fetched per iCloud account so I can use as encryption key/salt for a hash? Or is there a better way to manage non-consumable in app purchases?
For every user downloading your app, Apple creates a receipt containing some meta-information (which app version the user downloaded, when, and so on).
When your app offers in-app purchases, those are also saved in the receipt. Since this receipt is automatically synced with all devices of the user, it is the right choice to check what a user bought and unlock the content on all of his devices correspondingly.
See here for an article from Apple about receipt validation techniques.
If you choose the local (on-device) receipt validation, I recommend you to use the TPInAppReceipt library to encode the receipt. That saves a lot of headaches.

Restoring "remove ads" functionality when using consumable IAP

I'm researching how to properly implement the functionality to remove ads in my app when the user makes any IAP and have that functionality restorable.
The way i'm seeing the first part done is to simply put a value in the user defaults that the user has made a purchase and check it before displaying ad. No problem.
But i don't know how to do the restorable part because all my products are consumables. How can I restore this value when the user reinstalls the app? Because as i understand the only record of a consumable is on the device and cannot be restored by apple correct?
Any help would be greatly appreciated, thanks!
You cannot do this purely through store-kit APIs, as there is no restorable purchase record as you say. I can see a couple of options -
You could enable iCloud for your app and persist data to the user's iCloud account, however this won't work for users who don't have iCloud.
You could have the users register an account on your server and use that to store their purchase history (or provide a Facebook login etc).
If a user deletes and re-installs your app then they need to make another in-app purchase to remove the ads - Profit!

Non Renewable In-App Purchase with Restoration using iCloud

I am creating an app in which i have an in-app purchase functionality. I am using non-renewable type of subscription but i have to give the support for restoring the subscription in multiple devices.
After going through multiple documents, i found out using iCloud to be the better way to implement it and provide subscription content for user's multiple devices. Finally i decided the following design to be implemented:
User explores the app
Clicks on In-App purchase button option
Check for iCloud availability
iCloud Available :
Continue with the purchase in usual way
iCloud not available :
Show Alert view : "Sign in to iCloud required to access the subscribed content on your other device", with options "OK" and
"Continue anyway"
Click OK :
Remains on the same page
Click "Continue anyway" :
Continues with the purchase
If already purchased and iCloud available, update the iCloud receipt
On successful purchase, we get the transaction receipt. We will store this receipt in the iCloud (One time store in iCloud at the time
of purchase) using key value storage and also in the user defaults
Purchase successful.
User launches the app from another device
Check for any transaction receipt in the user defaults. If available, verify and proceed accordingly
If no receipt available in user defaults, Check for iCloud availability
iCloud Available :
Check if any transaction receipt is available
If available, verify the receipt. If the receipt is valid, provide subscribed content
If not available, no action required and proceed normally
iCloud not available :
Show alert view : "Please sign into your iCloud account to enjoy your subscription content, if any" with options "OK"
Inside the app, user switches on the option "subscribe to HD addition", will check for his subscription
ISSUE :
User purchases the app without logging into the iCloud
Launches the app from another device
He is not able to get the subscribed content
The only way to handle this scenario in a perfect way, considering all the test scenarios, is to store user's iCloud credentials into the user defaults, which i am not sure can be done/is recommended/is allowed. Any kind of suggestion is most welcome.
Also, I would need people's kind views over the above mentioned steps that whether it will be the right way to proceed with or not. Kindly suggest if i can improve it or can have a better way.
I made an App that uses iCloud NSUbiquitousKeyValueStore(which has similar selector like NSUserDefaults) to sync consumable type of IAP item.
You can check repos on Github like MKiCloudSync to see how it works.
When using NSUbiquitousKeyValueStore, there's no need for App to know the iDevices' iCloud status.
In my case, if someone holds 2 devices, device 1 has iCloud login but device 2 not, I'll ignore device 2.

Saving information about previous purchased items in iOS

I am working on an app that has a number of in app store purchase items that will enable certain functionality.
After each item is purchased, I would need to remember it (of course). I would also like to persist this information in iCloud in case the app is deleted or is installed on another device.
What is the best data structure to be used?
Can user defaults database be used for this?
What is important is that the user will not have access to change those values and enable by themselves the paid functionality.
Can user defaults database be used for this?
It can, but it's not the best idea to do so, since
What is important is that the user will not have access to change those values and enable by themselves the paid functionality.
and NSUserDefaults stores its contents as binary or plaintext property lists. Easily changeable on a jailbroken device. (Also changeable on a non-jailbroken one by modifying the iTunes backup files).
What you could do is either store them in the keychain, although the keychain is not really designed for this (and it can also be dumped on a jailbroken device using Ptoomey3's awesome Kaychain-Dumper tool), or better store it remotely on your server and let your server check what the user has purchased.
Of course, if it's not only the server that does the check, so for example you don't only send or don't send content based on purchases, but you also use this check for performing actions within your app, then it also can be hacked (google "MobileSubstrate cheat DoodleJump" for a nice example).
All in all: there's no perfectly secure system.
I use the KeychainItemWrapper class to store a flag in the keychain. The nice thing is, so far, is that the keychain survives an app deletion. IF the user then reinstalls the same app on the same device, the keychain data is still there.
There is no need to use iCloud. If the user installs your app on another device, you just need to provide a "Restore Purchases" button in your app. Then you call the Store Kit APIs to restore existing purchases. The "In-App Purchasing Programming Guide" covers how to do this.
This same functionality will allow a user to restore their purchases even if the flags in the keychain are lost.

How to store in-app purchases for offline availability on per-user basis

It seems that keychain on iOS stores data on a per-app basis rather than per-user.
So if I store information about in-app purchases in the keychain, these products will remain available on the device regardless of which Apple-id is currently logged in.
I could require network-access and perform a restore to know which products should be available, but it seems to be bad practise to do a non user-initiated retore. Also, the app should function properly offline.
My question is: How do I protect in-app purchases from being available to users other than the Apple-id that bought them?
You need to organize user authentication for this - make your users create accounts in your service and provide in your application ability to log in and out for them. After application launch it must check out which user in logged in and provide in-app purchases for that user.

Resources