我有一个移植到MacOS的iOS应用程序。该应用程序使用Firebase for Crashlytics。到目前为止,通过创建一个单独的Mac目标和为该目标创建单独的Firebase项目,我成功地配置好了一切。问题是,我在MacOS项目的控制台中看到的崩溃都在"AppKit“下。示例:
AppKit | -[NSApplication _crashOnException:] + 106
信息不是很丰富,是不是...现在,如果我检查崩溃,然后转到“Keys”,我仍然可以得到crashes异常:
crash_info_entry_0 | Crashing on exception: *** -[__NSCFCalendar rangeOfUnit:startDate:interval:forDate:]: date cannot be nil
但是,所有不同的崩溃都被分组到那个AppKit crash下,所以它不是很有帮助。
我意识到这个问题是由于AppKit在默认情况下捕获MacOS上的所有异常的默认行为造成的。有没有更好的方法来为MacOS设置Crashlytics,以便获得更细粒度的报告,就像在iOS和其他平台上一样?
发布于 2021-06-02 19:42:20
经过大量的研究,我发现这个问题没有完美的解决方案。我尝试重写NSApplication并将其设置为NSPrincipalClass,甚至实现了Sentry -没有成功。但是我找到了一种使用方法swizzling和FIRExceptionModel绕过AppKit的方法。
注意:首先,为了让Firebase Crashlytics在MacOS上工作,你需要在你的AppDelegate的didFinishLaunchingWithOptions中包含以下内容:
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; [userDefaults registerDefaults:@{@"NSApplicationCrashOnExceptions" : @"YES"}];
然后,您需要创建一个NSApplication类别并混合使用_crashOnException方法:
#import <objc/runtime.h> #import "NSApplication+CrashReport.h" #import <FIRCrashlytics.h> @implementation NSApplication (CrashReport) +(void)load { static dispatch_once_t once_token; dispatch_once(&once_token, ^{ SEL crashOnExceptionSelector = @selector(_crashOnException:); // Ignore 'Undeclared selector' warning. SEL crashOnExceptionReporterSelector = @selector(reported__crashOnException:); Method originalMethod = class_getInstanceMethod(self, crashOnExceptionSelector); Method extendedMethod = class_getInstanceMethod(self, crashOnExceptionReporterSelector); method_exchangeImplementations(originalMethod, extendedMethod); - (void)reported__crashOnException:(NSException*)exception { NSArray<NSString*> *stacktrace = [exception callStackSymbols]; [[FIRCrashlytics crashlytics]setCustomValue:stacktrace forKey:@"mac_os_stacktrace"]; FIRExceptionModel *errorModel = [FIRExceptionModel exceptionModelWithName:exception.name reason:exception.reason]; // The below stacktrace is hardcoded as an example, in an actual solution you should parse the stacktrace array entries. errorModel.stackTrace = @[ [FIRStackFrame stackFrameWithSymbol:@"This stacktrace is fabricated as a proof of concept" file:@"Hello from Serge" line:2021], [FIRStackFrame stackFrameWithSymbol:@"__exceptionPreprocess" file:@"CoreFoundation" line:250], [FIRStackFrame stackFrameWithSymbol:@"objc_exception_throw" file:@"libobjc.A.dylib" line:48], [FIRStackFrame stackFrameWithSymbol:@"-[__NSCFCalendar rangeOfUnit:startDate:interval:forDate:]" file:@"CoreFoundation" line:453]