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
Related
I have to restrict a Free app from being downloaded or installed for a 2nd time on an iOS device, as I would like to user to purchase the paid version of the same. A first time user of the free App can download the Free App and install it on their iOS device, but after using the Free App for certain number of times, the Free App will work with limited functionality as I would like to promote my paid version, so I prompt the user to buy my Paid version of the App. At this time the user can delete my Free App and Re-Install the same from either the iTunes store or the iTunes on their computer or iCloud backup.
Question is how can I restrict the user from re-installing the same Free App on their iOS device a 2nd time ?
Is there any way to tell the iOS on the user's device to stop the 2nd time install of the same Free app ?
Or is there any other way to achieve the same results ?
Thank you.
You're unlikely to reliably get past Apple's review process with these restrictions.
Free/lite apps are supposed to be fully usable apps in their own right. So, using a todo app as an example:
You could limit it to ten TODO items
But you'd get into trouble if it stopped working after ten days
Clearly you can also limit in terms of what functionality you offer. My apps, for example, only allow editing in the paid version; the free one is read-only.
I'm not sure that you can reliably do what you want. (What about if I have to wipe my phone and restore from a backup? Does that count as reinstallation?) But even if you could, it wouldn't necessarily be a good idea.
i think the recommended way is to use in-app purchase. You can enable a full Version to the user when he buys it. So there is no reinstall needed.
I'm not sure why you have the requirements you do, but this does not fit the model of the App Store. You are likely to have your application rejected, even if you were to find a way to do this.
If you (or your stakeholder) are insistent in this approach, maybe the App Store is not for you.
I am trying to submit my first iPhone app that has in-app purchasing features. Needless to say, I have been banging my head against the wall for a while. I have read through several tutorials, such as: http://troybrant.net/blog/2010/01/in-app-purchases-a-full-walkthrough/ and http://blog.mugunthkumar.com/coding/iphone-tutorial-%E2%80%93-in-app-purchases/ but it seems these are outdated? For instance, I can't find where the developer is to reject the submission on iTunes connect.
Additionally, I am submitting the app the in-app purchase features included in the bundle(I don't have them stored on the server- I just want to unlock the code when the user purchases the feature). What is the best way to do this?
Thanks!
Some of the information in the linked tutorials is in fact outdated: I could create in app items in iTunes connect without having to submit (and reject) a binary first. Just be sure NOT to submit your items for review while you are testing. Also changes to the items (e.g. price tier) have been processed almost immediately and I did not had to wait 24 hours.
To unlock your feature, you may use storing and retrieving the purchased status in NSUserDefaults . But this could easily be tempered with by users with jailbreak or acces to the apps folder. Have a look at http://maniacdev.com/2011/08/open-source-ios-keychain-wrapper-for-easily-securing-user-data-for-your-app/ . This offers a simple way to store data in the keychain. Still this will not prevent someone to 'hack' your app and enable the purchased feature without actual purchase, but it's not that easy...
In-App Purchase development is definitely a pain point in iOS development - their sandboxing model for this is ridiculous.
Needless to say - the articles you're reading are still up to date. The developer reject is definitely the way to go (I think can do from within the binary details). One thing to remember is that you need to have accepted the appropriate contracts and tax schedules also - if you haven't then the store "just doesn't work".
One thing that caught me: when you submit your final version of the app - make sure you tick the in-app purchases to be included; else the in-app purchases won't be reviewed (and accepted)!
Update: Although it's pretty long... you may want to flick through this: https://itunesconnect.apple.com/docs/iTunesConnect_DeveloperGuide.pdf
Explains how to developer reject etc.
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.
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
My in app purchase project working perfectly now, but I need to test purchasing and when once purchase is successfully done it cannot be undone? How can I test in app purchasing and upgrading my app to full version when it can be done just one time?
Delete the app from your device
Run "Clean" from the Product menu in XCode
On your device, go to "Settings", "Store", "Apple ID", and Sign Out
Start your app again, since you're not signed in to any account, the previous in-app purchase will not be recognized and you'll be able to buy it/download it again with the same test user account
None of the answers is really correct. Even if the you remove the cached purchase from your testing device, the product is marked as bought in Apple's server, associated to your test Apple ID. So the testing will not exactly reproduce the expected behavior. This is very important for testing the restore products function use cases, for example.
As far as I know, the real answer to this question is: You can't without creating a new test account, but that's not a really big deal, you can even use an invented email address (no need to validate it), and you can delete the account after using it.
If you delete your app and reinstall it, you can repurchase products. It follows the same code flow and nearly exactly the same user experience (there is a dialog letting you know that you can repurchase for free the second time). Also you can create more test users in iTunes Connect to be sure that you are doing completely clean testing.
I've spent several weeks deleting and reinstalling my app many times per day to ensure that my storekit implementation works just like I want it too.
All you have to do is delete your app from the device. This will wipe out any NSUserDefaults where you may have stored in-app purchase details.
Once you run your app again, make the purchase one more time, and Store Kit will tell you this:
"You've already purchased this. Tap OK to download it again for free"
Once you tap OK, you go through the same sequence of events you did when you made your first in-app purchase, so you can test again and again.
Use unit tests on your app, with false data, until you're satisfied.
(create test code - for each module you use)
I think I'll need more description of your process to have a better answer.