iOS 11 crashing with bundleProxy != nil error on using UNUserNotificationCenter

心不动则不痛 提交于 2019-12-03 12:38:55

I'm not sure if this is going to work for everyone, however I've figured it out for my use case. I had created a framework that the iOS app used. This framework was using UNUserNotificationCenter to setup alerts. It seems for some reason, the 'bundle' does not get correctly initialised when this code is used from inside a framework. Sometimes it works, sometimes it doesn't. This bundleProxy, by the sound of things, is some kind of a proxy that the notification framework relies on. Since the code is executing from inside of a framework, perhaps this bundle is not found at runtime and the system returns nil. I've had this issue in general when trying to load resources from the Framework where the bundle location isn't correct.

Any way, the solution for me was to store a reference to [UNUserNotificationCenter currentNotificationCenter] in the app's delegate at launch, and then pass this to any method that wanted to use it. By the time the app has finished launching, this proxy seems to load correctly if the calling code is the app's binary itself. This seems to have fixed it for me.

imqiuhang

Why does [UNUserNotificationCenter currentNotificationCenter] crash sometimes?

According to the crash stack trace, the bundleIdentifier is nil in the UNUserNotificationCenter's private init Method and an exception is raised. I don't know why.

Unfortunately, the method is called in a dispatch_once context, so we can't reproduce this crash easily. First,I tried to use NSBundle's Method: NSBundle.mainBundle.bundleIdentifier, but it failed. I guess the system did not use this Method to get bundleIdentifier, so I tried to use UNUserNotificationCenter's private init Method initWithBundleIdentifier:(String),it worked and tried to pass nil to this method, which caused a crash 100% of the time!!!! So we can use this method when file loads, and return nil if bundleIdentifier==nil, I hope this helps you.

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

    /* UNUserNotificationCenter + Hack */
@implementation UNUserNotificationCenter (Hack)

+ (void)load {
    static dispatch_once_t _onceToken;
    dispatch_once(&_onceToken, ^{
        [self safeHook];
    });
}

+ (void)safeHook {

    /*hook UNUserNotificationCenter's 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

OneSignal experienced this as well. Their fix was to inspect the current process name and if it contained IBDesignable in it to return early. It worked for me as well.

GitHub issue

Fix commit

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!