[Solved] Unity IAPs ProcessPurchase not calling after purchase, only after app restart

Hi,

I’m currently trying to integrate Unity IAPs into our live app. We were using another plugin, and purchases are working, so it’s not a setup issue, I’m simply trying to switch from one plugin to another.

I’m following the steps in the Unity manual, and everything seems to be working when testing in the editor. My problem is when testing on the device (currently Android).

I launch the purchase process, I get the dialog from Google Play (test purchase), make my purchase, come back to the app, then… nothing.

Looking at the logs through adb, I see the log:

purchase({0}): my_iap_item_id

so it’s getting purchased, however ProcessPurchase is NOT getting called (neither is OnPurchaseFailed, but that’s normal).

When I restart the app, ProcessPurchase IS called, and I go through the verification flow. This seems to be the normal flow for purchases that haven’t been finalised.

What am I missing here? Why is ProcessPurchase not being called after the fact? Is there something I should be calling? I’m working on a tight deadline, so I’d appreciate any quick responses or ideas

I’m on Unity 5.3.4p6

Thanks

Okay, after trawling through the raw log, there are two things that seem to stand out. The first is an exception:

E/Parcel ( 907): Class not found when unmarshalling: com.google.android.finsky.billing.lightpurchase.PurchaseParams
E/Parcel ( 907): java.lang.ClassNotFoundException: com.google.android.finsky.billing.lightpurchase.PurchaseParams
E/Parcel ( 907): at java.lang.Class.classForName(Native Method)
E/Parcel ( 907): at java.lang.Class.forName(Class.java:309)
E/Parcel ( 907): at java.lang.Class.forName(Class.java:273)
E/Parcel ( 907): at android.os.Parcel.readParcelableCreator(Parcel.java:2281)
E/Parcel ( 907): at android.os.Parcel.readParcelable(Parcel.java:2245)
E/Parcel ( 907): at android.os.Parcel.readValue(Parcel.java:2152)
E/Parcel ( 907): at android.os.Parcel.readArrayMapInternal(Parcel.java:2485)
E/Parcel ( 907): at android.os.BaseBundle.unparcel(BaseBundle.java:221)
E/Parcel ( 907): at android.os.BaseBundle.getString(BaseBundle.java:918)
E/Parcel ( 907): at android.content.Intent.getStringExtra(Intent.java:5794)
E/Parcel ( 907): at com.android.server.am.ActivityStackSupervisor.startActivityLocked(ActivityStackSupervisor.java:2402)
E/Parcel ( 907): at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:1883)
E/Parcel ( 907): at com.android.server.am.ActivityManagerService.startActivityInPackage(ActivityManagerService.java:5737)
E/Parcel ( 907): at com.android.server.am.PendingIntentRecord.sendInner(PendingIntentRecord.java:257)
E/Parcel ( 907): at com.android.server.am.ActivityManagerService.startActivityIntentSender(ActivityManagerService.java:5510)
E/Parcel ( 907): at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:262)
E/Parcel ( 907): at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:3229)
E/Parcel ( 907): at android.os.Binder.execTransact(Binder.java:446)
E/Parcel ( 907): Caused by: java.lang.ClassNotFoundException: Didn’t find class “com.google.android.finsky.billing.lightpurchase.PurchaseParams” on path: DexPathList[[directory “.”],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
E/Parcel ( 907): at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
E/Parcel ( 907): at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
E/Parcel ( 907): at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
E/Parcel ( 907): … 18 more
E/Parcel ( 907): Suppressed: java.lang.ClassNotFoundException: com.google.android.finsky.billing.lightpurchase.PurchaseParams
E/Parcel ( 907): at java.lang.Class.classForName(Native Method)
E/Parcel ( 907): at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
E/Parcel ( 907): at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
E/Parcel ( 907): at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
E/Parcel ( 907): … 19 more
E/Parcel ( 907): Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack available

But then again, the purchase seems to go through, so maybe it’s nothing.

I see the purchase being successful:

I/UnityIAP(11859): Successful resultcode from purchase activity.
I/UnityIAP(11859): Purchase data: {“orderId”:“GPA.1375-1597-9324-16851”,“packageName”:“com.triplefun.Masters”,“productId”:“masters_pack_x_small_diam”,“purchaseTime”:1462973484639,“purchaseState”:0,“purchaseToken”:“bdefigommkffffpadebiknml.AO-J1OwDDkJPTDVhhBwajE7FKHQHJldTFbM9QyNslVla1WiSQljHdQ_G5hDefpR_zlTOi4hffwrkPuUh-U8iRvhoGh6lWq4cx2mrRDGwHhsvxPEExvjZ0mpxiHPVlqHeY5WXRP6nDx7wuEqKST-pSA-8FcJT2f-cLg”}
I/UnityIAP(11859): Data signature: mp40CkUuS7CE93HpNn23bJ9pbnxCOFL0dOspq5ugVRtq3S+3JD+wAajUoQJi5nHk7IMrwwkuz/4jid/hFEXwbcxJWusFFnxkW0tuuaD1qypkCUs7Kj5i/B46k21y3gU3ZhaCBcA03LXbUwXYJ650naDS+MHXrFxukW3PBCGEAkvYOAhYuG1QYFwo+8HVNTmyoK0I58oYtGpGdadedrpwG1jEh/eaYaoI/cFUr2zQAMS4qcsXI91VoEP2t1itjmYaZD4lhiZ9CfudmejAiSUuroxncpbj1ipqxMn5oZXWADP6msIZf7uK4os1wxGPBkuExYYi/+Spb06VZZQdFICZpQ==
I/UnityIAP(11859): Extras: Bundle[{INAPP_PURCHASE_DATA={“orderId”:“GPA.1375-1597-9324-16851”,“packageName”:“com.triplefun.Masters”,“productId”:“masters_pack_x_small_diam”,“purchaseTime”:1462973484639,“purchaseState”:0,“purchaseToken”:“bdefigommkffffpadebiknml.AO-J1OwDDkJPTDVhhBwajE7FKHQHJldTFbM9QyNslVla1WiSQljHdQ_G5hDefpR_zlTOi4hffwrkPuUh-U8iRvhoGh6lWq4cx2mrRDGwHhsvxPEExvjZ0mpxiHPVlqHeY5WXRP6nDx7wuEqKST-pSA-8FcJT2f-cLg”}, INAPP_DATA_SIGNATURE=mp40CkUuS7CE93HpNn23bJ9pbnxCOFL0dOspq5ugVRtq3S+3JD+wAajUoQJi5nHk7IMrwwkuz/4jid/hFEXwbcxJWusFFnxkW0tuuaD1qypkCUs7Kj5i/B46k21y3gU3ZhaCBcA03LXbUwXYJ650naDS+MHXrFxukW3PBCGEAkvYOAhYuG1QYFwo+8HVNTmyoK0I58oYtGpGdadedrpwG1jEh/eaYaoI/cFUr2zQAMS4qcsXI91VoEP2t1itjmYaZD4lhiZ9CfudmejAiSUuroxncpbj1ipqxMn5oZXWADP6msIZf7uK4os1wxGPBkuExYYi/+Spb06VZZQdFICZpQ==, RESPONSE_CODE=0}]
I/UnityIAP(11859): Expected item type: inapp
I/UnityIAP(11859): onIabPurchaseFinished: true
I/UnityIAP(11859): Success (response: 0:OK)

And it goes to notify Unity:

I/UnityIAP(11859): NotifyUnityOfPurchase
D/InputDispatcher( 907): Focus left window: 10520
D/InputDispatcher( 907): Focus entered window: 11859

Then, later on, I see this:

W/AppOps ( 907): Bad call: specified package com.triplefun.Masters under uid 10027 but it is really 10237

Is this related or unrelated? I’ve attached the full adb log of the part in question if it highlights anything.

Thanks

2630690–184906–adb_log_unity_iap.txt (57.8 KB)

It looks like an internal problem with Google Play, the “ClassNotFoundException: com.google.android.finsky.billing.lightpurchase.PurchaseParams” looks relevant according to others who have hit this problem.

Googling this many people have hit the problem but there is no clear way to resolve it. Some people resolved it by waiting, some by restarting their device, some by reuploading their APK under a different package name (which is likely not an option for you).

I suggest you try uploading a new APK with a new version code, but beyond that you’d need to raise a support request with Google.

Hi Banderous,

Thanks for the reply. I redid a purchase with the old lib that we were using and the PurchaseParams ClassNotFoundException came up as well (see annotated log attached), so I guess it’s not blocking it.

I found the same StackOverflow question, though I think their problem was that they’d just uploaded their APK, and just hadn’t waited the required number of magic hours. Our app is live for a few months now, and as I’m using the same version number, I’ve no problem launching or purchasing - it’s just the callbacks aren’t being called on the Unity end.

I also built with iOS this morning and have the same problem, which the exception that it doesn’t work when I relaunch the app. I get the password prompt, so I’m assuming there’s a restore going on (I added a call to be sure), but again, no callbacks called.

2632087–185030–adb_log_android_native_iap.txt (68.5 KB)

Okay, so I’ve managed to figure out the problem with Android after building a separate problem with just IAPs in it. It was down to changing scenes. We use additive scene changing, deleting GameObjects by had if they don’t have a specific Component.

UnityIAP creates a new GameObject called IAPUtil that doesn’t appear in the scene hierarchy (in the Editor at least), and as there’s no way to check if an object is marked as DontDestroyOnLoad(), it got destroyed. Adding an exception for that object meant that Android is now working.

Still no luck on iOS though

2 Likes

Okay,

For iOS, the purchase not working were because of previous unfulfilled purchases. Once cleared, I can make purchases. However, if I interrupt the purchase before marking it as completed, I don’t get notified of it the next time the app launches, which I thought was the default?

Calling RestorePurchases() doesn’t work either.

I can however call to refresh the app receipt, which gives me the transaction that hasn’t been processed, then do it manually, but is this the expected behaviour?

  • How can I tell at app launch if there’s an unresolved purchase? I think refreshing the app receipt asks for the password, so it’s irritating to do it everytime
  • Am I meant to handle unresolved purchases myself by refreshing the app receipt and parsing it?
  • How can I get Unity to call the ProcessPurchase callback for unresolved purchases on iOS (on Android it seems to be working)

Thanks

Bump.

Current state:

Editor:

  • Works

Android:

  • Purchase works
  • Failed purchases works after restart

iOS:

  • Purchase works
  • Failed purchases get a restore message, but nothing is triggered
  • On app restart, I get prompted for my password, but nothing is called

I think I’m possibly hitting the same bug as [Closed] RestorePurchase on iOS not return ProcessPurchase callback - Unity Services - Unity Discussions

I went through and made sure that there was only one ConfigurationBuilder inited (though it’s not mentioned anywhere in the documentation) and that all callbacks are to actual functions, not anonymous ones (again, not in the code samples).

One possible cause after adding a ton of NSLogs to UnityPurchasing.m is that I think the product is try to notify Unity before the transaction observer is added.

The flow seems to be:

  • Initing
  • Retrieving products from JSON
  • Decoding Product Definitions
  • Initing product poll
  • Product poll callback
  • Received products
  • Serialising product metadata
  • Selecting receipt for transaction (null id)
  • Getting the app receipt
  • Getting the result from the app receipt
  • Sending unity a message with OnProductsRetrieved as the subject, JSON array of products as payload, & receipt
  • Init callback in Unity
  • Adding transaction observer

I’ve attached the full log if it makes sense to someone. Anything with the tag “[UNITY_IAP]” is an NSLog added to UnityPurchasing.m

2638145–185602–iOS_start_with_failed_purchase.txt (37.6 KB)

As for purchasing a previously bugged item, it’s because UnityPurchasing.m literally doesn’t notify unity, unless I’m missing something

The relevant logs:

2016-05-17 12:47:42.951 Masters[2175:1173510] [UNITY_IAP] PURCHASING PURCHASE FROM JSON {“id”:“masters_pack_x_small_diam”, “storeSpecificId”:“masters_pack_x_small_diam”, “type”:“Consumable”}
2016-05-17 12:47:42.952 Masters[2175:1173510] [UNITY_IAP] DESERIALIZING PRODUCT DEFINITIONS 2 FROM JSON {“id”:“masters_pack_x_small_diam”, “storeSpecificId”:“masters_pack_x_small_diam”, “type”:“Consumable”}
2016-05-17 12:47:42.953 Masters[2175:1173510] [UNITY_IAP] DECODING PRODUCT DEFINITION
2016-05-17 12:47:42.954 Masters[2175:1173510] [UNITY_IAP] PURCHASING PRODUCT masters_pack_x_small_diam
2016-05-17 12:47:42.954 Masters[2175:1173510] UnityIAP:PurchaseProduct: masters_pack_x_small_diam
2016-05-17 12:47:42.966 Masters[2175:1173510] [UNITY_IAP]PAYMENT QUEUE UPDATE FOR 1 TRANSACTIONS
2016-05-17 12:47:42.967 Masters[2175:1173510] UnityIAP:UpdatedTransactions
2016-05-17 12:47:42.967 Masters[2175:1173510] [UNITY_IAP] PAYMENT QUEUE UPDATE FOR (null) - CURRENT STATE: 0
purchase({0}): masters_pack_x_small_diam
UnityPurchaseManager:BuyItem(String)
UnityEngine.UI.Button:Press()
UnityEngine.EventSystems.ExecuteEvents:Execute(IPointerClickHandler, BaseEventData)
UnityEngine.EventSystems.ExecuteEvents:Execute(GameObject, BaseEventData, EventFunction`1)
UnityEngine.EventSystems.StandaloneInputModule:ProcessTouchPress(PointerEventData, Boolean, Boolean)
UnityEngine.EventSystems.StandaloneInputModule:Process()

The “CURRENT STATE: 0” refers to SKPaymentTransactionStatePurchasing where the code is:

caseSKPaymentTransactionStatePurchasing:
// Item is still in the process of being purchased
break;

So unity never gets notified. I’m assuming something else it meant to happen?

So building a sample project with the same bundleID, with nothing but UnityIAP in there, I can see that I have a purchase waiting, but no callback is triggered.

In this one, I’m specifically making a call to refresh purchases and getting the app receipt.

Log attached, as well as the class I’m using for IAP. In the log, anything marked [UNITY_IAP] is UnityPurchasing.m while anything logged [IAPManager] is the Unity class.

2638443–185633–iOS_start_with_failed_purchase_standalone.txt (46.6 KB)
2638447–185635–IAPManager.cs (5.1 KB)

I thought I’d be able to manually confirm a blocked purchase, but unfortunately it generates this error:

[IAPManager] Manually confirming pending purchase [Product id: masters_pack_x_small_diam, transactionID: , receipt: ]
UnityEngine.Logger:Log(LogType, Object)
UnityEngine.Debug:Log(Object)
IAPManager:Update()

(Filename: /Users/builduser/buildslave/unity/build/artifacts/generated/common/runtime/UnityEngineDebugBindings.gen.cpp Line: 37)

2016-05-17 17:08:43.412 Masters[2307:1230512] Uncaught exception: NSInvalidArgumentException: *** +[NSString stringWithUTF8String:]: NULL cString
(
0 CoreFoundation 0x20bb79a3 + 150
1 libobjc.A.dylib 0x20352e17 objc_exception_throw + 38
2 CoreFoundation 0x20bb78d1 + 0
3 Foundation 0x213068c9 + 76
4 Masters 0x0009e9f3 unityPurchasingFinishTransaction + 44
5 Masters 0x0009eba7 iOSStoreBindings_unityPurchasingFinishTransaction_m890609062 + 30
6 Masters 0x00175d69 NativeJSONStore_FinishTransaction_m2249698866 + 104
7 Masters 0x002c82d7 PurchasingManager_ConfirmPendingPurchase_m1082777978 + 100
8 Masters 0x000a18e9 IAPManager_Update_m837305831 + 584
9 Masters 0x00505f19 Z31RuntimeInvoker_Void_t2779279689PK10MethodInfoPvPS2 + 14
10 Masters 0x00c7d215 _ZN6il2cpp2vm7Runtime6InvokeEPK10MethodInfoPvPS5_PP15Il2CppException + 116
11 Masters 0x00671405 _ZN25ScriptingInvocationNoArgs6InvokeEPP18ScriptingException + 56
12 Masters 0x006713c7 _ZN25ScriptingInvocationNoArgs6InvokeEv + 18
13 Masters 0x00665af1 _ZN13MonoBehaviour16CallUpdateMethodEi + 152
14 Masters 0x0057f7e5 _ZN20BaseBehaviourManager12CommonUpdateI16BehaviourManagerEEvv + 52
15 Masters 0x0062a51d _Z10PlayerLoopbbP10IHookEvent + 1304
16 Masters 0x007b62ab _ZL19UnityPlayerLoopImplb + 14
17 Masters 0x0008190d UnityRepaint + 416
18 Masters 0x00081711 -[UnityAppController(Rendering) repaintDisplayLink] + 76
19 libglInterpose.dylib 0x02571905 -[DYDisplayLinkInterposer forwardDisplayLinkCallback:] + 272
20 QuartzCore 0x232129eb + 106
21 QuartzCore 0x23212837 + 594
22 IOMobileFramebuffer 0x228f950b + 86
23 IOKit 0x20e08759 IODispatchCalloutFromCFMessage + 256
24 CoreFoundation 0x20b6641d + 132
25 CoreFoundation 0x20b7a623 + 34
26 CoreFoundation 0x20b79d37 + 342
27 CoreFoundation 0x20b78149 + 1688
28 CoreFoundation 0x20ac72e9 CFRunLoopRunSpecific + 520
29 CoreFoundation 0x20ac70d5 CFRunLoopRunInMode + 108
30 GraphicsServices 0x220b7ac9 GSEventRunModal + 160
31 UIKit 0x2518c0b9 UIApplicationMain + 144
32 Masters 0x0007a0fb main + 202
33 libdyld.dylib 0x2076f873 + 2
)
2016-05-17 17:08:43.416 Masters[2307:1230512] *** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘*** +[NSString stringWithUTF8String:]: NULL cString’
*** First throw call stack:
(0x20bb798b 0x20352e17 0x20bb78d1 0x213068c9 0x9e9f3 0x9eba7 0x175d69 0x2c82d7 0xa18e9 0x505f19 0xc7d215 0x671405 0x6713c7 0x665af1 0x57f7e5 0x62a51d 0x7b62ab 0x8190d 0x81711 0x2571905 0x232129eb 0x23212837 0x228f950b 0x20e08759 0x20b6641d 0x20b7a623 0x20b79d37 0x20b78149 0x20ac72e9 0x20ac70d5 0x220b7ac9 0x2518c0b9 0x7a0fb 0x2076f873)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)

And I can’t actually create a Product with the right TransactionID/Receipt because they’re all set as internal/private

From the logs it appears Storekit is not notifying Unity IAP about the purchase completing. As you say, SKPaymentTransactionStatePurchasing should be followed by another update with a status of SKPaymentTransactionStatePurchased.

Try creating a new itunes connect sandbox account. ProcessPurchase should be called for all pending transactions.

It won’t be possible to confirm those products via ConfirmPendingPurchase since Unity IAP does itself is unaware they are pending - storekit has not informed it.

Hi Banderous,

To respond quickly to your points:

“Try creating a new itunes connect sandbox account”
Unfortunately not a solution for the people that currently have this problem in prod. My Standalone UnityIAP project uses the same account and can make/unblock purchases fine (I think the problem is related to another bug, where after a purchase, UnityIAP doesn’t update/refresh the receipt, so when you restart the app, it looks like you’ve a pending purchase, wherein you actually don’t)

“It won’t be possible to confirm those products via ConfirmPendingPurchase since Unity IAP does itself is unaware they are pending”
Unity IAP has the receipt, which has the pending products, so I’m not sure why it can’t trigger that they’re pending. You have both the productID, transactionID, and necessary receipt to force it yourself if necessary.

I took the class from the standalone project - which is processing callbacks on restart - into our current project - which isn’t processing callbacks on restart - and… it didn’t work. Completely the same code.

So, I’m at a complete loss right now. Do you know of anything that could trigger this not working? Scenes changing, things that should be marked in the plist/Xcode project but aren’t? Anything that I can look at

FINALLY!

As mentioned here ([Closed] RestorePurchase on iOS not return ProcessPurchase callback - Unity Services - Unity Discussions) the culprit was Facebook.

On iOS, if you’re on SDK 3.22 or higher, Facebook can be set to automatically log purchase events (https://developers.facebook.com/docs/app-events/ios#purchase), which I guess means that it’s adding a transaction observer before(?) Unity, so Unity is missing out on the purchase notifications on app startup. (NOTE: the docs mention having to call ActivateApp() to turn this on, but this is done automatically on iOS)

We’re not using logging, so we turned it off on the Facebook settings (developers.facebook.com > App > Settings > Basic > iOS > iOS Only: Log In-App Purchase Events Automatically (Recommended))

Is this technically classed as a Unity or a Facebook bug. Can you guys liaise with FB on this?

2 Likes

Thank you oh so much because I was having the same problem, and the culprit was indeed the scene change (I had FB In-App Log disabled). I already had this problem before with other plugins instancing stuff, but I totally missed the IAPUtil GameObject. How did you find it? :smile:

2 Likes

Literally printed out every object in the game when changing the scene :stuck_out_tongue:

1 Like