3
votes

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

2
This might rather qualify as an unforseen workaround regarding IAP rather than a bug, actually. Yet, catching this offline w/o access to apple's servers seems impossible, which is bad, imho.Tobi Nary
You're right I just didn't know how to phrase it. It's annoying but I suppose it's an edge case that I assume other apps struggle with as well.BenSDConway
Right. Hence my favorite and upvote. Consider putting a bounty, as it didn't get much attention yet.Tobi Nary
Even if you could check the email address signed into the store, that would be a bad idea because you can change the email address of an Apple ID.Douglas Hill
OP, I did set a bounty. Feel free to self-answer a detailed 'cannot be done' in case the bounty runs out, you at least get something out of it :)Tobi Nary

2 Answers

1
votes

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.

0
votes

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.