I want to restore consumable In App Purchases for a game. This game has only consumable in app purchases such as:
$0.99 for 1000 coins
$1.99 for 3000 coins
Using NSUserDefaults to persist the coins is not good because the user could delete the app and when they reinstall, they lose their coins. Also Apple has a restoreCompletedTransactions method but this isn’t for consumables so the developer has to keep track of this.
Please don't mention to use GameKit (Game Center) or a Web Server. Are there any other solutions? I've read that iCloud and Keychain are two other possible solutions (not sure if these are good for this).
PS: There are many answers on SO that are a few years old and that won't work for my case, so I am asking here again.
Keychain and iCloud is what you are looking at. Keychain data will also not be deleted when you uninstall the app.
There is a good helper on GitHub for keychain, which makes using it a breeze.
https://github.com/jrendel/SwiftKeychainWrapper
General read about data storing
How secure is NSUserDefaults on iOS 8,9?
To store your data in iCloud you should use key value storage for small data.
I use a singleton class to handle all this. For a simple example check out this answer I posted
SpriteKit: Why does it wait one round for the score to update? (Swift)
which is based in this great article
https://www.raywenderlich.com/63235/how-to-save-your-game-data-tutorial-part-1-of-2
Hope this helps
Related
I wondering what a best way to check in-app-purchase product status on app launching. Do I need to save purchase status on device or ask for status app store on every app launching?
Since iOS 7 is recommended to use the App Store receipt to save the status of IAP.
You can find out more in the docs. But in most cases is NSUserDefaults enough. E.g. I use IAPManager to handle all for me which persists all on the drive.
You should save in-app-purchase status on your device, using NSUserDefaultsfor example.
Imagine someone bought some in-app purchases from your app, and want to use it somewhere where the network is slow or doesn't work at all : if you doesn't store the information locally, then the user will be unable to use the unlocked features of your app.
This Ray Wenderlich tutorial concerning in-app purchases
provides an useful class, IAPHelper, which helps you manage your products easily, you should check it.
#1
I'm developing iOS App with a non-renewing subscription in it.
I want to make the subscription available on all of the user’s devices and to let users restore the purchase.
As said in Apple's docs:
For non-renewing subscriptions, use iCloud or your own server to keep
a persistent record.
I do not what to use my own server because my App is available only for iOS for now. So iCloud seems to be easer solution.
After watching and reading A LOT of WWDC videos and docs about iCloud seems like the best solution for me is CloudKit because Key-value storage is limited to 1MB and I have a big chances to get total data size bigger than this per one user (after a year of different purchases for ex.).
Question is: am I right so far?
#2
I'm using RMStore Library for purchases. As is it said in docs RMStore doesn't have reference implementation of Transaction persistence to iCloud and I couldn't find any examples in the Internet so I'll have to do it by my own from scratch.
The first problem staring me in the face is: what if there will be some problem syncing the receipt to iCloud after user has purchased the subscription? For example: user bought the subscription, got some error syncing it to iCloud, closed the App and that's it. Is this a real scenario? For non-renewing subscriptions receipt is not stored anywhere by Apple so I am fully responsible for delivering and saving it for my user. Should I immediately save the receipt in NSUserDefaults or in Keychain after transaction is finished to be able to compare synced data to local one next time user launches the App? Or maybe I should not 'Finish the transaction' until receipt is synced? I could not find any guides from Apple for this...
#3
The next obvious question is: Can user clear my App's iCloud private storage? Can user somehow delete stored in the iCloud receipt thereby deleting all information about his purchases? If yes - how should I handle it? If this scenario is real I have no way to recover his purchase and open App's functionality for him until he buys subscription again.
Thank you in advance.
CloudKit is not limited to 1MB. A record is limited. But if you have more than 1MB of data in a record, you should consider a refactor. If it's just some sort of data blob, then you should save it in a CKAsset. For that the limitations is much higher.
Syncing will be a problem no matter what technique you use. One way to improve on that is by registering a begin purchase flag, then do the purchase and after that set the purchased flag. Then if a record stays in the 'begin purchase' state you know something went wrong and you can check with the App Store if the purchase was successful.
you should add a restore purchases function to your app
I am currently making an app and there is an important piece of information I need to store. The user can make a one time in-app purchase.
My question is, what is the apple recommended or approved method for storing this?
No. 1 is most important to me. For example imagine the user can purchase 10 lives. After his purchase he will use some of them so imagine he now has a balance of 5. Where should this number be stored.
The issues or thoughts or random ideas I have as a result of reading things are;
if its saved in a simple file then a jailbreaker can just go in an
edit the file.
if its saved in an encrypted file I think I have extra issues with my
app/Apple/certain countries because I am using encryption.
what happens when the user accidentally removes the app. He cannot
restore his purchases as its a one time purchase
should I be and how should this important piece of information be
backed up on a sync
how do I ensure this information is saved as part of a backup.
I am not sure there is one answer to this problem. In my case I save the information in the keychain. Other iOS SDKs such as Amazon's or Facebook's do the same thing as far as I can see.
I am building a game that will be free to play, and will include 100 free consumable 'hints'. I intend to offer more hints for purchase through in-app purchase. My current method is to store a file locally with the number of hints the user still has left. When the game is first downloaded the local file doesn't exist, so a new file is created with 100 hints. When an in-app purchase happens, it simply adds to the number of hints. (In the game, each hint simply removes a choice from a multiple choice question - the file simply stores a counter.)
My problem: A user could simply delete the app when they have 0 hints remaining (which will delete my local file that has a count of 0), re-download the app from the app store and they will then start again with 100 hints.
My question: How do I prevent this? Is there a different method I should use for storing hints?
use the Keychain to store your data, because the Keychain items are not deleted even if the app is Uninstalled or removed. This Api will help a lot link, have a look
or
You can refer to Apple's documentation on Keychain data
If you are going to offer some part of your hints as an in-app product, I suggest you to keep track of all your hints (both purchased and free) on a server. This way you can keep track of each user and even if they delete and re-download your app, you will still be able to keep track of your hints.
Edit: If you are implementing IAP you might find it healthy to keep track of your purchased goods anyway (ie. keeping track of your purchase statistics, watching out for fake in-app purchases, etc.)
usualy you use a server for such things, so not the device but the account is the interesting. Also a good possibility to save your progress and share to other devices ;)
I am investigating the use of in-app purchase for what essentially would be a "pro" version of my app.
The app itself would be free but once in the user has the option to purchase the pro content (only 1 thing). The "pro" content would already be on the app and there is no need to download it, it would simply "unlock" it.
Is this allowed from the Apple Guidelines?
As only 1 non-consumable would be purchased I think the use of a back-end server isn't required.
Again is that allowed from the guidelines?
And is it safe and simple to just store the result in NSUserDefaults and if installed on another device pull it from SKPayment restore purchased and such?
I've looked at several other questions.
In-App Purchasing?
Retrieve purchased information in In-App purchase
How do I add consumable In App Purchases using NSUserDefaults and not my own server?
And those seem to suggest that my approach is valid, but as I know those things have changed recently I want to make sure I'm taking the right approach.
Thanks!
No problem having the content built in.
Best practice is to perform receipt verification on a server with an authentication protocol between the app and server (this is also true for several other mobile app stores). If you perform the verification on the device, people can use existing tools to get around your IAP checking and steal content. Take a look at https://developer.apple.com/library/ios/#releasenotes/StoreKit/IAP_ReceiptValidation/ for some information.
So while a server is not required, it is recommended. Only you can say if protecting your content is worth the hassle of maintaining a server.
I agree with J. Freeman that straight storage in NSUserDefaults seems weak. I store things in a local file but the format is tied to the device and requires a server computed key to create it. Finally, yes you should use SKPaymentQueue restoreCompletedTransactions to get things purchased on another device. Realize that the restored transactions should also have their receipts verified on your server.
Yes that is fine. You do not need a backend to do in-app purchases, and it is ok to ship with your content built in.
The one thing I would say be careful with though is storing the unlock information in NSUserDefaults as someone will easily be able to forge purchases that way. You should store the unlock information in the keychain.