views:

1037

answers:

2

For a basic app with nonconsumable in-app purchases, has anyone figured out best practices for using SKPaymentQueue's restoreCompletedTransactions?

Observations

I know it's recommended to always register a transaction observer to receive pending transactions that make their way back to the app, but this is a different question. It looks like restoreCompletedTransactions is something the app has to actively decide when to call to poll for all the purchases the customer has already made.

From what I can tell, the method is designed to retrieve purchases that may have been lost. For example a customer might install or move an app to a new device in such a way where the user defaults (where Apple recommends recording nonconsumable payments) are lost or reset.

Concerns

What's not clear to me is how to automatically detect this condition (i.e. how to decide when to poll for missing purchases) in a reliable way. I don't want to screw this up and risk denying a customer access to functionality they've already paid for.

At the same time, I don't want to call restoreCompletedTransactions every single time the app launches just to be safe and basically get back transactions I already know about 99.9% of the time. (Except for in-app purchasing, my app doesn't really require any network connectivity.)

Notes

Apple documentation clarifies that customers are not charged again for any nonconsumable purchases they have already made. If they try to re-purchase, a payment transaction is still supposedly sent to the app.

Worst-case, a customer could recover purchases this way but I'd still like to avoid walking them down a path that resembles re-purchasing something they've already paid for.

+2  A: 

After writing out the question and thinking about it, I came up with a couple solutions.

Automatic

One option is to record in user defaults whether restoreCompletedTransactions has been called (and successfully completed) yet in the app. If not, the app calls it once on start-up. Since this flag is stored in the same place as the nonconsumable payments, if user defaults get wiped later on then the restore method would get called again when the app starts.

This way, if an existing costumer is somehow doing a fresh install of the app they still get their purchases restored automatically. If they are a new customer that has never launched the app before, then the restore operation returns nothing.

In either case, restoreCompletedTransactions is only called once instead of at every launch.

Manual

Another option is to offer the customer a "Restore Purchases" button somewhere, hook it up to restoreCompletedTransactions and let them decide if and when it might be needed.

That option might be the most simple and reliable, but I'd rather handle it for them automatically if possible.

otto
The check for flag on startup and automatically restore is pretty witty. I ended up implmenting a button as did Ramp Champ. But then both applications are downloading large files when purchases are made.
Carl Coryell-Martin
Yeah. I'm leaning back towards having a restore button as well.For an automatic restore, I forgot to consider something obvious - that the user can prompted for their account password. That's the last thing I'd want to throw in the user's face the very first time the run the app.
otto
A: 

I have encountered a problem:when the user pressed retore transactions ,It prompts a dialog to allow the user input username and password. If the input information is correct,the observer will receive message:SKPaymentTransactionStateRestored

however,when the user press cancel,or input wrong password, there are no message to receive when waiting for several minutes.

so why?

beof
In addition to paymentQueue:updatedTransactions:, SKPaymentTransactionObserver can also receive paymentQueue:restoreCompletedTransactionsFailedWithError:. A potential typographical error can prevent this message from being received. See http://stackoverflow.com/questions/1781875/iphone-store-kit-how-to-catch-cancel-event/1791611#1791611
otto