Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Question Unity IAP - Restoring subscriptions

Discussion in 'Unity IAP' started by filip-yakuto, Sep 8, 2022.

  1. filip-yakuto

    filip-yakuto

    Joined:
    Aug 30, 2018
    Posts:
    5
    Hi,

    We need to implement restore functionality for purchases on iOS. We offer subscriptions and consumables in our products, so all the restored purchases should be subscriptions (it looks like they are by looking at the product ids).
    I have followed the documentation and added a method that triggers the purchase restore functionality for ios using the `IAppleExtensions`.

    `IStoreListener.ProcessPurchase(PurchaseEventArgs purchaseEvent)` is successfully invoked, however it is invoked for a bunch of transactions that we cannot validate against our backend records using the transaction Id.
    Also, recently purchased subscriptions doesn't seem to be coming back.

    1. Is the ProcessPurchase callback being invoked for previous purchases in any particular order? (i.e. most recent first)
    2. Does unity IAP pick up sandbox payments properly ?
    3. Does unity IAP pick up subscriptions on trial ?

    NOTE: I Also noticed that `ProcessPurchase` was triggers as part of the initialisation process on iOS, however the documentations states that that shouldn't be the case?

    unity version : 2020.3.38f1
    iap version: 4.1.5
     
  2. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Apple bundles all receipts. ProcessPurchase is not called in any order. Not sure what you mean by "pick up payments". But yes, if I understand correctly. What is your observation with subscriptions on trial? We are working on improved subscription support including trials as we move to StoreKit2 by the end of the year.
     
  3. filip-yakuto

    filip-yakuto

    Joined:
    Aug 30, 2018
    Posts:
    5
    Thanks for your promt response.

    When I say pick up i basically ask whether `ProcessPurchase` will be invoked for sandbox payments/ subscription on trial.
    The problem I am trying to resolve is, how can I detect what's the latest/valid purchase from all these subscription purchase transactions ?

    When i try to test the functionaity I :
    1. buy a subscription product (sandbox)
    2. delete the app
    3. re-install
    4. try to restore

    At this point, none of the transaction ids that are being restored maps to the latest purchase.
    Also it takes some time before unity IAP allows a subscription purchase to go through again (but i think that's a problem with the nature of sandbox subscriptions that don't last long)
     
  4. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    We use purchaseToken, this post should help https://forum.unity.com/threads/goo...-with-purchasedproduct-transactionid.1168256/
     
  5. filip-yakuto

    filip-yakuto

    Joined:
    Aug 30, 2018
    Posts:
    5
    Isn't `purchaseToken` Android specific ?

    I am getting wrong transactionIds on iOS. I am querying the transaction id that can be found in
    Code (CSharp):
    1. purchaseEvent.purchasedProduct.transactionID
    . Am i missing something ?
     
  6. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Oops, sorry about that, you are correct. I will follow up with the team here. I did find this https://developer.apple.com/documentation/appstoreserverapi/originaltransactionid
     
  7. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    This is how you can find the originalTransactionIdentifier from an AppleInAppPurchaseReceipt. That receipt can be found in the purchaseProduct.receipt.

    Code (CSharp):
    1.     private void LogAppleReceiptValidationInfo(IPurchaseReceipt productReceipt)
    2.     {
    3.         var appleReceipt = productReceipt as AppleInAppPurchaseReceipt;
    4.         if (appleReceipt != null)
    5.         {
    6.             LogConsole($"Apple - Original Transaction: '{appleReceipt.originalTransactionIdentifier}', Expiration Date : '{appleReceipt.subscriptionExpirationDate}', Cancellation Date : '{appleReceipt.cancellationDate}', Quantity : '{appleReceipt.quantity}'");
    7.         }
    8.     }
     
  8. filip-yakuto

    filip-yakuto

    Joined:
    Aug 30, 2018
    Posts:
    5
    When you say purchaseProduct.receipt are you referring to the purchasedProduct property in PurchaseEventArgs that is of type Product ?

    The receipt in there is a string. Is this the same receipt documented here? https://docs.unity3d.com/Manual/UnityIAPPurchaseReceipts.html

    If so, how do we get the IPurchaseReceipt (and therefore the AppleInAppPurchaseReceipt) from the string receipt ?

    Can I deserialise the payload from the receipt into an AppleInAppPurchaseReceipt?
     
  9. Yannick_D

    Yannick_D

    Unity Technologies

    Joined:
    Feb 21, 2022
    Posts:
    218
    The receipt you have is a string as a JSON hash, the same as the link you posted.

    From that receipt (found in purchaseProduct.receipt), you can use the CrossPlatformValidator.Validate which will return an array of IPurchaseReceipt.

    Alternatively, you can also use the AppleValidator.Validate to obtain an AppleReceipt which has inAppPurchaseReceipts containing an array of IPurchaseReceipt.

    See both examples (Store-specific details and Parsing raw Apple receipts):
    https://docs.unity3d.com/Manual/UnityIAPValidatingReceipts.html
     
  10. filip-yakuto

    filip-yakuto

    Joined:
    Aug 30, 2018
    Posts:
    5
    Thanks! I used cloud verification instead and managed to get the original transaction id.

    When attempting to restore purchases (subscriptions in my case) do we need to call `StoreController.ConfirmPendingPurchase` for any result we get back?

    I get some weird behaviour where, when i try to restore purchases and nothing comes back from Unity IAP, and then I try purchase the product, unity IAP fails the purchase with a reason `Duplicate Transaction`.
     
  11. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    No, there is no need to call ConfirmPendingPurchase during restore. Basically treat it like a brand new purchase. You should see ProcessPurchase triggered for each product that is restored.
     
  12. StacticKoud

    StacticKoud

    Joined:
    Nov 29, 2018
    Posts:
    8
    We have this exact same issue on iOS with Unity IAP 4.4.1
     
  13. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    To avoid confusion, please provide your steps to reproduce.
     
  14. novaVision

    novaVision

    Joined:
    Nov 9, 2014
    Posts:
    493
    But it doesn't. Here is my case:

    I got 2 subscriptions which must be verified on app start. I was able to test it on iOS only using Test Flight using my actual Apple ID account (not a sandbox user).

    By some reason, each time starting the app I am forced to make the subscription purchase because these 2 subscription products just doesn't have a receipt so I can't verify, is subscription active or not.
    Even knowing the fact it's not related to purchase restore feature (because app wasn't re-isntalled) but trying to restore purchases using `appleStore.RestoreTransactions` method, I receive only `true` as a result, but never receive
    ProcessPurchase callback. Also, checking the subscriptions receipts after restore I can't get any info, because receipts were not found.
    Furthermore, once I see these logs trying to restore the purchase - by some reason there wre unfinished transaction

    Code (CSharp):
    1.  

    How to get the ProcessPurchase callback and make the things works as expected?

    I am on Unity 2021.3 and IAP 4.5.1


    UPDATE
    Finally, I could make it work using Sandbox user login in AppStore app settings. However, there are still no callback after purchase restore request - if user without any subscription tries to restore purchased, I still will get `true` as a response. Sounds logically if that callback represents just a restore purchase request result, but in terms of app development it's impossible to understand in right time does user has a purchase or not. If he has, I will get the process purchase callback what is fine, but if not, I need to check the receipt again after getting `true` in purchase restore request, but I need to do it in some delayed time, becuase can be the case that
    process purchase callback can be delayed...
     
    Last edited: Dec 18, 2022