Ever since some IAP system version that we’re still trying to figure out, we now get the ProcessPurchase callback before OnInitialized, which of course breaks our code, since when receiving a purchase we need the IAP system started to do things with the API.
This happens if the Google Play account already has the purchase when the app first starts (or after it has its data deleted).
It’s difficult to recreate this error without a massive amount of work creating a fake app and fake purchase on Google Play, so I’m reporting the problem here.
We noticed this change in the release notes:
Was this it? If so, why is it called before initialization?
This change was also suspect, but probably intended since it says it’s after “fetched”, not after “sending purchase callbacks”:
No, ProcessPurchase is never called before IAP initialization, it’s the result of calling it. Please place Debug.Log statements in your code. And ensure not to be mixing Codeless IAP (which can initialize automatically) and Scripted IAP. If you never initialize IAP, you’ll never receive a ProcessPurchase callback.
We were placing Debug.Log statements, in OnInitialized and ProcessPurchase. That’s how we confirmed. The one in OnInitialized never happened, and we still got a ProcessPurchase. I assume it never happened because the code in our ProcessPurchase callback crashed, so the rest of the system didn’t initialize.
This didn’t happen before. We have never used the codeless API.
We altered the code in the following way, which fixed it:
When we get the ProcessPurchase callback before initialization, we now setup an “Action delayedPurchaseCallbacksForOnInitialized” and register the code we actually want to run when a purchase happens. Then on initialize, we run that action to run the purchase processing in the right order.
I don’t know what’s going on or if this is a big misunderstanding. How can I help reproduce this for you?
ProcessPurchase is always triggered by IAP Initialization. If you don’t initialize IAP (please try it) you won’t see ProcessPurchase, please confirm. Also, please share your purchase code.
Do you mean something else here? I know OnInitialized is triggered by calling UnityPurchasing.Initialize, and perhaps ProcessPurchase as well in this situation, but OnInitialized is only happening AFTER ProcessPurchase, if the user already has the purchase. That’s what I mean.
That’s what I thought you were saying, after looking at it again. But that’s not the issue. Does the system seriously only call OnInitialized after asking us to ProcessPurchase?
If so, why? This didn’t happen before, as far as I can tell.
Jeff, please read what I said. You are talking about calling UnityPurchasing.Initialize(). I’m not talking about that. Of course nothing happens if we don’t start the system.
I’m saying that (after calling UnityPurchasing.Initialize) the callback OnInitialized is only happening after ProcessPurchase.
I read what you said, I was suggesting a test. Please share your code so I can reproduce your scenario. I will also test with the Sample IAP Project to see if it is a general issue.
No problem, I’ll be trying to get some simpler code that initializes the system and then just prints something in the callbacks. There’s of course still the possibility that something went wrong on our side but I was trying to see that we were on the same page first.
Just a question in the meantime. What test were you suggesting? “Don’t initialize IAP, and you won’t see ProcessPurchase” was never in question. Nothing happens if we don’t start it, right?
It was a test. And yes, something could happen if you had a bug in your code, the test would have confirmed. Some developers explicitly call the purchase callback methods by mistake for example, and I wanted to rule that out. Also, some developers forget that they previously had Codeless tests in their project, which auto-initializes IAP. The same test would have ruled that out also. But we can move on now
That’s fair, I guess you folks have to deal with a lot of mistaken reports. But to clarify again, this was never about receiving ProcessPurchase; only about receiving it BEFORE the OnInitialized callback (which finishes the initialization of the IAP system).
I reproduced the problem. I used this code:
using UnityEngine;
using UnityEngine.Purchasing;
public class IAPTestListener : IStoreListener
{
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
static void OnBeforeSceneLoadRuntimeMethod()
{
new IAPTestListener().Initialize();
}
public void Initialize()
{
Debug.Log("Initialize");
ConfigurationBuilder builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
builder.AddProduct("com.somecompany.someapp.subscription.fullapp", ProductType.Subscription);
UnityPurchasing.Initialize(this, builder);
}
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
Debug.Log("OnInitialized");
}
public void OnInitializeFailed(InitializationFailureReason error)
{
Debug.Log("OnInitializeFailed");
}
public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason)
{
Debug.Log("OnPurchaseFailed");
}
public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs purchaseEvent)
{
Debug.Log("ProcessPurchase");
return PurchaseProcessingResult.Complete;
}
}
That pretty much clears it up! Thanks for the steps, pretty straight forward as you’ve mentioned. I’m testing now too. I was just reviewing the release notes for the upcoming release in a day or two, and it mentions a race condition when initializing and fetching product info that has been addressed, so I’ll be testing both versions. Stay tuned.
I’ve reproduced with IAP 2.2.5, and confirmed that the next release addresses the issue and OnInitialized is called before ProcessPurchase. The next release should be out in the next day or so.