IOS 11 with bundleProxy! = Nil error when using UNUserNotificationCenter

The next line of code is that our application suddenly started crashing on iOS 11 / 11.0.1 / 11.0.2 / 11.1.1 / 11.2.2 for some users:

UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; 

We have this in didFinishLaunchingWithOptions . The crash report says:

 Fatal Exception: NSInternalInconsistencyException Invalid parameter not satisfying: bundleProxy != nil Fatal Exception: NSInternalInconsistencyException 0 CoreFoundation 0x1869b3d38 __exceptionPreprocess 1 libobjc.A.dylib 0x185ec8528 objc_exception_throw 2 CoreFoundation 0x1869b3c0c +[NSException raise:format:] 3 Foundation 0x187342c24 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] 4 UserNotifications 0x18fcc973c -[UNUserNotificationCenter initWithBundleProxy:] 5 UserNotifications 0x18fcc950c __53+[UNUserNotificationCenter currentNotificationCenter]_block_invoke 6 libdispatch.dylib 0x186339048 _dispatch_client_callout 7 libdispatch.dylib 0x18633c710 dispatch_once_f$VARIANT$mp 8 UserNotifications 0x18fcc94ac +[UNUserNotificationCenter currentNotificationCenter] 

This is clear from iOS. Is anyone else experiencing the same error? Any idea what is going on?

+9
source share
3 answers

I'm not sure if this will work for everyone, however I figured it out for my use case. I created a framework that used an iOS application. This system used the UNUserNotificationCenter to configure alerts. For some reason, it seems that the “package” is not getting the proper initialization when this code is used from within the framework. Sometimes it works, sometimes it doesn’t. This bundleProxy , by the sound of things, is a kind of proxy server on which the notification system relies. Since the code is executed from within the framework, it is possible that this package was not found at runtime, and the system returns zero. I had this problem at all when trying to load resources from Framework where the package location is wrong.

In any case, the solution for me was to save the link to [UNUserNotificationCenter currentNotificationCenter] in the application’s deletion at startup, and then pass this to any method that would like to use it. By the time the application finishes launching, this proxy seems to load correctly if the calling code itself is a binary application. This seems to have fixed this for me.

+3
source

Why [UNUserNotificationCenter currentNotificationCenter] fail [UNUserNotificationCenter currentNotificationCenter] ?

According to the failure stack trace, bundleIdentifier is nil in the UNUserNotificationCenter private initialization method, and an exception is thrown. I do not know why.

Unfortunately, the method is called in the context of dispatch_once , so we cannot easily reproduce this failure. At first I tried to use the NSBundle.mainBundle.bundleIdentifier : NSBundle.mainBundle.bundleIdentifier , but this failed. I assume that the system did not use this method to get bundleIdentifier, so I tried to use the private initialization method UNUserNotificationCenter initWithBundleIdentifier:(String) , it worked and tried to pass nil to this method, which caused a failure 100% of the time !! !! Therefore, we can use this method when downloading a file and return nil if bundleIdentifier==nil , I hope this helps you.

see picture to know how it work

---------------- code -----------------

  /* UNUserNotificationCenter + Hack */ @implementation UNUserNotificationCenter (Hack) + (void)load { static dispatch_once_t _onceToken; dispatch_once(&_onceToken, ^{ [self safeHook]; }); } + (void)safeHook { /*hook UNUserNotificationCenter systemMethod initWithBundleIdentifier:*/ /* private method mix,hope no runtime check 😁*/ NSString * orig_initWithBundleSelectorName = [NSString stringWithFormat:@"%@%@%@",@"initWi",@"thBundleId",@"entifier:"]; SEL orig_initWithBundleSelector = NSSelectorFromString(orig_initWithBundleSelectorName); if (![self instancesRespondToSelector:orig_initWithBundleSelector]) { return; } SEL alt_initWithBundleSelector = @selector(ht_initWithBundleIdentifier:); Method origMethod = class_getInstanceMethod(self, orig_initWithBundleSelector); Method altMethod = class_getInstanceMethod(self, @selector(ht_initWithBundleIdentifier:)); class_addMethod(self, orig_initWithBundleSelector, class_getMethodImplementation(self, orig_initWithBundleSelector), method_getTypeEncoding(origMethod)); class_addMethod(self, alt_initWithBundleSelector, class_getMethodImplementation(self, alt_initWithBundleSelector), method_getTypeEncoding(altMethod)); method_exchangeImplementations(origMethod, altMethod); } - (instancetype)ht_initWithBundleIdentifier:(id)identifier { if (nil==identifier||NSNull.null==identifier) { return nil; } /* you can test, if give nil to this method ,100% crash!!!!*/ /* [self ht_initWithBundleIdentifier:nil] 100% crash!!!!*/ return [self ht_initWithBundleIdentifier:identifier]; } @end 
+3
source

Just adding UserNotifications.framework helped me.

  • Open project
  • Choose a target
  • Assembly steps
  • Binary link with libraries
  • Click "+"
  • UserNotifications.framework

Or check out this instruction http://docs.onemobilesdk.aol.com/ios-ad-sdk/adding-frameworks-xcode.html

0
source

Source: https://habr.com/ru/post/1272376/


All Articles