ios Restore Transactions appears to refresh receipts rather than restore.

Hi, I’m following your example code for restoring transactions: Unity - Manual: iOS & Mac App Stores

mExtensions.GetExtension<IAppleExtensions>().RestoreTransactions(OnRestore);

However, the external receipt validation (PlayFab) fails because the receipt has already been used. This seems to suggest the receipts are being refreshed rather than restored, which as I understand it would produce a new transaction & receipt - restoreCompletedTransactions | Apple Developer Documentation

Additionally the docs say the user’s password will be required to restore purchases, I’m not being asked for a password when trying to restore. I am asked for a password every time I purchase an item.

I’m extracting the receipt like so:

var wrapper = (Dictionary<string, object>)MiniJson.JsonDecode(e.purchasedProduct.receipt);
var payload = (string)wrapper["Payload"];

Is there something I’m missing or need to setup for this to work as expected?

I am using 2018.2.4f1, the services tab says IAP is up to date, and the IAP package is 2.0.3 in the package manager.

I am checking with the IAP team here, but I don’t believe Restore creates a new transaction and receipt.

It’s this part of the Apple docs that suggest to me there should be a new receipt, there’s a new transaction anyway.

“The payment queue delivers a new transaction for each previously completed transaction that can be restored. Each transaction includes a copy of the original transaction.”

Perhaps I’m wrong, but if that’s the case how does receipt validation work? I’m just getting errors about it being the same receipt.

Also, as mentioned above I’m not being asked to enter a password for the restore in sandbox either.

You would want to contact Apple about the password in the Sandbox. You might count it as a blessing however, previously, a few months ago anyway, users were constantly being asked for their Sandbox password. So Apple may have removed it altogether. And do you really want to check a receipt on a Restore operation? A restore implies they already successfully and legitimately purchased previously.

Jumping in on this…

Yes, I would really want to check the restore receipt again, especially when using PlayFab: when users are getting new devices, logging in with PlayFab creates a new account for them. If they forgot adding a persistent login method (like Facebook, or Google), they are forced to use their new PlayFab account. In this case, restoring purchases with Unity IAP & validating receipts fails, due to the receipts being used on a different PlayFab account already - because the transaction id in the restore receipt is the same. So on their new account, they are never able to get the product.

I created a FogBugz entry for this in 2017 and it was never answered: 932848.

Source

1 Like

Is this being looked at or should I create a new bug report with a recent Unity version (same information though)?

A bug report would not be necessary. Keep in mind that Apple returns all products in each receipt. Your users create their own PlayFab account? Perhaps I missed your point. Would this not be a PlayFab issue then?

With PlayFab it’s possible for this scenario to occur:

  1. A user creates an anonymous PlayFab account on one device and purchases a non-consumable
  2. The user gets a new device hooked up to the same iTunes account and creates a new anonymous PlayFab account (since there’s no way to login to an anonymous account on multiple devices).

On the second device, the user will never be able to purchase the non-consumable item, because according to iTunes it has already been purchased, and according to Playfab it has already been redeemed by the first anonymous account. PlayFab needs a new receipt in order to redeem the item on the second anonymous account, but as far as I can tell there isn’t any way to do this with Unity. I’m also having this issue, and I’m now in the process of writing custom restore functionality because the built-in RestoreTransactions function appears to refresh rather than doing a true restore with new receipts.

Restore across devices is currently broken in IAP 1.22. You might test also with IAP 1.19 to confirm. But the user would not be expected to purchase the non-consumable again. But the product “Should” be restored when you call the Restore method Unity - Manual: Restoring Transactions and ProcessPurchase would be expected to fire for the product upon restore.

The issue is that the product is restored, but with the same transaction identifier. Which is different from what Apple mentions as I wrote above . We cannot send the same transaction identifier to PlayFab multiple times. I have actually given up on this ever getting fixed.

Apple documentation says that there are two unique identifiers in their receipts, an original_transaction_id and a transaction_id. These IDs can be used to

Unity IAP apparently refreshes the original transactions on restoring non-consumable purchases. This results in getting the same transaction_id as the original_transaction_id. There can be multiple use cases that need a unique transaction ID on restore purchases, like to prevent fraudulent purchases by re-using a valid receipt. One way to prevent this is to save the unique transaction ID on the server whenever any user makes a purchase, and check for the existence of a transaction ID on the server before rewarding the purchase to the user. But this logic currently doesn’t work in Unity since restore purchase returns the original transaction ID that already exists on the server, and the transaction is considered as duplicate. I’m guessing the same logic is used by PlayFab.

We have no control over the receipts returned by the stores.

Im running into the same problem. Unity IAP does not return a restore receipt but the original receipt resulting in “Receipt already used” error being returned from Playfab. Considering that restoring purchases is a mandatory feature on iOS, this means Unity IAPs can’t be used with backend service on iOS. I really don’t want to have to change tools at the 11th hour but unless this is fixed, I have no choice.

The problem isn’t with Unity IAP, really. Since iOS 7, Apple uses a single App Receipt that records all the transactions for each app. When one calls the Unity IAP API to restore IAP, what really happens is that iOS replays all the previous transactions with new transaction objects (and thus new transaction IDs), which Unity passes back to the game logic, but the App Receipt does not recreate itself with new IDs. Take a look at Apple’s guide on restoring transaction. Nowhere in the document says that the app receipt would be regenerated with new IDs.

The problem is with the decision of PlayFab to only accept IAP transactions once to stop cheating, which I favor. If IAP items is set as non-consumbale, unless you want to prevent people from using others’ Apple ID to cheat the IAP items for free, it is best not to verify the receipt through PlayFab but instead verify it on-device, or roll your own verification server.

Another approach is to set IAP items as consumable.

Either way, it is best to provide a user ways to recover their PlayFab account, e.g. ask them to provide email/password or link with a third party account. When a user signs into another device using the same account, query its inventory from PlayFab to restore purchases.

While I agree restoring from PlayFab’s player inventory directly is the most secure approach, the issue of duplicated transaction IDs is still with Unity IAP. From the Apple developer site link:

The receipt created and delivered to Unity IAP has a different transaction ID as stated by Apple. However, Unity IAP uses the “original_transaction_id” on restore, thus returning a duplicate transaction to PlayFab. The case is documented in the bug report above and honestly, it should not be that difficult to provide the correct transaction ID. It is clear that the priority is somewhere else though.

The transaction is new, but the receipt is not. Do note that you are submitting the App Receipt to PlayFab, not the transaction objects. The original transaction in the receipt does not change no matter how many times you restore it – the system only sync with the original copy from App Store.

By the way, this screenshot is from is the Unity IAP source code that you can also observe in your exported Xcode project.

Here, Unity never passed back any original transaction IDs, which in iOS is retrieved by calling “transaction.originalTransaction.originalTransaction”.


Here’s is their logic of “selectReceipt:” method

Is there any update on this? This is mandatory in order to publish for IOS. The apps will get rejected due to this.

FWIW, we have many developers successfully publishing on iOS. I will mention this again to the IAP team

Can you describe what you would expect to see here?