iOS 11 在使用 UNUserNotificationCenter 时因 bundleProxy 崩溃!= nil 错误
Posted
技术标签:
【中文标题】iOS 11 在使用 UNUserNotificationCenter 时因 bundleProxy 崩溃!= nil 错误【英文标题】:iOS 11 crashing with bundleProxy != nil error on using UNUserNotificationCenter 【发布时间】:2018-03-17 15:38:41 【问题描述】:以下代码行是我们的应用突然开始在 ios 11 / 11.0.1 / 11.0.2 / 11.1.1 / 11.2.2 上对某些用户崩溃的地方:
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
我们在didFinishLaunchingWithOptions
中有这个。崩溃报告说:
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]
它显然来自 iOS。还有其他人遇到同样的错误吗?知道发生了什么吗?
【问题讨论】:
你弄明白了吗? 不,仍然看到神秘的崩溃 @SamJarman 我想是的 【参考方案1】:我不确定这是否适用于所有人,但我已经为我的用例找到了答案。我创建了一个 iOS 应用程序使用的框架。这个框架使用UNUserNotificationCenter
来设置警报。似乎由于某种原因,当从框架内部使用此代码时,“捆绑包”没有正确初始化。有时有效,有时无效。从事物的声音来看,这个bundleProxy
是通知框架所依赖的某种代理。由于代码是从框架内部执行的,因此可能在运行时找不到此捆绑包并且系统返回 nil。在尝试从捆绑包位置不正确的框架中加载资源时,我通常会遇到此问题。
无论如何,我的解决方案是在启动时在应用程序的委托中存储对[UNUserNotificationCenter currentNotificationCenter]
的引用,然后将其传递给任何想要使用它的方法。当应用程序完成启动时,如果调用代码是应用程序的二进制文件本身,则此 proxy
似乎可以正确加载。这似乎已经为我解决了。
【讨论】:
我遇到了同样的问题 bundleProxy != nil 断言失败。导致它的调用是 AppDelegate.didFinishLaunching 中的 UNUserNotificationCenter.current(),这似乎是您的建议。你能发布你的代码吗? 否,但如前所述,请确保您的代码未在框架内运行。如果是,你需要从你的应用的委托中传递一个引用。 它在一个框架中,在应用程序的委托中是我试图获取 UNUserNotificationCenter.current() 的地方,但那是调用失败。 项目中没有AppDelegate。我在对框架/SDK 项目进行单元测试时遇到此错误。 @Anees 然后在单元测试设置方法中创建并初始化它,可能是类设置方法【参考方案2】:为什么
[UNUserNotificationCenter currentNotificationCenter]
有时会崩溃?
根据崩溃堆栈跟踪,UNUserNotificationCenter 的私有 init 方法中的 bundleIdentifier 为 nil,并引发了异常。我不知道为什么。
不幸的是,该方法是在dispatch_once
上下文中调用的,因此我们无法轻松重现此崩溃。首先,我尝试使用NSBundle的方法:NSBundle.mainBundle.bundleIdentifier
,但是失败了。估计系统没有使用这个方法获取bundleIdentifier,所以我尝试使用UNUserNotificationCenter的私有init方法initWithBundleIdentifier:(String)
,成功了,并尝试将nil传递给这个方法,导致100%的时候crash!!!所以我们可以在文件加载的时候使用这个方法,如果bundleIdentifier==nil
返回nil,希望对你有帮助。
----------------代码-----------------
/* 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
【讨论】:
这个解决方案很棒,但并没有完全解决问题。使用此方法后,我的一些用户仍然会偶尔遇到崩溃。崩溃问题是Invalid parameter not satisfying: bundleProxy != nil
【参考方案3】:
OneSignal 也经历过这种情况。他们的解决方法是检查当前进程名称,以及它是否包含IBDesignable
以便提前返回。它也对我有用。
GitHub issue
Fix commit
【讨论】:
【参考方案4】:对于那些在这里使用 PacketTunnelProvider NetworkExtension 的人,如果您从 stopTunnelWithReason
调用它,可能会发生这种情况。而是先获取currentNotificationCenter
并保存。
【讨论】:
以上是关于iOS 11 在使用 UNUserNotificationCenter 时因 bundleProxy 崩溃!= nil 错误的主要内容,如果未能解决你的问题,请参考以下文章
iOS 11 在使用 UNUserNotificationCenter 时因 bundleProxy 崩溃!= nil 错误
iOS 11 - 使用大标题模式时的 UINavigationItem titleView
iOS 上的 IDFA 和 IDFV 仍在使用 XCode 11 构建