[Closed] RestorePurchase on iOS not return ProcessPurchase callback

logging the transaction count in paymentQueue:updatedTransactions and addTransactionObserver i found that

  • in the empty app i get 0 transactions in addTransactionObserver and then ios immediately fires a paymentQueue:updatedTransactions with the pending payment

  • in the main app i get 1 transaction already added in addTransactionObserver, so no event is fired

  • if I force the update, it is notified by unity after (more than?) a frame, so I cannot distinguish anymore the case “init complete, no purchases pending” from “init complete with x purchases pending”, so I have to change my app flow

Unity IAP adds a single transaction observer during initialisation and leaves it in place for the lifetime of the process.

If storekit is not notifying that transaction observer, as it appears from the log you sent, then that is an issue to take up with Apple. Unity IAP cannot add an additional transaction observer on the chance that storekit will send it transactions that it should already be receiving.

I am not adding another observer. i simply force a paymentQueue:updatedTransactions: when unityIAP adds itself to the SKPaymentQueue.

Is it possible that another plugin in your project would be adding a transaction observer? You mentioned previously that a transaction already exists when Unity IAP adds its transaction observer. SKPaymentQueue.transactions should be undefined until the first observer is added.

that what I was investigating right now. I do have native plugins in my project but some of them are compiled (.h + .a files) ant the ones for which I have the source do not add observers (except for reign native, which we used for wp8 before unityIAP and was the first thing I commented out and replaced with nslogs)

I managed to set a symbolic breakpoint in xcode for “-[SKPaymentQueue addTransactionObserver:]” and it hits before our splash screen, with this stack trace

(lldb) bt

* thread #1: tid = 0xbcbade, 0x000000018d177294 StoreKit`-[SKPaymentQueue addTransactionObserver:], queue = 'com.apple.main-thread', activity = 'starting resolver activity', 2 messages, stop reason = breakpoint 1.1

  * frame #0: 0x000000018d177294 StoreKit`-[SKPaymentQueue addTransactionObserver:]

    frame #1: 0x000000010131472c BurracoOnline`___lldb_unnamed_function2935$BurracoOnline + 84

    frame #2: 0x00000001012e7b20 BurracoOnline`___lldb_unnamed_function1610$BurracoOnline + 264

    frame #3: 0x00000001012e746c BurracoOnline`___lldb_unnamed_function1602$BurracoOnline + 112

    frame #4: 0x0000000182d59558 Foundation`-[__NSObserver _doit:] + 308

    frame #5: 0x0000000182410eac CoreFoundation`__CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 20

    frame #6: 0x00000001824106cc CoreFoundation`_CFXRegistrationPost + 396

    frame #7: 0x000000018241044c CoreFoundation`___CFXNotificationPost_block_invoke + 60

    frame #8: 0x0000000182479494 CoreFoundation`-[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1532

    frame #9: 0x000000018234e788 CoreFoundation`_CFXNotificationPost + 368

    frame #10: 0x0000000182d5689c Foundation`-[NSNotificationCenter postNotificationName:object:userInfo:] + 68

    frame #11: 0x000000018785633c UIKit`-[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 3584

    frame #12: 0x000000018785a500 UIKit`-[UIApplication _runWithMainScene:transitionContext:completion:] + 1684

    frame #13: 0x0000000187857674 UIKit`-[UIApplication workspaceDidEndTransaction:] + 168

    frame #14: 0x0000000183e0f7ac FrontBoardServices`__FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 36

    frame #15: 0x0000000183e0f618 FrontBoardServices`-[FBSSerialQueue _performNext] + 168

    frame #16: 0x0000000183e0f9c8 FrontBoardServices`-[FBSSerialQueue _performNextFromRunLoopSource] + 56

    frame #17: 0x0000000182425124 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 24

    frame #18: 0x0000000182424bb8 CoreFoundation`__CFRunLoopDoSources0 + 540

    frame #19: 0x00000001824228b8 CoreFoundation`__CFRunLoopRun + 724

    frame #20: 0x000000018234cd10 CoreFoundation`CFRunLoopRunSpecific + 384

    frame #21: 0x000000018761f834 UIKit`-[UIApplication _run] + 460

    frame #22: 0x0000000187619f70 UIKit`UIApplicationMain + 204

    frame #23: 0x00000001000be15c BurracoOnline`main(argc=<unavailable>, argv=<unavailable>) + 156 at main.mm:32 [opt]

    frame #24: 0x0000000181eea8b8 libdyld.dylib`start + 4

