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?
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.
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.
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?
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://discussions.unity.com/t/740418
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.
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.
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.
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?
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.
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://discussions.unity.com/t/700293 . You might want to test with it also, to confirm.
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.
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
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.
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?