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
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Bug Pending purchases for a long time are forgotten by the API

Discussion in 'Unity IAP' started by Claudiocdj, May 5, 2022.

  1. Claudiocdj

    Claudiocdj

    Joined:
    Jun 15, 2021
    Posts:
    6
    Hi guys,

    When I make a purchase in my game(Android), if I close the game with the purchase pending and then open it again, the purchase flow is performed normally.

    If I close the game with the purchase pending and open it after a long time, the purchase is never processed. The
    StoreListener.ProcessPurchase(PurchaseEventArgs e)
    is never called. Using
    IGooglePlayStoreExtensions.RestoreTransactions(Action<bool>)
    also does not call it.


    The purchase is processed with the game closed and when I open the app I do not receive the reward. This case only occurs when I stay more than 10 minutes with the game closed.


    Is there a way to check the status of a purchase using the same product ID that I used in the
    IStoreController.InitiatePurchase(string)
    method? When I initialize the StoreListener, can I check if a pending purchase was processed during the closed time.


    Thank you.
     
  2. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Can you share your full code for ProcessPurchase? We have not heard of this behavior. ProcessPurchase should always be triggered for any transaction still in Pending. You mention "the purchase is processed with the game closed", how do you know that? Does the user account show it as purchased? You are not doing any server side transaction handling? What type of product is this, consumable, non-consumable or subscription? If non-consumable or subscription, if the transaction was indeed completed outside the game, the user would be expected to see "Duplicate Transaction" if they tried to purchase it again later. And can you confirm why you are returning Pending?
     
  3. Claudiocdj

    Claudiocdj

    Joined:
    Jun 15, 2021
    Posts:
    6
    Hi @JeffDUnity3D,

    Thanks for your explanation. I recently got an alert from the Google Play Console and started investigating what the problem is.

    The message:
    We've turned off some payment methods. We've noticed that you don't always acknowledge the delivery of in-app content to users after they've paid outside your app. Or you don't integrate pending transactions correctly. As a result, payment methods that require pending transactions, like paying with cash, have been turned off. Other payment methods aren't affected. Contact us once you've fixed the issue so we can turn these payment methods back on.


    I used Google Play Slow Card Payments to test a purchase for a consumable product, and while the purchase was being processed I closed the game. if I open the game again in a short time, the purchase flow is performed normally but the problem happens when I take a long time to open the game, the API forgets about this purchase. I don't know if it could be something related to the test card or my application.

    I also don't understand what problem is related to the Google message.

    This is a snippet from the class that implements the IStoreListener interface and I also do the server side validation:
    Code (CSharp):
    1. public void InitiatePurchase (string productId)
    2. {
    3.     if (StoreController != null)
    4.     {
    5.         StoreController.InitiatePurchase(productId);
    6.     }
    7.     else
    8.         OnPurchaseError?.Invoke(PurchaseFailureReason.PurchasingUnavailable);
    9. }
    10.  
    11. public PurchaseProcessingResult ProcessPurchase (PurchaseEventArgs e)
    12. {
    13.     try
    14.     {
    15.         _ = Task.Run((() => ProcessPurchaseAsync(e))
    16.         return PurchaseProcessingResult.Pending;
    17.     }
    18.     catch (Exception ex)
    19.     {
    20.         Debug.LogError("Error while processing purchase.");
    21.         Debug.LogException(ex);
    22.         return PurchaseProcessingResult.Complete;
    23.     }
    24. }
    25. async Task ProcessPurchaseAsync (PurchaseEventArgs e)
    26. {
    27.     try
    28.     {
    29.         ReceiptValidationStatus status = await ValidateReceipt(e);
    30.         if (status == ReceiptValidationStatus.Pending)
    31.             return;
    32.         mainThread.Schedule(() =>
    33.         {
    34.             if (status == ReceiptValidationStatus.Success)
    35.                 HandlePurchaseComplete(e, false);
    36.             else
    37.                 DeclinePurchase(e.purchasedProduct, PurchaseFailureReason.SignatureInvalid);
    38.         });
    39.     }
    40.     catch (Exception ex)
    41.     {
    42.         Debug.LogException(ex);
    43.         throw;
    44.     }
    45.     finally
    46.     {
    47.         mainThread.Schedule(() => OnOperationCompleted?.Invoke());
    48.     }
    49. }
    50. void HandlePurchaseComplete (PurchaseEventArgs e, bool restoring)
    51. {
    52.     string id = e.purchasedProduct.definition.id;
    53.     GrantReward(id);
    54.     storeListener.ConfirmPendingPurchase(e.purchasedProduct);
    55. }
    56. void HandlePurchaseError (PurchaseFailureReason _)
    57. {
    58.     mainThread.Schedule(() => OnOperationCompleted?.Invoke());
    59. }
     
  4. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    @claudioDomene It seems like you are changing topics now. This last message is about deferred purchase handling, not about transaction handling after 10 minutes. Your code is unfamiliar, where you have seen to use async tasks with Unity IAP? And you only return Complete if there is an exception? This code would be unsupported. Please compare to the code from the Sample IAP Project v3 https://forum.unity.com/threads/sample-iap-project.529555/#post-7922275 You need to handle Google Deferred Purchases (sometimes referred to as Pending Purchases). It's a new purchase option from Google where users can purchase an IAP in the game, and then have 3 days to pay at a physical store location approved by Google. You need to return Pending from ProcessPurchase until purchaseState = 1 (purchased) and wait to award the product to the user until purchaseState = 1. Until then, you continue to return Pending from ProcessPurchase. You can tell a Pending purchase if purchaseState = 4 or 2. (purchaseState = 4 is not yet documented by Google) This forum post talks about how to check purchaseState.

    https://forum.unity.com/threads/google-play-iap-problem.1140367/#post-7351220

    If you look in Package Manager under the Samples for In App Purchasing you'll see

    Google Play Store - 04 Handling Deferred Purchases

    This is also discussed here.

    https://forum.unity.com/threads/deferred-purchase.1157054/

    But this should have nothing to do with different behavior after 10 minutes.
     
  5. Claudiocdj

    Claudiocdj

    Joined:
    Jun 15, 2021
    Posts:
    6
    Hi @JeffDUnity3D,

    Thanks for the explanations, I will implement your observations.

    We use asynchronous methods because we do server-side validation, so we need to wait for the response that the purchase was actually made before confirming a purchase.

    To test my corrections, how do I make my purchase receipt to have
    PurchaseState == 4
    ?

    Do i make a slow credit card purchase and then close the app for a few minutes before opening it again? How can I test to get this type of
    PurchaseState
    ?
     
  6. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    No, you do not need to do async processing for server side validation. What do you mean, wait for the response that the purchase was actually made, you mean you are waiting on your server response? Understood if so. The slow credit card option has never worked reliably. But back to your original question. So every purchase still in Pending disappears after 10 minutes? That would be separate from deferred purchase and is not expected. I might suggest to suppress your server validation logic for a few tests, and remove your async processing and then test Pending purchases to rule out as many variables as possible.
     
  7. Claudiocdj

    Claudiocdj

    Joined:
    Jun 15, 2021
    Posts:
    6
    OK, I'm going to try it, thanks!

    How can I reproduce a deferred purchase?
     
  8. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    As far as I know, the Slow Credit Card with Success is the closest option that Google offers for testing this feature.