Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

FetchAdditionalProducts not updating products

Discussion in 'Unity IAP' started by pep_dj, Jul 30, 2019.

  1. pep_dj

    pep_dj

    Joined:
    Nov 7, 2014
    Posts:
    179
    I am running Unity IAP v1.22.0. I need to refresh store controller products in order to detect refunds. I am calling FetchAdditionalProducts and getting Inventory refresh successful. (response: 0:OK) response.

    In the successCallback I'm reading the hasReceipt value of the products in storeController (products.all array), but it's true although the purchase has been refunded. The hasReceipt value only turns false after I restart the app, so Initialize is called again.

    So, why products are not refreshed after calling FetchAdditionalProducts (passing my product id's)? Should I do anything in order to get them refreshed?
     
  2. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    I've heard it can take from a few hours to a few days for Google to update the receipts. I suspect it's so multiple refunds can't be attempted in a row.
     
  3. pep_dj

    pep_dj

    Joined:
    Nov 7, 2014
    Posts:
    179
    After I refund the IAP in the Google developer console, I restart Google Play Store in my device (simply by running adb shell pm clear com.android.vending) and receipt is updated immediately. And I have 2 proofs of it:

    1 - When I call FetchAdditionalProducts right after purchasing the product, I can see in the log: I/UnityIAP: Sku is owned: myProductId. But if I call FetchAdditionalProducts after refunding the purchase and restarting Play Store, such log entry is not shown anymore. So here Google is telling us that we don't own the "myProductId" product anymore. But this change is not reflected in Untiy.

    2 - The definitive proof is that after I refund the purchase and restart Play Store, if I restart my game, then the receipt of the product is NULL, and hasReceipt is false. So here, again, Google is telling us that we don't own the product. So the problem is not on the Google side.

    So, how can I know that the user no longer owns an item without restarting my game? I've tried using FetchAdditionalProducts, and re-initializing UnityPurchasing, but none of them worked.
     
  4. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    You say "such log entry is not shown anymore", are you referring to the device logs? How is restarting your game any different from re-initializing IAP in your code?
     
  5. pep_dj

    pep_dj

    Joined:
    Nov 7, 2014
    Posts:
    179
    Yes, device log (LogCat).

    I don't know how is restarting the game any different from re-initializing IAP in my code. I don't know what Unity IAP is doing under the hood. Also, I have to restart my game by killing it, because calling Application.Quit leads us to a different problem: https://forum.unity.com/threads/and...ont-initialize-after-application-quit.665497/

    But I would like to focus on the main problem in this thread. I would like to be able to query for owned products without restarting the game.
     
  6. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    You just need to reinitialize IAP, is my point. You don't need to restart your game, unless your code is doing something else. Compare your device logs when you do vs when you restart the game, placing Debug.Log calls in all the IAP callbacks to confirm execution. Correct, don't use Application.Quit.
     
  7. pep_dj

    pep_dj

    Joined:
    Nov 7, 2014
    Posts:
    179
    Thank you for your answer. But is not working by reinitializing. The receipt field of the product is filled with the last receipt.
     
  8. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Have you confirmed that OnInitialized is called? Did you null out your controller, etc? I had suggested to place various Debug.Log statements throughout your code, so you can see what is being called when you restart your game, vs inline initialization. I suspect you still have your previous controller, with the previous receipts.
     
  9. pep_dj

    pep_dj

    Joined:
    Nov 7, 2014
    Posts:
    179
    Hello.

    I wish you were right. But unfortunately OnInitialized is called, and storeController is re-asigned, so previous controller is lost, and I'm checking receipts in the new storeController. Maybe something is cached and it isn't cleared until the game is restarted?
     
  10. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    That is possible, thank you for checking. I will test here too.
     
  11. pep_dj

    pep_dj

    Joined:
    Nov 7, 2014
    Posts:
    179
    Thank you. I'll be waiting for your response.
     
  12. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    So you know, it will likely be a couple of weeks to properly set expectations. We have other customers asking about the refund process, so maybe sooner.
     
  13. pep_dj

    pep_dj

    Joined:
    Nov 7, 2014
    Posts:
    179
    Thank you. I hope we can have a solution soon. Let me know if I can help in any way.
     
  14. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Sure! Can you modify the Sample project here to enable IAP re-initialization, I could use it to test, I already have it published on Google and Apple. Delete the /Library folder (to save space) and attach to this thread. The sample project is here https://forum.unity.com/threads/sample-iap-project.529555/ . You might want to test with it also, to confirm.
     
  15. pep_dj

    pep_dj

    Joined:
    Nov 7, 2014
    Posts:
    179
    Now I'm out of the office, but I'll do it tomorrow
     
  16. pep_dj

    pep_dj

    Joined:
    Nov 7, 2014
    Posts:
    179
    Here I'm attached the modified project. Now there is a button to re-initialize, but I don't know how to process a refund. Can I do it?
     

    Attached Files:

  17. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    In OnInitialized, go through each of the product receipts:

    foreach (Product item in controller.products.all)

    and look in item.receipt but I'm not sure which field. This would be a perfect case for Visual Studio debugging, you could view the entire item object all at once. Otherwise you'll need to Debug.Log each field.
     
  18. pep_dj

    pep_dj

    Joined:
    Nov 7, 2014
    Posts:
    179
    Ok, I modified it as you said (project attached here). Now, in OnInitialized there is a call to Debug.Log to show the hasReceipt field of all products. If you buy an item, and then click ReInitialize, you can see that hasReceipt is still false, so such field is not updated :(
     

    Attached Files:

  19. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    So what is the result of the same debugging when you restart the app? And what do you mean, "still false", I would expect hasReceipt to be true after the original purchase? You said previously "The definitive proof is that after I refund the purchase and restart Play Store, if I restart my game, then the receipt of the product is NULL, and hasReceipt is false." That is the same thing that you just observed, that hasReceipt is false. If hasReceipt is false, you don't give the product to the user, in your code.
     
  20. pep_dj

    pep_dj

    Joined:
    Nov 7, 2014
    Posts:
    179
    I mean that hasReceipt field is not updated after make a purchase. If I make a purchase, and I re-initialize it, hasReceipt should be true if it gets updated.

    Yes, this is the inverse case: when the product is refunded. In this case hasReceipt should be false, and it only happens when I restart the app, but not when I re-initialize.

    To summarize: we need a way to update the hasReceipt field without restarting the app. Is it possible?
     
  21. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    You mention "I mean that hasReceipt field is not updated after make a purchase. If I make a purchase, and I re-initialize it, hasReceipt should be true if it gets updated." That is correct, sorry if I'm not following. So it DOES get set to true, but only after you restart your app? If so and is likely your point, this would confirm your claim, and something likely would be amiss at our end.
     
  22. pep_dj

    pep_dj

    Joined:
    Nov 7, 2014
    Posts:
    179
    When I restart the app hasReceipt gets updated
     
  23. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Likely as you've saying all along, sorry for the confusion. I'll be testing here too.
     
  24. pep_dj

    pep_dj

    Joined:
    Nov 7, 2014
    Posts:
    179
    Thank you
     
  25. pep_dj

    pep_dj

    Joined:
    Nov 7, 2014
    Posts:
    179
    Hello... any news regarding this topic?
     
    awsapps likes this.
  26. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    No updates. I would suggest that we revisit this topic after we release the next version, hopefully next week. I suspect the behavior here will be different.
     
  27. pep_dj

    pep_dj

    Joined:
    Nov 7, 2014
    Posts:
    179
    I need to update my game before 4 days, or it will be removed from Play Pass, because is not compliant with the program policy:

    IAPs are remaining available even after a subscription is no longer active. Ensure that you are periodically (i.e. on launch) using getPurchases() to get an updated list of granted IAPs, restricting in-app content when detecting a reduction in actively granted purchases.

    I can't believe there is not yet a method to refresh purchases! So, will be my game removed??
     
  28. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    We have not found a reliable Google API call to obtain a refreshed list of purchases. I'm not sure why your game would be removed because of this? You can simply check on app launch, as you've stated, to get the subscription status. You are not required to do this during game play.
     
  29. pep_dj

    pep_dj

    Joined:
    Nov 7, 2014
    Posts:
    179
    I've been using a reliable Google API call to obtain a refreshed list of purchases since I started using it several years ago. The IabHelper.java example from android has a method called queryInventoryAsync that is calling the method
    getPurchases of the class IInAppBillingService. It works like a charm.

    Google says that purchased items should be checked when the app is resumed, not only when the app is launched. Not doing so is against their policy.

    Please, are you sure there is not any way to query purchases?
     
    awsapps likes this.
  30. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Correct. And you've already coded a work around? ("I've been using..") I'm not following. I trust you are checking subscription status at the beginning of the game which appears sufficient to Google "Ensure that you are periodically (i.e. on launch)..."
     
  31. pep_dj

    pep_dj

    Joined:
    Nov 7, 2014
    Posts:
    179
    I've been using it in native Android apps, not in Unity games.

    So... there is no way to do it in Unity, right? In that case I will try to tell them that the game is already checking it at launch, and I'll cross my fingers...
     
  32. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Sounds good. And you've tested your Unity implementation, and it properly removes the expired/cancelled subscription product at app launch? Their reply seems to imply that it does not.
     
  33. pep_dj

    pep_dj

    Joined:
    Nov 7, 2014
    Posts:
    179
    Yes, I've tested it and it works. I'm removing the items that have hasReceipt == false.
     
  34. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    So the message from Google is incorrect, they explicitly stated that testing at the beginning of the game is sufficient. And by testing, I mean that as the user, you no longer see the product listed in your Google purchases outside the game, on the dashboard, nor in the game. Same for you as the developer, if you've performed a refund for example, and checked Revoke as the option on your dashboard. And a 5 minute subscription in test, you no longer see the product in your game after restarting 10 minutes later after a purchase.