Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice
  2. Ever participated in one our Game Jams? Want pointers on your project? Our Evangelists will be available on Friday to give feedback. Come share your games with us!
    Dismiss Notice

ios Restore Transactions appears to refresh receipts rather than restore.

Discussion in 'Unity IAP' started by playsportmatt, Jan 25, 2019.

  1. playsportmatt

    playsportmatt

    Joined:
    Sep 1, 2016
    Posts:
    4
    Hi, I'm following your example code for restoring transactions: https://docs.unity3d.com/Manual/UnityIAPiOSMAS.html

    Code (CSharp):
    1. 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 - https://developer.apple.com/documen...23-restorecompletedtransactions?language=objc

    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:

    Code (CSharp):
    1. var wrapper = (Dictionary<string, object>)MiniJson.JsonDecode(e.purchasedProduct.receipt);
    2. 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.
     
  2. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    7,172
    I am checking with the IAP team here, but I don't believe Restore creates a new transaction and receipt.
     
  3. playsportmatt

    playsportmatt

    Joined:
    Sep 1, 2016
    Posts:
    4
    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.
     
  4. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    7,172
    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.
     
  5. Baroni

    Baroni

    Joined:
    Aug 20, 2010
    Posts:
    2,310
    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
     
    JeffDUnity3D likes this.
  6. Baroni

    Baroni

    Joined:
    Aug 20, 2010
    Posts:
    2,310
    Is this being looked at or should I create a new bug report with a recent Unity version (same information though)?
     
  7. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    7,172
    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?
     
  8. cabbyU

    cabbyU

    Joined:
    Sep 21, 2016
    Posts:
    11
    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.
     
  9. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    7,172
    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 https://docs.unity3d.com/Manual/UnityIAPRestoringTransactions.html and ProcessPurchase would be expected to fire for the product upon restore.
     
  10. Baroni

    Baroni

    Joined:
    Aug 20, 2010
    Posts:
    2,310
    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.
     
  11. alimustafa90

    alimustafa90

    Joined:
    Jul 23, 2017
    Posts:
    1
    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.
     
  12. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    7,172
    We have no control over the receipts returned by the stores.
     
  13. AllWallsWillFall

    AllWallsWillFall

    Joined:
    Nov 21, 2012
    Posts:
    2
    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.
     
  14. Neonlyte

    Neonlyte

    Joined:
    Oct 17, 2013
    Posts:
    167
    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.
    https://developer.apple.com/documen...se/restoring_purchased_products?language=objc

    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.
     
  15. Baroni

    Baroni

    Joined:
    Aug 20, 2010
    Posts:
    2,310
    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.
     
  16. Neonlyte

    Neonlyte

    Joined:
    Oct 17, 2013
    Posts:
    167
    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.
     
  17. Neonlyte

    Neonlyte

    Joined:
    Oct 17, 2013
    Posts:
    167
    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".
    QQ20200419-193313@2x.png
    QQ20200419-192431@2x.png

    Here's is their logic of "selectReceipt:" method
    QQ20200419-193423@2x.png
     
unityunity