iOS -- How to save in-app purchase data? - iphone

I'm planning on implementing some in-app purchase items and I want to save purchase information/data such that iTunes will backup said information when my customers sync. The Apple provided documentation states that this is possible, but doesn't really tell you how.
Where/how do I save purchase history (let's say, a NSString for each item) such that iTunes will back it up on the next sync?
Lastly, how would you suggest that I test this before making all of this go live?
Thanks.
P.S. Right now I'm using NSUserDefaults to store this info.

NSUserDefaults is fine for storing that kind of thing, but you should also use StoreKit's “check for purchased items” capability—a lot of apps that use in-app purchases have a button somewhere that checks the “purchased” state of the available products and re-enables them in the app, in case a user uninstalls and then reinstalls the app or installs it on a different device.
Testing in-app purchases can be done using the sandbox environment—iTunes Connect will let you set up a test iTunes Store account which has free access to all of your app's in-app purchases.

Actually NSUserDefaults is under
<Application_Home>/Library/Preferences
And the Library directory will be backed up by the iTunes.
Another way to save your in app purchase data (because it's very little) is to save it to keychain. Because keychain is safe and will be reserved when the app is deleted. So when user install the app again user can get their purchase instantly. Check this link:Lockbox: Easily Secure Your App’s Sensitive Data

As already mentioned you can use UserDefaults for this purpose, but as Apple states it can also be achieved using iCloud and NSUbiquitousKeyValueStore
https://developer.apple.com/documentation/storekit/in-app_purchase/persisting_a_purchase
Testing can be easily done nowadays right within Xcode using .storekit configuration file.
https://developer.apple.com/documentation/storekit/in-app_purchase/testing_in-app_purchases_in_xcode

While NSUserDefaults can be used to store purchase history, it's possible for a hacker to modify that and get access to paid features for free.
Keychain is a little better in that it's more persistent (will still be there after an app is removed and re-installed) but it's still possible for a really dedicated hack to add data to the keychain that makes your application think a purchase has been made.
You could also write out purchase info into some encrypted file you store within the app, that would be backed up with the app as well and might be more flexible.
The best approach is to store purchase data wherever is most convenient for your app, but then also check the receipt of the application that is stored in Bundle.main.appStoreReceiptURL to make sure what you have stored, Apple also considers to have been purchased.
That receipt is supposed to be sent through your own server to Apple, which returns receipt JOSN from the data stored at that appStoreReceiptURL.
For testing, although you can also use a sandbox iTunes account for testing on device, a newer method introduced with Xcode 12 is to use a StoreKit configuration where you can define all of your products without having to enter them in appStoreConnect first. When you run it will process purchase transactions locally, including within the simulator (not possible with the iTunes sandbox).
For more information on testing using the Xcode App Store Config files read this article:
https://www.namiml.com/blog/inapp-purchases-ios14-simulator

Related

In App Purchase: download extra data OR should information be contained in basic application

I am developing iPhone/iPad application with in-app-purchase. In-app-purchase requires extra data(~300KB .txt file).
Should data be downloaded after the purchase is done? I assume that it is necessary to set up my own server to retrieve the data(it can't be downloaded from some apple server for example)
OR should data be contained in basic application? Will apple approve this?
Either way is permissible as far as App Store approval is concerned. Use whichever works better for you.
(And yes, as of the current iOS release Apple will not host any extra data to be downloaded with an in-app purchase; you'll have to host it yourself.)

Copying data from a free iOS version to a full version of my app?

How could a full version of my iOS app access / copy the database / settings from the free version ?
I'm thinking of providing a free version of my app and I can't see how people then buying the full version could get access to the data from my free version ?
All apps are isolated on iOS. They are installed as different iOS system users. One user do not have permission to access another user's files. In the old times, one common approach to address this problem is to enable iTunes file sharing. And tell users to manually copy the files.
Your better bet is to use the freemium model to sell your app. Make the app free, and unlock extra features via in-app-purchase. This way, your files, documents, settings won't need transferring to the pro version. The app itself becomes pro after unlocking.
Here is the guide from Apple: https://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/StoreKitGuide/Introduction/Introduction.html (though not very intuitive).
The walkthrough here: http://troybrant.net/blog/2010/01/in-app-purchases-a-full-walkthrough/ is very helpful.
Last but not least, be aware that in-app-purchase is crackable. So please read: How to detect "IAP crackers"? , Verifying In App Purchase Receipt from Client , and https://stackoverflow.com/questions/4715414/apple-in-app-purchase-verify-receipt , verify in app purchase , In App Purchase Receipt verification within app .
Note that you are supposed to setup a server to validate iap receipts. Though it's doable from within the app, it's not safe. As far as I can remember, you can test in-app-purchase through StoreKit in iOS simulator v5.0, that should be Xcode 4.2. Before that, it can only be tested on a device.
#Dominik Hadl mentioned you can use a server to sync the file. The operation is usually complicated. If you prefer this idea, you can choose to use custom url scheme to launch one app from another to ease the operation. See steps below:
User press "Begin sync" in the free app to upload the file to your server
Server return the ID of the file to the free app
User press "Launch Pro App and Download my file", which leads to a custom url scheme to launch your Pro version (must be installed first), with the file ID
Pro version use the file ID to download that file directly
I think the only way how you can do this is syncing the data with some server, registering the device and the syncing the data back to the full version.
Because all iOS apps are sandboxed, they can't access any other application data (unless you have jailbroken iOS).
Since multiple apps can share the same iCloud container, I'd say that the best practice nowadays is to "simply" store the data in iCloud.
(I'm putting "simply" under quotes, because it is easy to put data in iCloud and take it out; but if you actually want to do syncing, you may need to do more than just "I'll load from iCloud and save to iCloud" in order to provide the best experience to the user.)

Is it safe to store the flag in NSUserDefaults once purchase is done via In App Purchase?

I have some features which would be unlocked only after the purchase through in app purchase.
Is it fine if I store the flag value in NSUserDefaults to check whether app has been purchased or not?
Is it safe to store the flag in NSUserDefaults once purchase is done via In App Purchase?
No, this is not safe.
The contents NSUserDefaults are stored in plain text. They can be accessed and modified with tools like iExplorer. This also works on devices that are not jailbroken.
This means that if you save the purchase information in the NSUserDefaults, users can unlock your content without doing an actual purchase.
To save the flags in a way that is not as easy to "crack", you could do one of the following:
Save an additional salted hash of your stored information. Use the hash to validate that the user has not modified the information. You can find an implementation of this concept here.
Save the flags in the keychain. Read more in Apple's Keychain Services Programming Guide. You can find several implementations of this concept on GitHub, e.g. Lockbox.
Update: As of iOS 8.3, the access to the app sandbox is somewhat restricted. While this adds some security, I would still not recommend using NSUserDefaults, as access to the sandbox is still possible for jailbroken devices, apps that have iTunes file sharing enabled, and of course devices running older versions of iOS.
Yes, it's the best way. So you can tract through flag which are stored in NSUserDefault.
But,
When you delete the app from device then it's value become FALSE.
So it will ask for purchase again. But, it will not charge user for purchase same thing again.
Cheers.
Yes that is the best way. At lease I stored in NSUSerDefault in my Non-Consumable In-app purchase type.. So it is working as charm for me until now.

iPhone : In-App purchase query

I want to add In-App purchase functionallity in my app.
My app contains many feature. In the free version, Some features of my app will be accessible and some features are disabled.
What i want to do is, i want to enable all the feature once the user pays for full version of my app.
How do I store flags in iOS keychain ?
How can I do this ?
Is there any examples or good links ?
There are many ways you could achieve this:
Using your own server and delivering the content once the app is purchased succesfully.
Using the iOS keychain to store some flags.
I will talk about the second point here. I will assume you can't get your own server.
The easiest way to do is to code in "disabled" features into your app, as you normally would. But store a flag a somewhere, say, a flag called "contentHasBeenPurchased". You could store this flag anywhere; in a plist, in NSUserDefaults, but these are insecure ways to store your flag because a jailbroken app could easily access your application's sandbox. These methods are secure with non-jailbroken users, for the most part... There is software that allows you to access the iOS filesystem and edit plists from there. So yeah, storing this specific flag in a plist or NSUserDefaults is certainly not a good idea.
So you are left in storing this flag "contentHasBeenPurchased" in the iOS keychain, because it is encrypted. If you don't know how to use the iOS keychain, it's a bit complex to learn, but it will certainly pay off in the near future. After you have your flag in the keychain, it's just matter of checking whether its value is true or false to enable the purchased content. When the user purchases the app, just set the flag to true, and you are ready to go.

iPhone - in-app purchase : recording the purchase

I've read here and elsewhere the following thing :
Finally, after providing the feature,
you should “remember” that the user
has purchased the app. Apple’s
recommended way is to use
NSUserDefaults, the same way you store
your settings.
But... If I'm not wrong, when you delete an app from your phone (but not from iTunes), and if you restore it later from iTunes, the prefs are deleted and restored to their default values. Is that right ?
So am I right saying that doing this way, if the user deletes the app from its phone and some weeks later reinstall it from its iTunes library, its in-app purchases will be lost ?
Yes, you are correct. When the user deletes the app the NSUserDefaults is erased too. However, the app store has a handy restore purchases feature, where you can request to be told the purchases that apple has recorded for the current user.
There doesn't seem to be a good method of detecting that purchases need to be restored (at least from what I've seen on here), most developers seem to simply offer a button that starts the restore process manually.
There is an alternative, which is to store the user purchases in the Keychain, which is (at least right now) not deleted when the app is uninstalled. I've confirmed this is the case on iOS 4.3 - though it may not stay that way forever.
Here's some sample code that demonstrates both restore purchases, and using the keychain to save purchases