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. Dismiss Notice

IAP restore issues (Android)

Discussion in 'Unity IAP' started by DanWeston, Mar 31, 2019.

Thread Status:
Not open for further replies.
  1. Lisan

    Lisan

    Joined:
    Jun 17, 2009
    Posts:
    214
    Okay, "short live the Bug!" then. :)
     
    JeffDUnity3D likes this.
  2. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Ok that was funny! This is my highest priority issue right now, I'm personally testing to ensure that it gets fixed quickly.
     
  3. Tankzo

    Tankzo

    Joined:
    Jul 16, 2019
    Posts:
    16
    Jeff,
    You're fixating on the word "restore."

    True, we don't need to do a "restore" to the google store but we sure as heck need to be able to know if a "receipt" (m_StoreController.products.WithID(id).hasReceipt) exists for a given non-consumable.
    (Mostly because we set a bool in OnInitialized() (or more accurately for me, 0.5 seconds AFTER OnInitialized()) that is used elsewhere in our apps that disables Ads, increases multipliers, adds time, or a host of other 'perks' that are granted when a user has purchased our apps.)

    IAP does the automatic 'restore' great but SOMETHING is providing: "Already recorded transaction <TransactionID>" in the Debug.Log() (I thought it would be in ProcessPurchase, but I'm logging EVERYTHING in that function and NONE of my debug.logs are getting hit in ProcessPurchse or OnPurchaseFailed() during the "automatic restore"), and we really want/need to be able to set our bools based on this "SOMETHING...."
     
    Last edited: Dec 2, 2020
  4. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    @Tankzo Yes, this thread is specifically about Restore (only). Restore is the behavior when the user purchases a non-consumable or subscription. They either then reinstall the game, or install the app on a second device. The expectation is that Restore will properly trigger ProcessPurchase for each of these products, so the products are "restored" onto the device automatically. Your point about the receipt being available is a separate issue. But if the Restore properly occurs, then the receipt will come along with it. To be clear, we have some issues around this and not working as expected. The hope was that the Google Billing Library v3 should have resolved this. We are also working to address the async issue that you mentioned, but again, a separate issue. (we have a few)
     
  5. Tankzo

    Tankzo

    Joined:
    Jul 16, 2019
    Posts:
    16
    @JeffDUnity3D,

    2.2.3 fixed the issue with timing of the restore of non-consumable purchases with the Google play store.

    IDK what the bug number is but the solution is listed in the release notes:
    - GooglePlay - `IStoreListener.OnInitialized` is now called after all purchases have been fetched from the store.

    (Yes, I understand that the fetching occurs automatically with google but having OnInitialized returning before the fetch is completed is what caused @Funtyx's (and my) issue.)

    Tested and verified on API 19, 21, & 27 devices

    Thank you for fixing this one! <3
     
    JeffDUnity3D likes this.
  6. Lisan

    Lisan

    Joined:
    Jun 17, 2009
    Posts:
    214
    Hello,

    Is it intended behaviour, that in 2.2.4 on every application focus lost and restore i see following in the log?

    2020-12-16 20:58:46.004 4751-4813/? I/Unity: Already recorded transaction xxx
    UnityEngine.Purchasing.PurchasingManager:processPurchaseIfNew(Product)

    I tried to switch the screen off and back on, and every time new such line added.

    BR, Alexey
     
  7. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Yes, it's expected.
     
  8. Lisan

    Lisan

    Joined:
    Jun 17, 2009
    Posts:
    214
    Hi,
    With 2.2.4 and 2.2.5 i have following behavior:

    On application start my purchase is restored. When restoring, it is succesfully validated on our server, but after validation, when calling
    Code (CSharp):
    1. _storeController.ConfirmPendingPurchase(product)
    it writes following:
    "Unable to confirm purchase; Product has missing or empty transactionID"

    It is the same product, which was succefully validated before.

    Is it a bug, and is it dangerous?

    BR, ALexey
     
  9. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Yes, we are aware of the issue and hope to have it resolved in an upcoming release
     
  10. Lisan

    Lisan

    Joined:
    Jun 17, 2009
    Posts:
    214
    Thanks.
    But can you, please, describe the current state of issue, what exactly happens and how it can affect the flow? I need to decide, can i release the game with 2.2.5 or not.
     
  11. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    If you use ConfirmPendingPurchase on a consumable product, the user would not be able to purchase the product again. So you'll want to test this scenario.
     
  12. Lisan

    Lisan

    Joined:
    Jun 17, 2009
    Posts:
    214
    And if i don't have consumables (and i don't) this issue is not affecting my users?
     
  13. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    You'll want to test in your specific situation. You'll continue to get a ProcessPurchase during every app start for all products left in this Pending state, and you'll need to validate the product receipt each time.
     
  14. Lisan

    Lisan

    Joined:
    Jun 17, 2009
    Posts:
    214
    Is there any hope, that we will get 2.2.6 with this fix anytime soon?
    It happened that this behaviour broke our game logic badly.
     
  15. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Hopefully addressed within the first few weeks of January, the team is on holiday break now.
     
  16. Daryl_1

    Daryl_1

    Joined:
    Feb 13, 2014
    Posts:
    22
    There needs to be an easier way for us to rollback to an earlier IAP version..
     
  17. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
  18. Lisan

    Lisan

    Joined:
    Jun 17, 2009
    Posts:
    214
    We have epic consequences for chosing to stay on 2.2.5 :(
    We just changed the code to compensate the bug, but after a week or so started to get mass refunds for purchases.
    All these refunds are the same, happened exactly after 72 hours after purchase was made. User himself have no way to request refund after 48 hours, so it's Google doing. And after some seach we discovered, that Google refund purchases automatically if they not confirmed in 72 hours. So it was VERY bad decision to release the game with 2.2.5
     
  19. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    We are looking into this.
     
  20. Lisan

    Lisan

    Joined:
    Jun 17, 2009
    Posts:
    214
    Meantime, we will try to roll back to fix it fast, but how do we decide which version to chose? We need to roll back to some stable version without critical bugs.
    Every version has description with issues fixed, but no one has description with issues broken. I wrote about it before, it's not a good behavior, cause users can still keep installing 2.2.5 without knowing about this epic bug.
    And i read in 2.2.5 "- Fixed - GooglePlay - Fails to initialize when the player has made no purchases" - it's important fix, but where it was broken, in 2.2.4 or earlier?
     
  21. Lisan

    Lisan

    Joined:
    Jun 17, 2009
    Posts:
    214
    Jeff?
    Is there any chance we will get update in the 1-2 days? We are losing a lot of money every day on refunds.
    If we have to wait more, i better roll back for now, but which version to chose for rolling back? It's hard to chose without knowing the bugs of each version.

    As far as i can suppose:

    2.2.5 - bug with refunds
    2.2.4 - bug with initialization (?) It said in 2.2.5 "Fixed - GooglePlay - Fails to initialize when the player has made no purchases" I haven't seen this bug, and don't know, is it bug from 2.2.4 or from other vesrion.
    2.2.3 - "ProcessPurchase called more than once for any purchase which is not consumed" (fixed in 2.2.4) - i believe it's not the same that in 2.2.5, cause as far as i remeber, it was only in purchase process, but purchases was confirmed succesfully, so we didn't get new ProcessPurchase every start (Correct me if i am wrong)
    2.2.2 - initialization was finised before fetching all purchases.

    So, maybe 2.2.3 is the best candidate to roll back, what do you think?

    BR, Alexey
     
    Last edited: Jan 11, 2021
  22. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    @Lisan I am providing updates here daily. We are working on the next release, hopefully later this week.
     
  23. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    @Lisan Are you using ConfirmPendingPurchase?
     
  24. Lisan

    Lisan

    Joined:
    Jun 17, 2009
    Posts:
    214
    Yes.
     
  25. Funtyx

    Funtyx

    Joined:
    May 3, 2017
    Posts:
    29
    Good day! Help please, we have already made a bunch of releases and our clients complain beforehand that they cannot restore their purchase using our "Restore" button. Below I attach the code that is activated when you click on the "Restore" button and there are events RestoreSuccess.Invoke (); and RestoreFail.Invoke (); which perform the actions we need to restore the purchase or give an error. When we click on the button, we freeze and do not get into more than one state not in RestoreSuccess.Invoke (); not RestoreFail.Invoke ();
    Please help to restore the non-consumable purchase correctly.

    Code (CSharp):
    1. #if UNITY_PURCHASING || UNITY_UNIFIED_IAP
    2. using UnityEngine.Events;
    3. using UnityEngine.UI;
    4. using System.IO;
    5. using System.Collections.Generic;
    6.  
    7. namespace UnityEngine.Purchasing
    8. {
    9.     public class IapRestore : MonoBehaviour
    10.     {
    11.         public UnityEvent RestoreSuccess;
    12.         public UnityEvent RestoreFail;
    13.  
    14.         public void RestorePurchase()
    15.         {
    16.             //Windows
    17.             if (Application.platform == RuntimePlatform.WSAPlayerX86 ||
    18.                 Application.platform == RuntimePlatform.WSAPlayerX64 ||
    19.                 Application.platform == RuntimePlatform.WSAPlayerARM)
    20.             {
    21.                 CodelessIAPStoreListener.Instance.ExtensionProvider.GetExtension<IMicrosoftExtensions>()
    22.                     .RestoreTransactions();
    23.             }
    24.  
    25.             //Apple
    26.             else if (Application.platform == RuntimePlatform.IPhonePlayer ||
    27.                 Application.platform == RuntimePlatform.OSXPlayer ||
    28.                 Application.platform == RuntimePlatform.tvOS)
    29.             {
    30.                 CodelessIAPStoreListener.Instance.ExtensionProvider.GetExtension<IAppleExtensions>()
    31.                     .RestoreTransactions(OnTransactionsRestored);
    32.             }
    33.  
    34.             //Android Samsung
    35.             else if (Application.platform == RuntimePlatform.Android &&
    36.                 StandardPurchasingModule.Instance().appStore == AppStore.SamsungApps)
    37.             {
    38.                 CodelessIAPStoreListener.Instance.ExtensionProvider.GetExtension<ISamsungAppsExtensions>()
    39.                     .RestoreTransactions(OnTransactionsRestored);
    40.             }
    41.  
    42.             //Android Google Play
    43.             else if (Application.platform == RuntimePlatform.Android &&
    44.                             StandardPurchasingModule.Instance().appStore == AppStore.GooglePlay)
    45.             {
    46.                 CodelessIAPStoreListener.Instance.ExtensionProvider.GetExtension<IGooglePlayStoreExtensions>()
    47.                     .RestoreTransactions(OnTransactionsRestored);
    48.             }
    49.  
    50.             else
    51.             {
    52.                 Debug.LogWarning(Application.platform.ToString() + " is not a supported platform for the Codeless IAP restore button");
    53.             }
    54.         }
    55.  
    56.         void OnTransactionsRestored(bool success)
    57.         {
    58.             if (success)
    59.             {
    60.                 if (CodelessIAPStoreListener.Instance.StoreController != null
    61.                  && CodelessIAPStoreListener.Instance.StoreController.products.WithID("com.companyname.gmae.fullversion") != null
    62.                  && CodelessIAPStoreListener.Instance.StoreController.products.WithID("com.companyname.game.fullversion").hasReceipt)
    63.                 {
    64.                     RestoreSuccess.Invoke();
    65.                 }
    66.             }
    67.             else
    68.             {
    69.                 RestoreFail.Invoke();
    70.             }
    71.         }
    72.     }
    73. }
    74. #endif
     
  26. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Did you test this code with a single store first, before coding it all? You are mixing Scripting and Codeless, and you should not do this. You are incorrectly making direct calls into the Codeless listener. By definition, a listener should not be called explicitly, and only handles callbacks. You should not do anything for Google, restore happens automatically. Unfortunately you'll need to start over, consider starting with the Sample IAP Project here https://forum.unity.com/threads/sample-iap-project.529555/ Test Google (Android) restore first, you don't need to add any code. Then iOS, which requires a button click https://docs.unity3d.com/Manual/UnityIAPRestoringTransactions.html
     
  27. Lisan

    Lisan

    Joined:
    Jun 17, 2009
    Posts:
    214
    Actually i don't completely understand what's going on. Here is my whole story again.
    I have a lot of refunds after releasing my game with iAP 2.2.5 to Google Play. All refunds are same, exactly 72 hours after purchase. Users have no way to do this, so it's auto-refunds by Google Play.

    Here is what i found on the subject:
    https://stackoverflow.com/questions/61303150/google-in-app-purchase-are-always-refunded
    They say, that Google Play will refund purchases automatically, if they are not properly acknowledged within 72 hours.

    But not all my purchases are refunded, only about 20-25% of them. This means, that some purchases got succesfully confirmed after purchase, and some didn't.

    I didn't reproduced the whole thing on my device (didn't wait for 3 days). But when i buy something, i have no errors.
    All purchase flow is working correctly. At first the code initialized purchase, then ProcessPurchase is fired. In ProcessPurchase we call server validation, and return PurchaseProcessingResult.Pending. Server validation returns correct result, and then we call _storeController.ConfirmPendingPurchase(product);
    Confirmation brings no errors at this point, purchase finished, and content opened.

    When i launch the game the next time, i have only this in log:
    Code (CSharp):
    1. 021-01-13 00:27:28.418 8278-8320/? I/Unity: Already recorded transaction ofcicjgfpfdbaieajdagmfed.AO-J1OyVvkjooRjEvS_vs2gjlyHN-M4HEHpyZUC3KSg0tJU8mNpwe3mtr4tOnKaFBCpV-UiLH8iJv9CfhYWMX5bSrHhdHj6Z9-R_RRhV0XYa_pRiu36n8Ns
    2.     UnityEngine.Purchasing.PurchasingManager:ProcessPurchaseIfNew(Product)
    3.     System.Action:Invoke()
    4.     UnityEngine.Purchasing.Extension.UnityUtil:Update(
    But ProcessPurchase is not called, whitch means purchase was confirmed succesfully.

    Next, i remove the game from device and install it again. And that's there error begin to appear.
    On the first start restoration is launched, and we get ProcessPurchase fired. It again sends data to server validation and got "OK" result, but when _storeController.ConfirmPendingPurchase(product) called after it, we get an error:
    "Unable to confirm purchase; Product has missing or empty transactionID"
    And after it we have it on every app launch. This code was working correctly in the old iAP (1.23.5), but now restoration process somehow reopens transaction and it can't be confirmed anymore.

    But it looks like i miss something, cause i still don't understand where are refunds originated from, If where are no error in purchases itself, only in restoration. But they all are 72 hours from initial purchase, whitch means that transactions got broken upon purchases, not restorations.

    upload_2021-1-13_0-53-48.png


    Jeff, do you have thoughts on this?

    BR. Alexey
     
  28. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    It appears that ConfirmPendingPurchase in 2.2.5 is silently failing. We are working on this for the next IAP release at high priority.
     
  29. Lisan

    Lisan

    Joined:
    Jun 17, 2009
    Posts:
    214
    I decided to switch from server validator lo local CrossPlatformValidator for the time being while waiting for the update, and not using pending transaction. This way it will work without rolling back to the old iAP.
     
    JeffDUnity3D likes this.
  30. gregStagwell

    gregStagwell

    Joined:
    Dec 23, 2020
    Posts:
    2
    @JeffDUnity3D Are there any updates on the issues with IAP?
    We have issues since updating to 2.2.2 with the consumable product confirmation that seems to never happen. Thanks
     
  31. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Yes, please use IAP 2.2.7. This thread is discussing Restore which does not apply to Consumables
     
Thread Status:
Not open for further replies.