Crashlytics doesn't work in iOS keyboard extension

976 views Asked by At

I'm using the latest version of the Fabric and Fabric/Crashlytics cocoapods (so, version 3.0.8 according to the debugger output) to integrate Crashlytics into an iOS keyboard extension. Recently, it simply stopped reporting crashes from the keyboard extension. I've checked both my code which initializes Crashlytics and the Crashlytics script build phase of my project, both are executed (and the build phase is in my keyboard extension's target).

It's hard to tell if this is related, but when I run the app I see Crashlytics try to submit crashes,

[Crashlytics:Crash:Reports] Submitting async /var/mobile/Containers/Data/PluginKitPlugin/[some-numbers]/Library/Caches/com.crashlytics.data/com.myCompnay.myApp.extension/v3/prepared/[some-more-numbers-idk-if-they're-supposed-to-be-secret].multipartmime

and then a corresponding number of messages reading

2015-06-25 09:22:33.063 com.myCompany.myApp.extension[5975:1649412] Attempted to create a task in a session that has been invalidated

leading me to believe that this is a bug in Crashlytics. The changelog for the latest version mentions an issue with background tasks

Fixed an issue that would incorrectly default to enabling NSURLSession background uploads in extensions

could this be related? Has anyone encountered and resolved this issue?

2

There are 2 answers

0
Ben Pious On

A few minutes after posting this, it occcured to me to actually set a symbolic breakpoint on [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:] instead of on the methods I had tried in the past. The breakpoint was hit in Crashlytics code.

To fix this, I swizzled backgroundSessionConfigurationWithIdentifer: with a method that returns the default configuration. Implementation is below:

static Class URLSessionClass;

@implementation NSURLSessionConfiguration (FixCrashlyticsBug)

+ (void)load {
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    URLSessionClass = object_getClass((id)self);
  });
}

+ (NSURLSessionConfiguration *)defaultSessionConfigurationWithIdentifier:(NSString *)__unused identifer {
  return [self defaultSessionConfiguration];
}

@end

@implementation CrashlyticsInterfaceManager

+ (void)startCrashlyticsFromExtension {
//Do the swizzle here instead of in load, so we don't do it in the container app as well
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    SEL originalSelector = @selector(defaultSessionConfigurationWithIdentifier:);
    SEL swizzledSelector = @selector(backgroundSessionConfigurationWithIdentifier:);
    Class class = URLSessionClass;
    Method swizzledMethod = class_getClassMethod(class, swizzledSelector);
    Method originalMethod = class_getClassMethod(class, originalSelector);
    BOOL didAddMethod = class_addMethod(class,
                                        originalSelector,
                                        method_getImplementation(swizzledMethod),
                                        method_getTypeEncoding(swizzledMethod));
    if (didAddMethod) {
      class_replaceMethod(class,
                          swizzledSelector,
                          method_getImplementation(originalMethod),
                          method_getTypeEncoding(originalMethod));
    } else {
      method_exchangeImplementations(originalMethod, swizzledMethod);
    }
    [Crashlytics startWithAPIKey:@"MyAPIKey"];
  });
}

@end
0
Teruto Yamasaki On

Clashlytics is distinguished by BundleIdentidfier, it seems to work. Main app , App Extension is a different Bundle Identifier.

In the same Bundle Identifier and Keyboard App, you will create another new project. If you set the icon for the Keyboard App Extension to the new project , it would be better. Icon will be used in Clashlytics Web page. 

Install clashlytics to the newly created project, and complete. Now , it also works with the original Project. When you are finished , you can delete new project.

I worked in this way.