Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

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

Discussion in 'Unity IAP' started by Nicolas1212, May 11, 2016.

Thread Status:
Not open for further replies.
  1. Nicolas1212

    Nicolas1212

    Joined:
    Dec 18, 2014
    Posts:
    139
    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
     
  2. Nicolas1212

    Nicolas1212

    Joined:
    Dec 18, 2014
    Posts:
    139
    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
     

    Attached Files:

  3. Banderous

    Banderous

    Joined:
    Dec 25, 2011
    Posts:
    669
    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.
     
  4. Nicolas1212

    Nicolas1212

    Joined:
    Dec 18, 2014
    Posts:
    139
    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.
     

    Attached Files:

  5. Nicolas1212

    Nicolas1212

    Joined:
    Dec 18, 2014
    Posts:
    139
    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
     
    nicholasr and erika_d like this.
  6. Nicolas1212

    Nicolas1212

    Joined:
    Dec 18, 2014
    Posts:
    139
    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
     
  7. Nicolas1212

    Nicolas1212

    Joined:
    Dec 18, 2014
    Posts:
    139
    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 http://forum.unity3d.com/threads/ia...s-not-return-processpurchase-callback.392000/

    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
     

    Attached Files:

  8. Nicolas1212

    Nicolas1212

    Joined:
    Dec 18, 2014
    Posts:
    139
    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?
     
  9. Nicolas1212

    Nicolas1212

    Joined:
    Dec 18, 2014
    Posts:
    139
    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.
     

    Attached Files:

  10. Nicolas1212

    Nicolas1212

    Joined:
    Dec 18, 2014
    Posts:
    139
    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 <redacted> + 150
    1 libobjc.A.dylib 0x20352e17 objc_exception_throw + 38
    2 CoreFoundation 0x20bb78d1 <redacted> + 0
    3 Foundation 0x213068c9 <redacted> + 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 <redacted> + 106
    21 QuartzCore 0x23212837 <redacted> + 594
    22 IOMobileFramebuffer 0x228f950b <redacted> + 86
    23 IOKit 0x20e08759 IODispatchCalloutFromCFMessage + 256
    24 CoreFoundation 0x20b6641d <redacted> + 132
    25 CoreFoundation 0x20b7a623 <redacted> + 34
    26 CoreFoundation 0x20b79d37 <redacted> + 342
    27 CoreFoundation 0x20b78149 <redacted> + 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 <redacted> + 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
     
  11. Banderous

    Banderous

    Joined:
    Dec 25, 2011
    Posts:
    669
    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.
     
  12. Nicolas1212

    Nicolas1212

    Joined:
    Dec 18, 2014
    Posts:
    139
    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
     
  13. Nicolas1212

    Nicolas1212

    Joined:
    Dec 18, 2014
    Posts:
    139
    FINALLY!

    As mentioned here (http://forum.unity3d.com/threads/ia...processpurchase-callback.392000/#post-2641575) 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?
     
    Adam_Nosal and mpinol like this.
  14. DanjelRicci

    DanjelRicci

    Joined:
    Mar 8, 2010
    Posts:
    308
    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? :D
     
    Nicolas1212 and erika_d like this.
  15. Nicolas1212

    Nicolas1212

    Joined:
    Dec 18, 2014
    Posts:
    139
    Literally printed out every object in the game when changing the scene :p
     
    erika_d likes this.
Thread Status:
Not open for further replies.