Search Unity

  1. Unity 2018.3 is now released.
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. We've updated our Terms of Service. Please read our blog post from Unity CTO and Co-Founder Joachim Ante here
    Dismiss Notice
  4. Want to provide direct feedback to the Unity team? Join the Unity Advisory Panel.
    Dismiss Notice
  5. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice

Unity IAP How to Retry PurchaseProcessingResult.Pending Purchase?

Discussion in 'Unity IAP' started by TitanUnity, Jun 26, 2018.

  1. TitanUnity

    TitanUnity

    Joined:
    May 15, 2014
    Posts:
    174
    Hi,

    We're having trouble retrying Pending purchases since upgrading to Unity 2018.1.3f1. Our payment flow works like this:

    PurchaseProcessingResult.Pending.png


    The specific problem occurs if our App Server is unavailable for any reason. So in a test scenario let's say we disable our App server (preventing steps 6 and 7 from completing). You can see that the ConfirmPendingPurchase call will never fires so the purchase is left in a Pending state.

    Our assumption was that by retrying the purchase of the product we could "retrigger" the validation process and the purchase would be completed, but this doesn't work:
    m_StoreController.InitiatePurchase(product);

    It just fires an error: PurchaseFailureReason.DuplicateTransaction

    Was something changed? The only way we've found to make this work so far is to close the app and restart, forcing the store to re-initialize which will retrigger ProcessPurchase for the Pending transaction.
     
  2. TitanUnity

    TitanUnity

    Joined:
    May 15, 2014
    Posts:
    174
  3. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    3,130
    I am checking the IAP team and will follow up
     
  4. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    3,130
    If previously you attempted to purchase again and if it succeeded, wouldn't that orphan the first transaction and leave it in pending? Cannot you retry Step 6 above and implement a time out and/or error return with a retry mechanism, instead of attempting to purchase again? We suspect that the previous behavior was in error. What would be your ideal behavior for the IAP system (other than attempt to repurchase)?
     
  5. TitanUnity

    TitanUnity

    Joined:
    May 15, 2014
    Posts:
    174
    Before installing Unity 2018, if a purchase was left in a Pending state as described above, if we called InitiatePurchase
    Code (CSharp):
    1. m_StoreController.InitiatePurchase(product);
    the Unity IAP system would automatically retrigger ProcessPurchase:
    Code (CSharp):
    1. public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs e){ ..  }
    and the Pending purchase for the user would be automatically Completed and delivered.

    It seems now that when calling InitiatePurchase() for a product that is in a pending state, the Unity IAP system throws a PurchaseFailureReason.DuplicateTransaction error instead.

    As you mentioned, if the original behavior of the Unity IAP system automatically calling ProcessPurchase was an error that at least makes sense, but you're right, we now need to implement our own retry logic for player's that encounter purchase problems during their session and then manually call
    Code (CSharp):
    1. m_StoreController.ConfirmPendingPurchase(product);
    when the purchase has been validated.

    We actually started built a flow last night that simulates what the Unity IAP did before. But to answer your question about our ideal behavior, the only thing that makes sense to us in the case that our App Server is inaccessible is to present the user with an error message suggesting that the purchase was NOT delivered successfully and to please try again. At that point, the user has 2 options:

    1. Relaunch our app and open our store UI which will automatically complete the transaction on IAP init:
    Code (CSharp):
    1. UnityPurchasing.Initialize();
    2. Try again (tap the product they wanted to buy again). The system would call a smart InitiatePurchase() that would detect an incomplete Pending transaction for that product and proceed to ProcessPurchase, if no Pending purchases were outstanding it would create a new transaction so there would be no orphan transactions. << We just built this flow manually, it looks something like this:

    Code (CSharp):
    1.     public override void PurchaseProduct(string sku)
    2.     {
    3.         try
    4.         {
    5.             if (!IsInitialized())
    6.             {
    7.                 OnPurchaseFailed("Store not initialized.");
    8.             }
    9.             else
    10.             {
    11.                 Product product = m_StoreController.products.WithID(sku);
    12.                 if (product == null)
    13.                 {
    14.                     OnPurchaseFailed("Product not found.");
    15.                 }
    16.                 else if (IsProductPending(product))
    17.                 {
    18.                     StartCoroutine(ValidateTransaction(product));
    19.                 }
    20.                 else if (!product.availableToPurchase)
    21.                 {
    22.                     OnPurchaseFailed("Product not available for purchase.");
    23.                 }
    24.                 else
    25.                 {
    26.                     m_StoreController.InitiatePurchase(product);
    27.                 }
    28.             }
    29.         }
    30.         catch (Exception e)
    31.         {
    32.             OnPurchaseFailed("Could not initiate purchase transaction. Error: " + e.Message);
    33.         }
    34.     }
    So you can see we're manually checking if the product is Pending by calling IsProductPending(). We also implement our own ValidateTransaction() coroutine that calls m_StoreController.ConfirmPendingPurchase(product) on success.
     
    Last edited: Jun 27, 2018
  6. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    3,130
    Attempting to purchase again is not valid flow. As mentioned, it would leave the previous transaction in an orphaned state. A DuplicatePurchase error the second time would be expected. Apologies if you saw different behavior in a previous version, the current flow is now correct as far as we can tell. During the Step 6 above, you would want to retry as you agreed. You can test Pending behavior with this sample project. It might make sense to create a separate button for Initialize, instead of in the Start() method. The Toggle button allows you to either return Pending or Complete from ProcessPurchase. Currently, if you have a product left in Pending, the next time the app starts and IAP initializes, ProcessPurchase (for the original purchase left in Pending) is triggered, and you can retry your validation again. Otherwise, if your server is down, you will need to retry at run time. Otherwise, you have two options. Simply pass the product to ConfirmPendingPurchase without the server validation, or relaunch the game.

    https://forum.unity.com/threads/sample-iap-project.529555/
     
    MihaPro_CarX likes this.
  7. stokato

    stokato

    Joined:
    Aug 20, 2018
    Posts:
    1
    But how can I check what the product is pending?
     
  8. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    3,130
    @stokato Do you mean at app launch? If so, are you receiving a ProcessPurchase callback for the product? I've been testing with this sample app which allows you to configure Pending vs Complete at run time (using the Toggle button). I also write debug information to the UI. https://forum.unity.com/threads/sample-iap-project.529555/
     
  9. Lesha-VH

    Lesha-VH

    Joined:
    Jul 3, 2012
    Posts:
    68
    Unity 2017.4.8f1
    IAP 1.21.0
    Android/Google Play store

    I make purchase (press buy button after enter password), than - BEFORE google answer - disconnect device from internet.

    After restore internet connection and press the same item I get error in
    public void OnPurchaseFailed(Product i, PurchaseFailureReason p)
    with reason UserCancelled

    After re-launch application IAP plugin does not call
    public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs e)
    and I can not buy the same consumable item with reason UserCancelled

    I think purchases hangs somewhere - or I miss something?
    Thanks!
     
    Last edited: Sep 5, 2018
  10. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    3,130
    Understood, thank you for the description. Are you able to purchase after you reinstall the app?
     
  11. Lesha-VH

    Lesha-VH

    Joined:
    Jul 3, 2012
    Posts:
    68
    Jeff, after re-install I CAN NOT buy the same consumable product. (no call ProcessPurchase at app launch, when try to buy - OnPurchaseFailed with reason UserCancelled)
     
  12. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    3,130
    Got it, we are investigating.
     
  13. Lesha-VH

    Lesha-VH

    Joined:
    Jul 3, 2012
    Posts:
    68
    Jeff, did you reproduce the bug?
    Only install NEW application version from google play version fix it))
     
  14. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    3,130
    @Lesha-VH Can you elaborate? Did you fix it?
     
  15. ThiagoUken

    ThiagoUken

    Joined:
    Sep 26, 2018
    Posts:
    1
    I'm having the same issue with pending purchases. Is there a more elegant way to handle it without having to restart the app? I tried calling UnityPurchasing.Initialize again without restarting but it doesn't fire the ProcessPurchase event.
     
  16. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    3,130
  17. SyedUmair

    SyedUmair

    Joined:
    Sep 2, 2013
    Posts:
    27
    I am also having exact problem. Unity Team should handle it in a better way or at least provide a method to fetch pending purchases at run-time. So, we can check and call ConfirmPendingPurchase without the need to re-launch the app.
     
  18. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    3,130
    Your pending purchases will be available when you initialize IAP. You can initialize IAP at any time. But yes, we are working on an improved solution.
     
  19. SyedUmair

    SyedUmair

    Joined:
    Sep 2, 2013
    Posts:
    27
    it's great, if you guys are working to improve the flow.
    Yes, for now, I would do multiple initializes to get the pending transactions. But, I guess, its not the best idea to call Init methods once SDK is initialized, successfully. :)
     
  20. jjurica

    jjurica

    Joined:
    Feb 14, 2017
    Posts:
    1
    Hello. I was wondering if you would kindly share IsProductPending() and ValidateTransaction() coroutine? There still seems to be missing information on how to access the list of pending purchases. Thanks