It looks like the transaction observer is being added from a listener added to NSNotificationCenter. Can you set a breakpoint to try to catch what is adding the notification listener?

Alternatively you could binary search through your installed plugins until you find the one that’s adding it.

that seems a better approach than my current “(lldb) p (id)($sp)” attempts…
I’ll try to look into NSNotificationCenter stuff.

what I could use to do the binary search?

By binary search I meant:

  1. Remove half the plugins
  2. Retest. If the observer is still added it must be one of the plugins you did not remove, otherwise it is in the half you removed.
  3. Resume from step 1 using whichever half of the plugins is known to contain the plugin which adds the transaction observer

13 hits for -[NSNotificationCenter addObserverForName:object:queue:usingBlock:]
146 hits for -[NSNotificationCenter addObserver:selector:name:object:]

it seems almost every plugin I have does something with NSNotificationCenter
then I tried removing StoreKit and let the linker complain…
(found a rogue Prime31 static constructor doing an extern call into it’s libStoreKit.a but I don’t reference it anymore and nothing changed when i commented out that line of code - I put a log in there to be sure, it doesn’t get called)

can’t do that because they are too much entangled with our code - we were unable to completely remove Prime31 and Reign from the project because it was a mess to refactor (for P31, we still use its “static OnActivityResult” on Android, and Reign is here for WP8 Facebook integration)

I was hoping for a way to scan the various .a for references to SKPaymentQueue calls…

I think it’s Facebook. I removed Facebook from our app and successfully got notified of a pending purchase on app restart.

If you’re on SDK 3.22 or higher, it’s set to automatically log IAP (https://developers.facebook.com/docs/app-events/ios/#purchase), though it’s not clear if you need to explicitly call ActivateApp() or if it’s done automatically for you on iOS. I guess to do the logging, they’re adding a listener, and it’s either because they don’t do it on Android, or the fact that iOS needs a password to restore transactions which lets them get in there first.

I’m trying a build right now where IAP logging is turned off in the developers.facebook.com settings to see if that makes a difference, or if I need to jump into the code to stop the ActivateApp() call

1 Like

found the culprit (I hope is the only one)

(lldb) p *(id*)($sp+16)
(GADInAppPurchaseTransactionReporter *) $1 = 0x000000013fab29d0

apparently admob thinks it should interfere with the payment flow

1 Like

Can confirm that turning off the automatic in-app purchasing on Facebook settings (developers.facebook.com > App > Settings > Basic > iOS > iOS Only: Log In-App Purchase Events Automatically (Recommended)) unblocks unity purchasing notifications. ActivateApp() is called automatically on iOS.

( @M_R - we’re not using AdMob - FB is pretty much the only plugin, aside from iOS Native)

As to when this change propagates to Unity, I’m not sure. After it worked, I reset logging of purchase events through the site, and it continued to work, so I’m not sure if it’s order issue (including Unity IAP before Facebook), or a cache issue (FB hadn’t propagated the re-change back), etc. At this point, after a week of sitting through half hour builds, I don’t really care :slight_smile:

2 Likes

@Nicolas1212 we do have facebook but that setting is off - and it will remain off -

now I’m trying if there is a similar setting for admob

1 Like

found it! [GADMobileAds disableAutomatedInAppPurchaseReporting];in application:didFinishLaunchingWithOptions:

4 Likes

Awesome finds @Nicolas1212 and @M_R . :sunglasses:

I’m noting these in our FAQ and we’re considering whether a code-change could address this “first registered observer gets all the callbacks” issue.

2 Likes

Is the any way to add this line to Unity project? Or only way is to remember to edit exported Xcode project every time?

I get it. Just need to subclass UnityAppController. :slight_smile:

// AppController.h

#import "UnityAppController.h"

@interface AppController : UnityAppController 
@end

IMPL_APP_CONTROLLER_SUBCLASS(AppController)


// App Controller.mm

#import "AppController.h"
#import <GoogleMobileAds/GoogleMobileAds.h>

@implementation AppController

-(BOOL)application:(UIApplication*)application willFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
    [GADMobileAds disableAutomatedInAppPurchaseReporting];
    return [super application:application willFinishLaunchingWithOptions:launchOptions];
}

@end
2 Likes

Hi,

I have issue with “This In-App purchase has already been bought. It will be restore for free”.

If I buy some consumable product, then verify, but not consume (with ConfirmPendingPurchase), and after that, again try to buy the same product, I have this message, and no any callback is called.
This is problem, because I disable all buttons and dont have any callback to enable it.

it is not related with addObserver.

Any ideas ?

@Martin_k ,

Could you start a new thread and include the information requested here: