简体   繁体   中英

Firebase Crashlytics MacOS - all crashes under AppKit

I have an iOS app that is ported to MacOS. The app uses Firebase for Crashlytics. So far I managed to configure everything just fine, by creating a separate Mac target and separate Firebase project for that target. The problem is that the crashes I see in the console for the MacOS project are all under "AppKit". Example:

AppKit | -[NSApplication _crashOnException:] + 106

Not very informative, is it... Now, I can still get the crashing exception if I inspect the crashes and then go to 'Keys':

crash_info_entry_0 | Crashing on exception: *** -[__NSCFCalendar rangeOfUnit:startDate:interval:forDate:]: date cannot be nil

But with that all the different crashes are grouped together under that AppKit crash and so it is not very helpful.

I realise that this issue is due to the default behaviour of AppKit catching all exceptions on MacOS by default. Is there perhaps a better way to setup Crashlytics for MacOS, in order to get more granular reports, like on iOS and other platforms?

After a lot of research I found that there is no perfect solution to this. I tried overriding NSApplication and setting it as NSPrincipalClass, and even implemented Sentry instead - no success. But I found a way to bypass AppKit using method swizzling and FIRExceptionModel.

Note: Before anything, for Firebase Crashlytics to work on MacOS, you need the following in your AppDelegate's didFinishLaunchingWithOptions:

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults registerDefaults:@{@"NSApplicationCrashOnExceptions" : @"YES"}];

Then you need to create a category of NSApplication and swizzle the method _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]
    ];
    // Note: ExceptionModel will always be reported as a non-fatal.
    [[FIRCrashlytics crashlytics] recordExceptionModel:errorModel];
    [self reported__crashOnException:exception];
}

@end

This code as a gist: https://gist.github.com/sc941737/c0c4542401ce203142c93ddc9b05eb1f

This means however that the exceptions won't be reported as crashes, but as non-fatals. So I would recommend setting an extra custom key to filter crashes from non-fatals more easily. See Firebase docs for details: https://firebase.google.com/docs/crashlytics/customize-crash-reports?platform=ios

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM