ios auto renewal subscription and user in our service - ios

In our service, each user has a username (email), password and a unique identifier. How can I link any purchases through Apples' auto renewal subscription to that user?
Is there any field that renders an Apple user as unique?
I don't want to link it to the device, because the user can run the app from many devices, so I want a unique identifier for the user.

Apple does not provide you a unique identifier for an Apple user or Apple ID (probably to help protect the users privacy). What I was doing was using their first Auto-Renewing receipt as their unique identifier. So you should be able to use the original_transaction_id in your receipt verifications. When you verify a receipt with Apple's servers, the response should include the transaction id of the original auto-renewing subscription that that user purchased from you regardless of which device they were on. And I've found that even if a subscription lapses and then starts again, there will always be the one original auto-renewing transaction that is referenced.
It's a bit of a trick but it seems to work.
Alternatively, you could also use an iCloud key-value store to store a unique ID. That ID will be the same on all a user's devices, but they have to have iCloud turned on on all their devices. And technically they could be using different accounts for iCloud than they're using to make purchases so this isn't perfect.

Related

iOS In App Purchase Receipt Duplicate Management

When building In App Purchases into an iOS app, Apple gives you access to a receipt that you can send to your server to view all In App Purchase transactions for that given iTunes user related to your application.
If in my application I require users to login or create an account through my system before making a purchase, how can I guarantee that iTunes receipt will not be duplicated?
For example, if a user makes a purchase, the application sends the user ID, and iTunes receipt to my server. The server then stores that receipt along with the user ID in a database. The next time the server wants to check the users purchases we can retrieve all the receipts for that given user ID out of the database and run checks on it.
But if the user logs out and logs in as a different user and makes another purchase the receipt will be sent to the server again, with a different user ID. Effectively, allowing 1 purchase to be used on unlimited user accounts.
Due to the fact that the receipts change over time (auto renewing subscriptions, etc), I don't think it's safe to rely on the receipt being the same every time it's sent to my server and using the receipt data as a unique identifier.
I also considered storing the original_transaction_id for one of the transactions, but I don't think that would work since an application might have multiple non-consumable items, or multiple subscriptions, therefor there might be multiple completely valid original_transaction_id's in one receipt. So it doesn't really associate that receipt, but just the transaction.
Ideally, I'd like a system where when a user logs out, and logs in (as a different user or same), the application will send the receipt to the server, and dissociate any of the same receipts for all existing users, and link this new receipt to the user that logged in. Problem is, it doesn't look like there is any type of unique identifier for a given receipt that I can use to check for duplicate receipts in my system.
What is the best way to detect duplicate receipts sent to my server (so I can dissociate the old receipts accordingly)?
PS. I think this system is most important for subscriptions, and non-consumable items. For consumable items it will always have to be linked to 1 specific user, and I can just store the transaction_id and original_transaction_id for that consumable item to ensure it doesn't get duplicated.

How do apps tie accounts with in-app purchase subscription?

