We have an app where we offer consumable in-app purchase which is in the form of virtual currency. (e.g. 100 coins) The in-app currency is used for some of the advanced features in the app and the user can replenish them as needed.
We are looking for a way to reliably track the virtual currency (surviving reinstalls) and are leaning towards a server based solution where we can track these in a database. The other factor in play here is that we want to reduce the friction in the app so there is no login, registration or fb connect.
We ran into one issue with this approach:
- We need to find a unique identifier associated with the "device" that will survive reinstalls.
Also, we realize that this approach wouldn't support synching the currency balances across multiple devices of a single user. Any way to tie this data to user's appstore account?
Generate a fingerprint when a user logs in to a particular device for the first time.
Save this fingerprint in the keychain with the with the value "kSecAttrAccessibleWhenUnlockedThisDeviceOnly" for the "kSecAttrAccessible" key.
Things to consider,
Item will keychain will persist even user deletes the app
Keychain Items are backed up and restorable even to other device by since you using the above key the fingerprint would not be restored to the other devices.
If the devices ownership is changed then replace it with a new one for the new user or associate with the new user.
Related
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.
I am having trouble understanding the theory of in-app purchases and have got to the point where I read so much I have confused myself.
I have an application where I don't require the user to register however I do store data on a server and track this using the UUID. My application scrapes a hi-score system for an online game and the user has to input which players on the online game they wish to keep track of. This information is then sent to my server which scrapes the data every 24 hours by default. Here is an example of the database on my server.
Devices Table:
uuid,
scrape_interval
Players being tracked table:
uuid,
player_name
Tracking information table:
player_name,
track_data,
tracked_on
I want to include an in-app purchase which once purchased will mean that data is scraped every 12 hours instead of every 24 hours, the way I plan to do this is by updating the devices table and set the scrape_interval to 12 hours where uuid = uuid that made the purchase.
However how will this work for users that have multiple IOS devices, how do I ensure the list of players they are tracking is kept sync across devices? I have read about using an iCloud ID which is apparently a unique identifier but does this mean I will have to do a check on the launch of my app to ensure the user is logged into an iCloud account and force them to login if they aren't? This doesn't seem very user-friendly but nor does implementing a custom registration and login system.
Am I over thinking? Is there a simple solution?
In app purchases can be restored across multiple devices associated with a single itunes account. So a single purchase may actually exist on 5 devices, and you can not tell which is which.
The IAP will provide no device specific id. Your only option is to generate a unique installation id and sync all installation ids that have the paid status.
I'm developing an iOS application in which users can buy an extra feature through an in app purchase. I have gotten the in app purchasing and restoring the purchases working correctly, where I save a boolean to the NSUserDefaults saying whether they have successfully bought and or restored the purchase.
However there is a bug where if User 1 buys the in app purchase on their phone, then logs into the App Store on User 2's phone and restores purchases. Then logs out again and allows User 2 to log back in, it means User 2 still has that in app purchase unlocked for free as the boolean in NSUserDefaults is still set to true.
I'm trying to find a way to query the user's App Store email or another way to check if the user's App Store email is the same as the one they bought the purchase under. But this needs to be done locally as the user could use this feature when they don't have any internet connection.
Does anyone have any suggestions of how I can do this or any better practices?
Thanks
This is, unfortunately by design, so as the old adage goes "it's not a bug, it's a feature".
It's designed like this so a user with multiple devices (e.g. iPhone and iPad), can make a purchase on the first device and benefit by restoring their purchases on their other device(s).
Of course this opens the door for people to share purchases across other peoples devices just as you describe.
The good news is there is a property on SKPayment called applicationUsername, its purpose as the docs state...
Use this property to help the store detect irregular activity. For example, in a game, it would be unusual for dozens of different iTunes Store accounts to make purchases on behalf of the same in-game character.
If you don't have anything unique to identify the user, e.g. an email, username, id, etc then your problem can't be solved I'm sorry, but if you do, keep reading, this is where it gets interesting.
When the user restores their purchase you should use the restoreCompletedTransactionsWithApplicationUsername method to make the call instead of restoreCompletedTransactions.
The docs are unclear what happens next, but my understanding is transaction state will be SKPaymentTransactionStateFailed if the username sent in the purchase call is not the same as the username sent in the restore call.
But if i'm wrong then you should be able to find the applicationUsername on the payment property of the transaction and compare it yourself before setting your property on NSUserDefaults. Sorry I haven't tried this myself, I only know the theory.
When setting the username, don't set it as plain text, the docs on applicationUsername suggest that...
The recommended implementation is to use a one-way hash of the user's account name to calculate the value for this property.
And further in Detecting Irregular Activity they explain...
Don't use the Apple ID for your developer account, the user's Apple ID, or the user's unhashed account name on your server.
Also, ideally you will be using a constant identifier, i.e. something that can't be changed for the user. If you use a hash of their email address for instance, if they change it and you didn't keep that hash as a constant restoring will fail as an unintended side effect.
Hope this helps.
You can control it via your servers by checking originalTransactionIdentifier of the receipts. As this remains same for all the purchased from one itunes account. You can associate this originalTransactionIdentifier with the username. Next time if you receive some already stored originalTransactionIdentifier against a different username, you can take the actions according to your suitability.
We are looking at using consumable (non-renewable) IAP for subscriptions for our app after being rejected for auto-renewable subscriptions. I've read through many posts pertaining to this, but haven't seen any discussion on limiting the number of iOS devices a user can use the consumable on or "restore" to.
The main concept seems to be, let user create an account (optionally) on your server, and allow them to enter account info to restore/share across multiple devices.
My primary question is, how can we limit the number of devices a user is allowed to use the subscription on, and the number of devices a user is allowed to "restore" to, and still meet Apple's requirements for restoring purchases?
If we setup a server, and allow the user to optionally create an account to store the receipt information, how can we keep that user from sharing their login information with anyone if we have no way to uniquely track the number of unique devices that are using the account? (perhaps I'm wrong here, but with the deprecation of UUID and the possibility of identifierForAdvertising changing if the app is deleted and re-installed, there is no way to cache a unique device to determine how many devices have used the subscription, correct?)
I've contemplated storing an auth token in the user's iCloud, but from my understanding, there is no upper limit on how many devices can share an iCloud account.
I'm sure I'm not the first to run into this problem, how is everyone solving this?
Thanks -
Matt
Consumable items are intended to be device-sepcific. And once consumed, the user must purchase it again, even if it were purchased previously on the given device.
Apple doesn't officially want you to limit the number of devices for subscriptions or non-consumables - they want your IAP subscriptions and non-consumables to be available on ALL of a user's devices. See: https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/StoreKitGuide/APIOverview/OverviewoftheStoreKitAPI.html
Why not use iCloud to transfer an IAP non-renewable-subscription between devices? That limits it to just the user's device set. Why do you care if they have 2 devices or 10? I bet that users don't typically share their apple-id's outside of their immediate family.
My client has an app in the App Store that uses the auto-renew subscription type. Upon resubmitting the app it was rejected because they claimed they don't have periodic content (even though they do... but this problem seems to be ubiquitous currently). I was wondering what the best approach is to deal with non-renewing subscriptions. Specifically issues dealing with:
Losing your device and restoring your subscription
Restoring your subscription to multiple devices (as mandated by Apple)
Preventing users from abusing the system.
What I came up with so far is the following:
When a user purchases a 1 month subscription this information is stored locally (say in NSUserDefaults). Also, a unique ID is generated and sent to my clients server. When the subscription ends users are asked whether they want to be directed to the purchase screen. If users wishes to save the subscription in case they need to restore they device, or in case they lose their device, they can opt to have the unique identifier sent to their email address (which they are prompted to enter, indicating that this information will not be used). The app has an place to enter this ID. It will retrieve the subscription information from the server and again store this in the NSUserDefaults. Each time a restore is done, a counter is increased. When it has reached say 5, the user can no longer restore. The same principle described above works in the case of sharing subscriptions over multiple devices. Does this seem like a reasonable solution (and one that Apple will accept)?
Thanks for your time!
Why don't you want to use Apple's restoreCompletedTransactions? It just provides you with information about ALL the previous purchases, on any device, at any time.
http://developer.apple.com/library/mac/#documentation/StoreKit/Reference/SKPaymentQueue_Class/Reference/Reference.html#//apple_ref/occ/instm/SKPaymentQueue/restoreCompletedTransactions