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. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Yes, there are some changes in this area.
     
  2. GerardInc

    GerardInc

    Joined:
    Jan 25, 2017
    Posts:
    15
    @JeffDUnity3D do consider making this plugin open source. I'm certainly willing to dedicate time into patching this issue for the greater good; especially so as we've previously managed to stable reproduce some of the issues in this thread in our office. Our release cycles are also a lot more nimble - and we are in direct contact with customers reporting this issue.
     
    DanWeston likes this.
  3. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Unfortunately we are bound by legal constraints currently, we have discussed this.
     
  4. MigrantP

    MigrantP

    Joined:
    Jun 24, 2013
    Posts:
    116
    @JeffDUnity3D Thanks, we sent an update to the players having the problem before, and it seems to be fixed. We've shipped out the update to the public now, fingers crossed =)
     
    Sailendu likes this.
  5. Sailendu

    Sailendu

    Joined:
    Jul 23, 2009
    Posts:
    250
    Which version of the IAP plugin you're using? Please tell me, I really need the fix for this.
     
  6. MigrantP

    MigrantP

    Joined:
    Jun 24, 2013
    Posts:
    116
    Version 1.23.4. The issue it resolved for us was the one where non-consumable purchases would get consumed if you used the app on multiple devices.
     
    GiyomuGames likes this.
  7. Sailendu

    Sailendu

    Joined:
    Jul 23, 2009
    Posts:
    250
    Thanks for responding. So, this does not solve the restore bug? Are those two issues not linked with one another? I am confused.
     
  8. Lisan

    Lisan

    Joined:
    Jun 17, 2009
    Posts:
    214
    Is it the same issue, as purchase restoring on the other device?
     
    Sailendu likes this.
  9. MigrantP

    MigrantP

    Joined:
    Jun 24, 2013
    Posts:
    116
    Yes, you could not restore the purchase (on the second device or on the first device), because it had been marked as consumed. The behaviour of the bug is described in the original post on this thread; the cause (consumeAsync being called) was discovered by a poster later.
     
  10. Sailendu

    Sailendu

    Joined:
    Jul 23, 2009
    Posts:
    250
    Thanks a lot for letting me know. So finally the issue we have been facing for more than a year is now fixed in 1.23.4, this is great.
     
  11. MigrantP

    MigrantP

    Joined:
    Jun 24, 2013
    Posts:
    116
    I agree! It doesn't help directly with people who already had the problem, but that can be dealt with by sending them promo codes for the items they lost.
     
  12. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    We've been tracking two issues. One is that Consume was being incorrectly called, and the other was that the Google API wasn't syncing purchases in a timely manner. What issue were you seeing? Was Restore working previously on the same device, just not on a second device?
     
  13. Sailendu

    Sailendu

    Joined:
    Jul 23, 2009
    Posts:
    250
    In my case, restore was working on the same device, but not on a second device, also if I try to make the purchase again on the 2nd device, I received error about "Duplicate purchase", and the IAP was marked as non-consumable in the code.
     
  14. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Got it! It looks like they were indeed related. I was able to just test and confirm with IAP 1.23.5. A subscription purchase on one Android device properly triggers ProcessPurchase upon IAP initialization on the second device.
     
    Last edited: Aug 25, 2020
  15. Deleted User

    Deleted User

    Guest

    Hi @JeffDUnity3D, I see the new release of IAP 2.0.0, but from looking at CHANGELOG.md notes, I don't see anything referencing a fix for the Google Play restore issue. Can you please confirm whether this fix made it into this release? Also, please clarify what fix we can expect for updating to this new Lib

    Thanks
     
  16. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    From our testing, it looks like it was already fixed when we tested with 1.23.5, please confirm. It does not look to be related to the Google billing library after all.
     
  17. karyll

    karyll

    Joined:
    Apr 4, 2017
    Posts:
    50
    I upraded to 2.0.0 and here is what happens in my scenario: i have one-time items for sale (player skins), (A, B, C) and 2 devices (Phone and Tablet). I buy A on P and B on T. The expectation would be that when I restart the game, both A and B are available on both P and T. But they are not, each is only available on they device they were bought on. What "works" is that if buy A on T then i get the "item already owned" message and the restore is done, and both A and B are on T.

    Does anyone have a different better experience than mine?
     
  18. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Your expectation is correct. Please share your device logs. So you have confirmed that ProcessPurchase is not called on app launch? Please show your code and Debug.Log statements that will show in the logs. Are you using Codeless or Scripted IAP? Codeless would require a Listener to catch the ProcessPurchase calls during initialization. Also, what happens when you reinstall the app each time? Does only the single local purchase restore?
     
  19. karyll

    karyll

    Joined:
    Apr 4, 2017
    Posts:
    50
    @JeffDUnity3D , one more question: assuming everything works correct, is there a time delay between synchronization of the items? So for example, I buy item A on Phone , should Tablet pick it up immediately or there is a period (minutes, hours?) that google spends doing .. stuff.. before Tablet sees the item A as purchased?
     
  20. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    [
    That's certainly possible, especially for test purchases.
     
  21. Deleted User

    Deleted User

    Guest

    @JeffDUnity3D we integrated v2.0.0 (after v1.23.5) and got some results, but not a "full fix" end result. Here is the flow, as described to me by the dev team:

    It is probably easiest to try and show the behaviour with some user scenarios. I have added a 'theory' into these - I could be way off with this as they are only educated guesses based on our knowledge of the IAP Lib functions.

    User Scenario 1: This is the one that makes the issue look 'fixed'.
    Setup: Install APP on Device A. Device B has never had APP installed - this can either be a known device or a device that is factory reset.
    1) Device A: purchase an IAP, which allows access to an activity in the APP. This activity unlocks correctly.
    2) Device B: install APP and open it.
    Result: The IAP activity is unlocked correctly.
    Theory: As the device has been factory reset, the Play Store Data cache on the device has nothing (Cached) for APP. When the billing library asks what IAP are owned, the Google libraries have to go further back into the system to retrieve any purchase data for APP. This is what enables it to pull the purchases correctly. This seems to be the same as deleting the Play Store Data cache via Device Settings.

    User Scenario 2: This is the bit that is NOT 'fixed' and is probably a lot more relevant to our users.
    Setup: Install APP on Device A and Device B. Make sure that both versions have been opened and closed before starting this flow. This replicates the scenario where a user has played the APP on 2 devices before deciding to purchase or has a purchase already on 2 devices and looks to make another.
    1) Device A: purchase an IAP, which allows access to an activity in the APP. The activity unlocks correctly.
    2) Device B: open the APP. The activity is still locked. Logs shows that this IAP is NOT owned.
    3) Device B: Do explicit Restore purchases call. The activity is still locked.
    Result: The IAP purchased on Device A will not restore on Device B.
    Theory: Opening the APP on Device B in the setup phase ensures that the Play Store Data cache has been populated with APP data - i.e. no purchases. Once that is done, we are back to the original issue of Unity and the Play Store Data cache.
    4) Device B: purchase the IAP, which allows access to an activity in the APP.
    Result: the user gets a message saying they already own this item. The item is then restored and the activity is unlocked.
    4 Alternate) Device B: delete the Play Store Data cache. Reboot the app and the activity is unlocked. I have seen this 'trick' take a couple of deletes of the cache, but normally is first go.

    User Scenario 3: This is a 3 device setup that was arrived at after testing multiple other scenarios.
    Setup: Device A: An IAP(s) activity 1 and activity 2 is unlocked. Device B: IAP activity 1 unlocked. Device C: nothing unlocked. These all have the same user account. Device A was used to make all purchases in this scenario.
    1) Leave the devices overnight.
    Result: In the morning all 3 devices had IAP activity 1 and activity 2 unlocked correctly.
    Theory: This seems to go back to the Google information we received about the Play Store Data cache needing up to 24 hours to refresh from the store. The only thing that changed was time. Nothing was cleared, nothing else was even opened. I opened the apps in the morning and everything was correct. Sometimes the refresh is relatively quick (a few hours), or longer (over night). The user expectation is that it would appear instantly (the purchase shows in your Play Store account on Device B instantly), so when it doesn't it is an issue.

    I hope this illustrate the flow we are seeing with v2.0.0 of the IAP. We are using the Scripted IAP for integration, and following the examples in the IAPDemo.cs as template.

    If you need further data let me know and I see if I can help resolve this problem.
     
    Last edited by a moderator: Sep 2, 2020
  22. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    @dioniguerra Thanks for the great report! Your theories look quite reasonable, we will look into this.
     
  23. karyll

    karyll

    Joined:
    Apr 4, 2017
    Posts:
    50
    The testing I have done since yesterday seems to fall in the Scenario 3 @dioniguerra described. Items do restore between devices, but at random times, regardless of the fact that they are test or normal purchases. I have had one case where I bought item A on Tablet and item B on Phone and they both were eventually available on both devices, but at different times during the day.
     
  24. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Are you using the aggressivelyRecoverLostPurchases flag? https://forum.unity.com/threads/uni...0-is-now-available.415517/page-2#post-6205023 Although these are not lost purchases per se, we are investigating at this point
     
  25. karyll

    karyll

    Joined:
    Apr 4, 2017
    Posts:
    50
    @JeffDUnity3D to be honest, I do not know, this is why I was unable to answer your previous technical questions, and can only do end-user testing. I am using an Asset Store plugin to manage the integration between my app and the Unity IAP called Easy IAP and all the code is there outside of my expertise.

    I have read about that flag in the changelog but for me (as a not-so-experienced-developer-with-play-store-integration) the terminology is too high level and I understood nothing :) It is not clear to me if I set the flag, or if the flag is already set somewhere, it is unclear what value should I set for things to work as I want them to, etc..
     
  26. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    You would need to contact Easy IAP, this discussion is regarding scripting with Unity IAP and the API's that we expose. They would need to implement these features, and also stay up to date with the latest IAP releases.
     
  27. karyll

    karyll

    Joined:
    Apr 4, 2017
    Posts:
    50
    From the logs, the flag you mention is running with "false". Are you suggesting that if it is set to "true" then restore will happen faster? Or what's the connection between the flag and the Scenario 3 (delayed restore on devices)? upload_2020-9-2_21-24-21.png
     
  28. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Undetermined, we are fact finding at this point.
     
    karyll likes this.
  29. justtime

    justtime

    Joined:
    Oct 6, 2013
    Posts:
    422
    JeffDUnity3D, hi there!
    Could you describe "aggressivelyRecoverLostPurchases" flag behavior? How it works and what should i do with this "Strongly recommend deduplicating transactions across app reinstallations because this relies upon the on-device, deletable TransactionLog database"?
     
  30. nicholasr

    nicholasr

    Unity Technologies

    Joined:
    Aug 15, 2015
    Posts:
    183
    @justtime Thanks for the curiosity about this advanced feature and the opportunity to explain it further - it is a complex feature which can help reduce the amount of user-actions that are required to reward a player with their purchase, if the purchase was interrupted (e.g. network). It requires a backend server to perform complex de-duplication, in order to correctly reward users a single-time for a single-purchase.

    *EDIT* When this helps: a network interruption, or accidental cancellation / app crash while the Google "Purchasing ..." progress-spinner is spinning. A OnPurchaseFailed will normally be called...and this feature can make a ProcessPurchase to be called.

    In detail:

    When a player experiences a network disruption during a purchase on Google Play, the Google Backend might become out of sync with the client. The phone might think "The purchase failed" due to the Google Billing software stack receiving only an error notification from the Google Backend about this purchase attempt. And critically, the Google Backend might simultaneously think "The purchase has started and is looking good to me ...", which is a conflicting view with the phone. (The Backend will put that Product Identifier into a "purchase is in-progress" state.)

    One workaround is Google Billing offers a partially-deprecated "getPurchaseHistory" API to query the true state of a purchase. "aggressivelyRecoverLostPurchases" uses this API. The feature triggers a network request.

    Now to your question, the "pro" of the Unity IAP feature: Enabling "aggressivelyRecoverLostPurchases" causes IStoreListener.ProcessPurchase to be called more quickly and potentially multiple times, for a single interrupted purchase (with it off, a player must either restart their application 1 to 2 times before they are rewarded for the purchase or purchase it a second time and experience a "duplicate" error message but also be rewarded for the purchase). Unity IAP detects the purchase-start and the purchase-interrupt, and triggers a recovery process which queries the Google history API.

    The "con" of the feature: The Google history API fetches partial state information about the purchase, sharing the "purchaseToken", however omitting the "orderId" which we historically have used as the basis for Transaction ID. Therefore an "aggressivelyRecoverLostPurchases" game may receive purchase notification on ProcessPurchase first with "TransactionID == <purchaseToken>" and second, either soon or after app-restart, with "TransactionID == <orderId>". The player has a possibility here of erroneously be rewarded twice for a single purchase. This is incorrect behavior for the player. Next, take all that information together, and in order to correctly, singly reward the player for a single purchase, "aggressivelyRecoverLostPurchases = true" will require the developer to de-duplicate the ProcessPurchase responses down to a single purchase. The developer can use a (backend game-server + database) Google Developer REST API to query Google for the full Purchase Response and the "orderId" given the "purchaseToken", or given the "orderId", enabling de-duplication, that is a recommended way to use this advanced feature.

    *EDIT 2* The Google REST "purchases.products.get" API to me looks like it provides orderId for purchases given only purchase tokens.

    We are looking to migrate to "purchaseToken" exclusively in our next two minor/major releases of Unity IAP to avoid this problem, and for other reasons. We might retire the "aggressivelyRecoverLostPurchases" feature, too, because the base Google "getPurchaseHistory" API is deprecated.

    And for developer who do not enable "aggressivelyRecoverLostPurchases" the players who suffer purchase interruption situations can simply restart their app twice, or attempt to re-purchase the same product, to be rewarded for their purchase.

    Is this answer taking your question in the wrong direction?
     
    Last edited: Oct 15, 2020
    justtime and DarekRusin like this.
  31. justtime

    justtime

    Joined:
    Oct 6, 2013
    Posts:
    422
    @nicholasr Thanks a lot!
    Could you also describe this part from 2.1.0?
    "IGooglePlayConfiguration.UsePurchaseTokenForTransactionId API for overriding TransactionID on Google Play"
    I mean use cases for overriding TransactionID.
     
  32. justtime

    justtime

    Joined:
    Oct 6, 2013
    Posts:
    422
    HI! I'm using the latest iap 2.1.1. People continue to send me messages about lost transactions. Reinstall and clear cache doesn't work.

    Also, 2nd issue, when transactions are not available on another device is still here.
     
  33. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    For clarity, can you elaborate what you mean by "lost transactions"? What are the customers complaining about? And describe your 2nd issue? I'm not clear what you mean by "Not available on another device is still here". thx
     
  34. justtime

    justtime

    Joined:
    Oct 6, 2013
    Posts:
    422
    1)User buy items, delete app, install it again, items/transactions can't be found
    2)User buy items, install app on another device, tablet for example, and he can't get access to these items on this another device
     
  35. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    These are non-consumable or subscription products?
     
  36. justtime

    justtime

    Joined:
    Oct 6, 2013
    Posts:
    422
    non-consumable
     
  37. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Yes, we are working on this, and hope to have an updated release out soon to address this behavior. Hopefully in a few weeks.
     
    justtime likes this.
  38. AdamVlcek

    AdamVlcek

    Joined:
    Aug 8, 2013
    Posts:
    4
    Hi! Any update? How many few weeks more? ;)
     
  39. Funtyx

    Funtyx

    Joined:
    May 3, 2017
    Posts:
    29
    Tell me how to restore a purchase on an android? After uninstalling the application and reinstalling it, I have certain data in the PlayerPrefs that will allow me to unlock the levels. In my game there is one non-consumable purchase that unlocks all levels. I put a script in the first scene in order to initialize the PlayerPrefs data but nothing works.

    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. namespace UnityEngine.Purchasing
    7. {
    8.     public class IapRestore : MonoBehaviour
    9.     {
    10.         public UnityEvent RestoreSuccess;
    11.         public UnityEvent RestoreFail;
    12.         public void RestorePurchase()
    13.         {
    14.             if (Application.platform == RuntimePlatform.WSAPlayerX86 ||
    15.                 Application.platform == RuntimePlatform.WSAPlayerX64 ||
    16.                 Application.platform == RuntimePlatform.WSAPlayerARM)
    17.             {
    18.                 CodelessIAPStoreListener.Instance.ExtensionProvider.GetExtension<IMicrosoftExtensions>()
    19.                     .RestoreTransactions();
    20.             }
    21.             else if (Application.platform == RuntimePlatform.IPhonePlayer ||
    22.                 Application.platform == RuntimePlatform.OSXPlayer ||
    23.                 Application.platform == RuntimePlatform.tvOS)
    24.             {
    25.                 CodelessIAPStoreListener.Instance.ExtensionProvider.GetExtension<IAppleExtensions>()
    26.                     .RestoreTransactions(OnTransactionsRestored);
    27.             }
    28.             else if (Application.platform == RuntimePlatform.Android &&
    29.                 StandardPurchasingModule.Instance().appStore == AppStore.SamsungApps)
    30.             {
    31.                 CodelessIAPStoreListener.Instance.ExtensionProvider.GetExtension<ISamsungAppsExtensions>()
    32.                     .RestoreTransactions(OnTransactionsRestored);
    33.             }
    34.             else if(Application.platform == RuntimePlatform.Android)
    35.             {
    36.                 if (CodelessIAPStoreListener.Instance.StoreController != null
    37.                     && CodelessIAPStoreListener.Instance.StoreController.products.WithID("com.company.fullversion") != null
    38.                     && CodelessIAPStoreListener.Instance.StoreController.products.WithID("com.company.fullversion").hasReceipt)
    39.                 {
    40.                     RestoreSuccess.Invoke();
    41.                 }
    42.                 else
    43.                 {
    44.                     RestoreFail.Invoke();
    45.                 }
    46.                 //if (CodelessIAPStoreListener.Instance.StoreController?.products.WithID("com.company.fullversion")?.hasReceipt)
    47.                 //{
    48.                 //    RestoreSuccess.Invoke();
    49.                 //}
    50.                 //else
    51.                 //{
    52.                 //    RestoreFail.Invoke();
    53.                 //}
    54.             }
    55.             else
    56.             {
    57.                 Debug.LogWarning(Application.platform.ToString() + " is not a supported platform for the Codeless IAP restore button");
    58.             }
    59.         }
    60.         void OnTransactionsRestored(bool success_apple)
    61.         {
    62.             if (success_apple)
    63.             {
    64.                 RestoreSuccess.Invoke();
    65.             }
    66.             else
    67.             {
    68.                 RestoreFail.Invoke();
    69.             }
    70.         }
    71.     }
    72. }
    73. #endif
     
  40. Tankzo

    Tankzo

    Joined:
    Jul 16, 2019
    Posts:
    16

    @Artixpro,
    This is NOT a good solution but it seems to be a work-around.
    Change public void RestorePurchase() to a coroutine:

    public IEnumerator RestorePurchase()
    {
    yield return new WaitForSeconds(0.5f);
    ....

    It looks like the UnityPurchasing.Initialize() is "completing" and returning OnInitialized(IStoreController controller, IExtensionProvider extensions) BEFORE it pulls any receipts for non-consumables. So any code you run from the OnInitialized() function will run BEFORE your receipts are pulled.

    My testing shows that OnInitialized() competes between 0.02 secs to 0.15 secs before the receipts come in (averages 0.05 seconds. I've never seen it go above 0.20 seconds.

    This is a horrible workaround because it is based on a fixed time but it has allowed my apps to restore non-consumable purchases on Androids.

    Try the coroutine fix and see if it works.
     
    justtime likes this.
  41. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    You would not want to add any code to do a Restore on Android, it's done automatically. If the user doesn't already have the product during IAP initialization which triggers ProcessPurchase, then there is possibly an error in your code (or you are seeing the issue described in this thread)
     
  42. Skolwind

    Skolwind

    Joined:
    Aug 28, 2014
    Posts:
    8
    @JeffDUnity3D, were you talking about Unity IAP 2.2.2 update? Does it solve the issues (mentioned by justtime)?
     
  43. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Please describe your issue. Are you attempting to restore across devices?
     
  44. Skolwind

    Skolwind

    Joined:
    Aug 28, 2014
    Posts:
    8
    I have exact same issues.
     
  45. Lisan

    Lisan

    Joined:
    Jun 17, 2009
    Posts:
    214
    Hello!
    We just got update 2.2.3, but there is nothing about it in release notes.
    What is 2.2.3 exactly?

    upload_2020-12-2_19-24-35.png
     

    Attached Files:

  46. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Stay tuned for the release notes. Regardless if you see your issue in the release notes, we would always ask you to test first with the latest release. I would need to do the same thing here, and appreciate your help.
     
  47. Lisan

    Lisan

    Joined:
    Jun 17, 2009
    Posts:
    214
    We are testing it.
    For now for some reason i got ProcessPurchase two times instead of one.
     
  48. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Yes, separate and known issue
     
  49. Lisan

    Lisan

    Joined:
    Jun 17, 2009
    Posts:
    214
    Is it documented somewhere? Shouldn't be some kind of "known issues" in release notes, as it is for Unity builds? I wasn't prepared for this.
     
  50. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Typically a company doesn't document bugs that are short lived. We wouldn't release a build with known issues, we are working on this.
     
Thread Status:
Not open for further replies.