[bug] Unity IAP 2.2.5 cannot ConfirmPendingPurchase

reproduce step:

  1. Purchase a consumable item A.

  2. In “ProcessPurchase” callback, return “PurchaseProcessingResult.Pending”. And request server to validate.

  3. Before server return, kill the game process, then reopen it.

  4. When IAP is initializing, I received the “ProcessPurchase” callback (previous version cannot receive, version 2.2.5 has resolved the bug)。In the callback, return “PurchaseProcessingResult.Pending”, and request server to validate again.

  5. After server return, I called “ConfirmPendingPurchase” to finish the transaction.

  6. Try to purchase the same item A, I got PurchaseFailureReason.DuplicateTransaction error.

Thank you.

1 Like

I have the same problem. In my case, I’m using the UDP store, and the message that I get on initialization of Unity IAP at step 4 is:

UnityEngine.Purchasing.PurchasingManager: ProcessPurchaseIfNew(Product)
UnityEngine.Purchasing.PurchasingManager:OnProductsRetrieved(List`1)
UnityEngine.Purchasing.JSONStore:OnProductsRetrieved(String)
System.Action`2:Invoke(T1, T2)
UnityEngine.Purchasing.UDPBindings:OnInventoryQueried(Boolean, Object)
System.Action`2:Invoke(T1, T2)
UnityEngine.UDP.UdpIapBridge:OnQueryInventory(Inventory)
System.Action:Invoke()
UnityEngine.UDP.MainThreadDispatcher:Update()

If I try to purchase the same consumable item (step 6), I get a message Purchased Finished. ResultCode: -300, message: invalid operation: iap pack1 needs to be consumed first

I will look into this.

Something about returning PurchaseProcessingResult.Pending for a transaction on app restart (a transaction that didn’t complete correctly during a previous play) causes issues for me. Once the asynchronous call goes out to our game server like a normal transaction, I return Pending, but when my server call returns, the PurchaseEventArgs product is reset and my transaction id is blank. So I receive a “Unable to confirm purchase; Product has missing or empty transactionID” instead of completing the transaction successfully. Normal purchases work fine, just re-attempted transactions on app restart see this issue.

We are working on this issue at high priority, and should be included in the next release. It appears that ConfirmPendingPurchase in IAP 2.2.5 may be silently failing. The current ETA is next week.

@JeffDUnity3D
Hi, I’m trying to upgrade UnityPurchasing to 2.2.5 from 1.23.1.

In my case, I noticed that automatic restoration of non-consumable products which have been successfully purchased may be failed in Android.
Is it possible to have relation to failure of ConfirmPendingPurchase silently?

As far as I know, IStoreListener.OnInitialized is called after IStoreListener.ProcessPurchase. In Changelog at 2.2.3, it says as bellow;

GooglePlay - IStoreListener.OnInitialized is now called after all purchases have been fetched from the store.

In old version, IStoreListener.OnInitialized is called before IStoreListener.ProcessPurchase, and automatic restoration is succeeded.

IStoreListener.ConfirmPendingPurchase is required a IStoreController instance, so if IStoreListener.OnInitialized is called after IStoreListener.ProcessPurchase, it is not possible to call IStoreListener.ConfirmPendingPurchase during IStoreListener.ProcessPurchase which may be automatically called from the system.

I have so far called IStoreListener.ConfirmPendingPurchase during IStoreListener.ProcessPurchase for ensuring to process pending transactions before processing a new item. Is this usage something wrong?
I tried to call IStoreListener.ConfirmPendingPurchase after IStoreListener.OnInitialized, but nothing happened. Probably, it is main issue discussed in this thread.

I’d like to confirm just in case although I think IStoreListener.ConfirmPendingPurchase is not be related automatic restoration but it should be used for pending transactions.

Further, I noticed IPlayGoogleStoreExtensions.RestoreTransaction is supported now, then I tried to call it manually, but nothing happened unfortunately.

@ You initialize IAP at the beginning of your game, then perform your purchases. You should not initialize again. Please see the Sample IAP Project here as an example. You should not be using ConfirmPendingPurchase unless you are doing server-side receipt validation Sample IAP Project

@JeffDUnity3D
Sorry, I found out it is my system’s bug.

I have been saved purchasing information using PlayerPrefs so far.
It is only work correctly after IStoreListener.OnInitialized is called because the instance of PurchaseEventArgs via IStoreListener.ProcessPurchasing is compared to the result of IStoreController.products.WithID(string).
The IStoreController reference is not set until IStoreListener.OnInitialized is called, so comparison is failed.
In result, saving purchasing information using PlayerPrefs is failed and it just looks like not be restored; nevertheless automatic restoration is succeeded actually.

Anyway, thank you for quick reply and useful information!

1 Like

@JeffDUnity3D Hello, we are currently facing the same problem but on ios. ProcessPurchase is launched multiple times instantly for the same product. We also had the problem on android (with UnityPurchasing 2.0.0) but after upgrading to 2.2.5 it got fixed. But ios is not.
Xcode 12, Unity 2019.4.10f1

It is something about this:

[2.2.4] - 2020-12-03

Fixed

  • GooglePlay - IStoreListener.ProcessPurchase called more than once for any purchase which is not consumed, i.e. when ProcessPurchaseResult.Pending is returned, by fixing a race-condition.

The issue we are addressing is not “multiple times instantly”, that sounds like it might be an issue in your code. Please share your purchasing script.

@JeffDUnity3D We have this log in our IStoreListener:

        public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs e)
        {
            var productInfo = string.Format("{{ id: {0}, receipt: {1}, transactionID: {2} }}",
                e.purchasedProduct.definition.id, e.purchasedProduct.receipt, e.purchasedProduct.transactionID);
            GPLog.Log(LogType.Purchasing, $"{nameof(ProcessPurchase)}() {productInfo}");

And here is the result. Transaction 100000754661848 is called multiple times. We return pending during ProcessPurchase, verify purchase on our server and call ConfirmPendingPurchase. As you may see confirm is called after all these ProcessPurchase are already triggered:

@DimaHubenkoGamepoint This is expected with the current issue as discussed in this thread, we are working on it.

@JeffDUnity3D Since I got a connection I have a question:
What is the idea of the verification flow when the receipt is not verified by the server? By now we have no other option except of “ConfirmPendingPurchase”. So user gets his money taken anyway…

Last image on this page has only point 8 which is ConfirmPendingPurchase…

Correct, there are no other options at this time, other than local receipt validation https://docs.unity3d.com/Manual/UnityIAPValidatingReceipts.html

Hi, just want to report that we also experienced the ConfirmPendingPurchase issue on our end.

Our test case consists of making a IAP purchase using a live build of our app that uses 2.1.1, then the second time we try purchasing the same IAP the duplicate transaction error will trigger.

So we’re trying to push a fix on our next app update using 2.2.5 but our tests indicates that ConfirmPendingPurchase doesn’t always clear orphaned transactions. We get a log saying: “Unable to confirm purchase; Product has missing or empty transactionID”
We got kinda desperate and even tried using FinishAdditionalTransaction to no avail and even trying to call ConfirmPendingPurchase on all product on our init.

Glad to know that we weren’t the only one with issue and that theres a fix on the way. Thanks!

Quick question though, when OnPurchaseFailed is triggered, are we suppose to call ConfirmPendingPurchase on it anyways?

1 Like

Agreed, we are working on this one at highest priority. There is no need to make any additional calls when you receive OnPurchaseFailed.

I have the “ConfirmPendingPurchase” issue when using 2.2.6 and 2.2.7

2 Likes

The issue has been addressed, you are likely seeing something else. Please provide details and specific steps to reproduce and the code that you are using, and how you are debugging.

I have almost the same problem in 2.2.7

Reproduce steps:

  1. Purchase a consumable item A.

  2. In “ProcessPurchase” callback, return “PurchaseProcessingResult.Pending”. And request server to validate.

  3. Return “Error” from server and keep purchase in Pending, then reopen App.

  4. When IAP is initializing, I received the “ProcessPurchase” callback. In the callback, return “PurchaseProcessingResult.Pending”, and request server to validate again.

  5. After server “Success” return, I called “ConfirmPendingPurchase” to finish the transaction.

  6. Try to purchase the same item A, I got PurchaseFailureReason.DuplicateTransaction error and “Already recorded transaction”.

  7. Every next app reopen I got “Already recorded transaction” on startup.

  8. Try to purchase the same item A, I got PurchaseFailureReason.DuplicateTransaction error and “Already recorded transaction”.

  9. After app reinstall, I received the “ProcessPurchase” callback and got the same behavior from Step 4.

It looks like Consumable item becomes Non-consumable, because App tries to purchase it every app reinstall, doesn’t allow to purchase it again and also I got “acknowledgementState”:1,“consumptionState”:0 in recipe validation on server.

But e.purchasedProduct.definition.type is Consumable. So the product is still Consumable, but doesn’t consumes after “ConfirmPendingPurchase” on startup.

Also, if I change “PurchaseProcessingResult.Pending” to “PurchaseProcessingResult.Complete” on “ProcessPurchase” after problem detected, the problem still exists.

So “ConfirmPendingPurchase” and “PurchaseProcessingResult.Complete” doesn’t consume product in Pending state after App restart.

@Olegleg Your issue is not related to ConfirmPendingPurchase if you see the same behavior when not using it? Please test with IAP 3.0.1 (but should also work with 2.2.7). In the meantime, please share your code for ProcessPurchase, I don’t have this issue with the Sample IAP Project here Sample IAP Project