Restoring purchased products on macOS

Hi there!


I'm currently trying to implement IAP in my macOS app and struggling with the feature to restore purchased (non-consumable) products for various reasons:


  • When I request a receipt refresh submitting a SKReceiptRefreshRequest according to Apple's doc (in the sandbox, outside of Xcode), the delegate method
    - (void)request:(SKRequest *)request didFailWithError:(NSError *)error is alway called with an error = nil
  • I realized that SKReceiptRefreshRequest is only available since macOS 10.9, while the other StoreKit classes / protocols exist since 10.7; How to handle refreshes with a deployment target < 10.9?
  • Most important: What exactly is the purpase implementing this function? I think the user can only "loose" his purchases when deleting the receipt from the app bundle (or the app bundle itself). Then he can re-download or restore the app and a receipt is requested during the first launch. When does a user need to restore a purchase which is a non-consumable product to unlock some app funcationality? Is this function mandatory for the App Store Review?

Any help or hint is appreciated, Mattes

Accepted Reply

Okay, now I figured it out:

  • A user might restore the app from a backup performed before the IAP was done. Now its receipt is valid and passing the check when launching the app, but it doesn't hold the purchase. So a "Restore" functionality is needed. Deleting and reloading the app would avoid this situation, but you never know what users do...
  • Calling [[SKPaymentQueue defaultQueue] restoreCompletedTransactions]; did the trick: The transactions observer's method is called, and I finish the transaction and simply reevaluate the receipt.

To me it looks like SKReceiptRefreshRequest is broken, maybe filing a radar these days...


Mattes

Replies

The user needs to be able to restore a purchase when they load the app into a new device. If you can obtain the purchase information from the receipt then you don't need to support restoreCompletedTransactions.

Sorry, I still don't get it: On a new device the receipt validation will fail and via exit code 173 the App Store login will prompt for credentials. Afterwards the app will receive a new receipt including the IAP... Anyway, thanks for pointing to transaction restoration: If I understand it correctly it will also provide a new receipt, so I might use this approach (although I don't need to restore detailed transactions)... Thanks, Mattes

Okay, now I figured it out:

  • A user might restore the app from a backup performed before the IAP was done. Now its receipt is valid and passing the check when launching the app, but it doesn't hold the purchase. So a "Restore" functionality is needed. Deleting and reloading the app would avoid this situation, but you never know what users do...
  • Calling [[SKPaymentQueue defaultQueue] restoreCompletedTransactions]; did the trick: The transactions observer's method is called, and I finish the transaction and simply reevaluate the receipt.

To me it looks like SKReceiptRefreshRequest is broken, maybe filing a radar these days...


Mattes

Having same issues with SKReceiptRefreshRequest. Always error = nil.

You mentioned that [[SKPaymentQueue defaultQueue] restoreCompletedTransactions] refreshes the receipt, however for me it doesn't no matter what I try...

All lifecycle steps are repeated and I finish all restored transactions.

I'd suggest to go with

restoreCompletedTransactions
for the following reasons
  1. SKReceidtRefreshRequest
    always failed with an error in my code, but unfortunately the error object was nil and I couldn't resolve this issue.
  2. In addition this class requires OS X 10.9 or higher, limiting its usage
  3. Your 3rd way is not very user friendly. Although customers could delete and re-purchase the app (w/o being charged), they might loose data like user preferences. And most users won't recognize repurchasing the IAP as a way to restore.

Just make sure your

SKPaymentTransactionObserver
is handling the corresponding transaction.


Mattes

Seems like exiting with 173 is the only way to get the receipt ATM. In development you have to be using Development Certificate for this to work.


Here is an example of app that does it:

itunes.apple.com/app/importer-…s/id1125811461?l=en&mt=12