I'm working on an iOS app where a user must sign up/sign in to an account for my app. To be able to use my services I want users to pay via in-app purchases (auto-renewing in my case). This would then tie their IAP to their account (they created with us) to be able to use on any other iOS device.
Case 1:
For example if a subscription was bought on phone A for an account, when signing on to phone B (using the same account) shouldn't make the user pay again.
Case 2:
Or if a subscription was bought for account A on a phone, when signing up for account B on the same phone should make the user pay for account B.
Basically I want an in-app purchase to tie to my account (rather than a apple device/Apple account which is how it works to my understanding.)
I understand that their are receipts which is probably part of the answer to my question. Or if this a limitation to in app purchases what other ways can this be done (other than using Apple's IAP)
The answer to the title of the question:
When a purchase is made there is an update received in the app, the next time it is launched which contains a transaction_id (original_transaction_id for renewals), you should associate this transaction id with your app user id.
Case 1: Apple provides an option to "Restore Purchases" in your app. Since, the same account is used, your app servers would already know that a user has already paid and the app shouldn't prompt the user to pay again. However, in order to receive the upcoming renewal updates on phone B, you must "Restore Purchases" which would let Apple link the previous purchase on this device as well. Once the restore is done, the users purchase receipt will be available on the device and all subsequent actions should be taken based on the content validation of the receipt.
Few points here:
Apple will reject your app, if it doesn't provide this option to the user.
Even if your app is buggy, and you failed to restore purchases, user wouldn't be charged again. The purchase would fail saying you already have purchased this.
The above case is completely based on the assumption that the user is using the same Apple Id on both the devices(same application user id doesn't matter).
Case 2: I am not sure if that is anyhow possible. Since it's the same device, the user uses the same AppleId(unless he signs out and changes apple id in App Store) and Apple will restrict the repurchase. At best you may restrict the account B with the subscription content but if your application allows multiple accounts on the same device use case(e.g Instagram), I am not sure if there's a provision for the same.
I tested the same scenario for a music service app I use. Have an active subscription, logged out and signed up with other email (app), but the purchase was denied alerting I have already purchased. However, it was allowing me upgrade and downgrade options. I didn't opt for testing them so not to mess up my account.
P.S: There are a lot of other caveats/gotchas to take care of. Some of them:
In case 2, apple restricts the repurchase but it doesn't restrict if the user chooses an option other than the current active subscription, which will upgrade/ downgrade the subscription. Based on how you have implemented things, it might even change the subscription for user A immediately or next time the user logs back in or on next renewal thereafter.
In both the cases discussed here, user uses the same Apple Id, but consider the cases - same Apple Id different app id AND different Apple Id and same app Id. (See this)
For case 2, you should always refresh receipts or restore purchases(if there's no receipt available) for a fresh user login. The receipt has a original transaction id which you should have linked the first time the purchase was made with user A. Based on the receipt, you can either choose to let user B access the content or restrict. However, you cannot let the user pay for the new account(I suppose so).
Helpful Links:
Restoring Purchases
Receipt Validation

Apple inapp Non-Renewing subscription purchase, force-require login?

here's my straightforward question:
is it allowed for my iOS application to force users to log into my custom account management system, so I can link them to my backend when they want to purchase a non-renewing subscription?
Here's the backstory:
I have a non-renewing subscription. For a good amount of users I can see that the Apple receipt does not contain information about this subscription; the in_app array is empty. This is correct according to the API:
https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/Products.html
The in-app purchase receipt for a consumable product or non-renewing subscription is added to the receipt when the purchase is made. It is kept in the receipt until your app finishes that transaction. After that point, it is removed from the receipt the next time the receipt is updated—for example, when the user makes another purchase or if your app explicitly refreshes the receipt
For some users, I can still see the purchase in the receipt, but let's consider that a bug from Apple and follow their API documentation to the letter.
(More on why this is a bug here https://forums.developer.apple.com/thread/22345)
In order to restore the user's purchase, I'd need something to identify him with. I could create a unique token, store that on the iCloud keychain and use that across the devices to detect the purchase belongs to that Apple account, but since my application supports account creation, I'd rather just use that mechanism. Else I'm using two different methods of purchase detection side by side: iCloud keychain token or a user account.
Thing is, I'm not sure I am allowed to force users to make an account before making a purchase. Is this something Apple would reject the app submission for with a message like "Your users must be able to buy stuff without going through your lengthy account registration process" ?
From Apple :
Non-renewable subscriptions. Subscriptions that don’t involve
delivering episodic content. Examples include access to a database of
historic photos or a collection of flight maps. It’s your app’s
responsibility to make the subscription available on all of the user’s
devices and to let users restore the purchase. This product type is
often used when your users already have an account on your server that
you can use to identify them when restoring content. Expiration and
the duration of the subscription are also left to your app (or your
server) to implement and enforce.
https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/Products.html
So its your app's responsibility to check that user has valid subscription or its over and let them purchase it again !
For this you will ask user to first make account or login into app so by this way you can track their subscriptions.

Disable restore IAP when same Apple account but different user account in application

In my app I have items to show just for users that are pays for subscription. User can log to app by e-mail and password and can logout and on same device can log different user.
My problem is that Apple Id in phone is still same. So when different user logged in he could restore purchase even that he didn't pay anything.
So my question is how can I fix it? How can I connect Apple account to my custom account? Or at least somehow when trying to restore IAP check that this Apple account already have this subscription but different user was logged in. How other apps do this? Thanks
Edit:
I want to use Auto-renewing subscription in my app and I just don't know how to connect it to my custom account system.
When a user makes an IAP, you will not know the Apple Id used to make the purchase. What you will know, however, is the transaction id for the purchase. What you will want to do store the transaction id of the original purchase with your custom account.
When a user restores, you will determine if the SKPaymentTransaction's originalTransaction's transactionIdentifier matches the custom account. If not, then you can assume this is a different user. You can read more about that here:
https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/Restoring.html
Note that the receipt contains a field called the original transaction id. This is what you would use for subscriptions to track the original transaction id. This is because each time you auto renew, a new transaction id will be generated for the auto renew. The receipt will actually contain all the purchases.
On your server, you would want to save the original transaction id and potentially the receipt. Essentially the more metadata your store around this, the better off you will be if you have to do any form of double checking transactions.

switching from auto-renewable to renewable subscription

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

Resources