I understand that for each single purchase, there should only be one callback: either the success callback or the failure callback. However, we have observed that for some purchases, we first receive a failure callback with codes such as UserCancelled, Unknown, ServiceUnavailable, etc., followed by a success callback after a short period.
This issue makes handling transactions very difficult. Should we proceed with the failure logic upon receiving a failure callback? Is this behavior expected?
From examining the Unity IAP code for the Google Play Store, it seems that OnApplicationPause(false) can trigger a call to m_FetchPurchases.FetchPurchases(). Additionally, LaunchGoogleBillingFlow also returns a GoogleBillingResult. Could these be causing both success and failure callbacks to be triggered?
The OnPurchaseSuccessful or OnPurchaseFailed callbacks are invoked only for purchases that require user input to proceed. The OnApplicationPaused method does not trigger these callbacks; it merely fetches purchase data to send to ProcessPurchase, so it is unlikely to be related.
Regarding the issue of simultaneous success and failure callbacks, we are currently investigating this matter. These callbacks seem to be originating from the onPurchasesUpdated method, which is a listener from the Google Play Billing Library. This situation is not expected behavior, and we are working to identify the root cause and a potential solution.
I now suspect that the issue is caused by calling Initialize multiple times with the same IDetailedStoreListener (because we wanted to trigger the purchase callbacks when we want to). Therefore, I’m considering calling Initialize only once. However, a new problem has emerged. If the payment process takes too long, when returning to the game, we may be unable to handle the callback because we need to re-establish our session or connection. What I want is to trigger the callback when I’m ready so that it can be handled properly. Is there a way to implement this logic?
You should only be calling Initialize once, otherwise there might be unexpected behaviours. We only recommend calling it again in the OnInitializeFailed if it failed to initialize.
The callbacks are not queued on our end, so if there’s no callback associated, you will miss that call.
For purchases, you can always return PurchaseProcessingResult.Pending in ProcessPurchase if you want to delay the confirmation. This lets you take all the time you need and you can then call the ConfirmPendingPurchase when ready.