macOS In-App Purchase product restore doesn't update receipt

I'm developing a freemium app with a non consumable IAP.

When I originally start the app with a test user it correctly downloads the initial receipt for the app, the one that doesn't contain any product id (no Type 17 values included).

Then I proceed, as a test user, with the only non consumable purchase avaiable and it correctly downloads the receipt that contains the purchased product id (and all other Type 17 validatable values).


To test a restore scenario I then usually delete (as root to not mess up the file privileges) the receipt that contains the product id and I swap it with the one downloaded originally (with no product id).


I then initiate the process of restoring calling:

[[SKPaymentQueue defaultQueue] restoreCompletedTransactions]

it goes through flawlessly but the receipt is not updated with the product id of the product that should have been restored.


If then I try to force this process using

SKReceiptRefreshRequest

storeassetd replies with: "### Receipt is VALID for app (/pathToApp.app), checkSignature = 0. No need to renew." And the request fails with error: (null).


And it sounds right, because the receipt inside the bundle IS valid, but I need it to be updated with the product id (and every other Type 17 values) so that I can validate it and unlock the paid features for the user.


How can I update a receipt after a restore purchase?

I am unfamiliar with MacOS - I just do iOS.

But I suspect the problem is this fancy approach:

"To test a restore scenario I then usually delete (as root to not mess up the file privileges) the receipt that contains the product id and I swap it with the one downloaded originally (with no product id)."

The device must keep some record of the receipt and that record doesn't get deleted or swapped. Therefore the system doesn't refresh the receipt because it is, it thinks, current.


If you wish to test a restoreCompletedTransactions then do what the user would do; delete the app from the device and then reinstall it.

Unfortunately on macOS sandbox environment the receipt is the first thing that has to be there to be able to launch and start the app.

Every time the app starts without a receipt it exits with code 173 and that triggers a Mac App Store login to download the receipt again.


I can save a copy of the app with only the original receipt in it, proceed to purchase on another copy of the app and then try the restore on the first copy that has the receipt without the purchased product id inside.


The result is the same, the "restore" passes with no problem but the receipt is not updated with the product id of the purchased product.

TMI. Pretend to be a user who will need to restore their IAP. Emulate what that user does. Doesn't that user delete the app, wait three weeks and then say "hey I want that app again'. Then they download it from the App Store and tap 'restore'. Well you emulate that by deleting the app, no need to wait three weeks, reinstall from Xcode (rather than downloading from the App Store), and tap restore.

If you start the app from finder and it doesn't have a receipt in it it will asks for the App Store login to download one to be able to be launched.

Otherwise it doesn't open.

The receipt must be there to be launched, the Mac App Store always provide a receipt for your app.

The same receipt is downloaded with the app from the app store and, if you already had purchased the iap, the product id of the iap is already inside the receipt.

I need to test a restore, from a situation with a valid receipt with no product id inside to a situation with a receipt that has the product id.

The only ways to simulate this scenario is to swap the receipt as i wrote, or to save a copy of the app with just the initial receipt inside, purchase from another copy and then restore from the first copy.

Both ways I end up with a non updated receipt (that doesn't have the product id inside).

Let's try this again. Can you delete the app from your Mac? Of course you can! Can you reinstall the app on your Mac from Xcode? If so, why not do that and try your restore on that reinstalled app?

And here is a reference on how to launch on a different Mac.

https://developer.apple.com/library/content/documentation/IDEs/Conceptual/AppDistributionGuide/BetaTestingYourMacApp/BetaTestingYourMacApp.html


You can't sandbox test your IAP on an App that is downloaded from the App Store. Such an app operates only in the production environment.

Because, as I already explained, this would lead to a MAS login request that would lead to a download of an updated receipt. That works as expected and I do not have to test that.


What I have to test is this scenario:

You downloaded the same app on 2 mac. You purchase the IAP on the first mac. You want to restore the purchase on the second mac.


The way to achive it on a test environment is to swap the receipt or have 2 copy of the app.


The class and method that is supposed to updated the receipt is [[SKPaymentQueue defaultQueue] restoreCompletedTransactions] but apparently it doesn't work.

I'm not testing on a mas downloaded app, I build from xcode and then i open the app from the finder following the way that is described by the doc.


By the way the reference is this one:


https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/Restoring.html#//apple_ref/doc/uid/TP40008267-CH8-SW9

I recommend that you reread the posts above and reconsider what you are trying to do.

But you certainly know best.

Good luck!

Thank you for your raccomandation, I tried (really) to follow your suggestion but unfortunately it didn't help.

I know this is an old question but this appears on the top of the results when searching for this problem, so my answer here should be useful for everyone else having the same issue.


The scenario jackwolf81 described is similar to this.


You have a fremium app with an In-App Purchase. The user has the app installed on two Macs. He buys the In-App purchase on one of his Macs and now wants to restore the purchase on the other Mac.


1. SKReceiptRefreshRequest will not work because the receipt is valid (Note that it does work for invalid and missing receipt cases).

2. restoreCompletedTransactions will replay the transactions but will _not_ update the receipt.

3. The only solution is to exit(173)



So currently my code is doing this.

- Check for a valid receipt.

- If valid, warn the user a relaunch is required and exit(173)

- If not valid, use the SKReceiptRefreshRequest API (avoiding having to relaunch the app)

macOS In-App Purchase product restore doesn't update receipt
 
 
Q