views:

313

answers:

2

I'm builing an iPhone app that should handle subscriptions through In App Purchase. When I get the receipt back from Apple in my app I want to save the receipt on my own server and on my server I also want to verify the receipt with the Apple server. It is very important that this connection to my server is made as this saves information about the user that will be needed later.

In my SKPaymentTransactionObserver I'm now trying call my server on SKPaymentTransactionStatePurchased. The problem is that on SKPaymentTransactionStatePurchased there seems to be a standard alert saying "Thank You" and that the purchase is completed. As it take some time for the app to contact my server this standard alert is shown before the call to my server is completed and what happens if the user quits the app here, he thinks that the purchase is finished as it said so? When should I contact my server? And if I want to show an alert for the user when the call to my server is completed when should I do that?

This is the code I'm using:

//This is called on "SKPaymentTransactionStatePurchased"
- (void) completeTransaction: (SKPaymentTransaction *)transaction
{
    [self saveAndVerifyOnServer:transaction];
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
A: 

Hi.

You could store the purchase in the app immediately (just in NSUserDefaults) until you have successfully talked to your server.

When your server gets back to you, delete the key from NSUserDefaults.

If the app quits before the server gets back to you, the key will still be in NSUserDefaults when it starts next time and you can send the purchase then.

Sam

PS Remember to call [[NSUserDefaults standardUserDefaults] synchronize] to make sure your key gets written!

PPS You will need to protect against multiple purchases somehow. Probably with some sort of unique key generated by the app.

deanWombourne
Thanks for your help! I have been working with implementing this solution but what is [[NSUserDefaults standardUserDefaults] synchronize]? I haven't used that before, do I need to to write to defaults?
Martin
The synchronize method forces NSUserDefaults to save itself immediately. If you don't call this, the variables do still get saved but at some point in the future which is fine 99% of the time but you want to cover yourself against a user quickly quitting the apps so it's best to be sure!
deanWombourne
+1  A: 

This is what the documentation for SKPaymentQueue says about the finishTransaction method:

Your application should call finishTransaction: only after it has successfully processed the transaction and unlocked the functionality purchased by the user.

From this, I think you need to save and verify the transaction on your server and only when that's confirmed call the finishTransaction method. As dean notes, you'll need to cater for the situation where a user quits before you've managed to verify.

The good news is that the SKPaymentQueue persists across sessions, so it will remember that you've not finished buying something. This means that the next time you add a transaction observer you may get a call in your delegate immediately. You may need to code your server process so that it can restart a transaction.

Stephen Darlington
I tried removing the finishTransaction and it seems like the popup that verifies the successfull payment is shown anyway?
Martin
Well, the payment _has_ been successful at that point. The money has been taken from their iTunes account. `finishTransaction` says that _you've_ finished the transaction. I don't think you can change the order of events, you just have to adjust your UI to suit.
Stephen Darlington
Thanks! Many guides that I've seen says its a good way to add the Transaction Observer directly when the app starts. Is this heavy and can make my app slow? When do you think is the best way to add the observer?
Martin
If there's nothing in the queue I would expect that it's fairly lightweight, but you'd really need to test. What I would want to check is that adding this line does not prompt for a username/password. In my app I have this check in the "Upgrade" screen.
Stephen Darlington
So you don't add the Observer until the user opens the "purchase" screen?
Martin