[crashlytics][ios] Use FIRLibrary protocol functionality to detect default app configuration (fixes previous issue)

This commit is contained in:
Salakar
2019-07-30 05:30:12 +01:00
parent 05f93ed4cd
commit 6afd570eb4
3 changed files with 164 additions and 158 deletions

View File

@@ -16,9 +16,18 @@
*/
#import <Foundation/Foundation.h>
#import <FirebaseCore/FIRLibrary.h>
@interface RNFBCrashlyticsInitProvider : NSObject
@interface RNFBCrashlyticsInitProvider : NSObject <FIRLibrary>
+ (BOOL)isCrashlyticsCollectionEnabled;
/// Returns one or more FIRComponents that will be registered in
/// FIRApp and participate in dependency resolution and injection.
+ (NSArray<FIRComponent *> *)componentsToRegister;
/// Implement this method if the library needs notifications for lifecycle events. This method is
/// called when the developer calls `FirebaseApp.configure()`.
+ (void)configureWithApp:(FIRApp *)app;
@end

View File

@@ -15,14 +15,12 @@
*
*/
#import <FirebaseCore/FIRAppInternal.h>
#import <Firebase/Firebase.h>
#import "RNFBCrashlyticsInitProvider.h"
#import "Crashlytics.h"
#import "RNFBPreferences.h"
#import "RNFBJSON.h"
#import "RNFBMeta.h"
#import "FIROptions.h"
#import "FIRApp.h"
#import "Fabric.h"
NSString *const KEY_CRASHLYTICS_DEBUG_ENABLED = @"crashlytics_debug_enabled";
@@ -30,43 +28,41 @@ NSString *const KEY_CRASHLYTICS_AUTO_COLLECTION_ENABLED = @"crashlytics_auto_col
@implementation RNFBCrashlyticsInitProvider
+ (void)load {
if ([self isCrashlyticsCollectionEnabled]) {
// TODO(salakar): Without dispatch `[FIRApp configure];` breaks Detox and causes a crash on start (cannot read a userDefaults key)
dispatch_async(dispatch_get_main_queue(), ^{
FIROptions *defaultFirebaseOptions = [FIROptions defaultOptions];
if (defaultFirebaseOptions == nil) return;
+ (void)load {
if ([self isCrashlyticsCollectionEnabled]) {
[FIRApp registerInternalLibrary:self withName:@"react-native-firebase-crashlytics" withVersion:@"6.0.0"];
}
}
NSString *googleAppID = defaultFirebaseOptions.googleAppID;
if (googleAppID == nil) return;
+ (BOOL)isCrashlyticsCollectionEnabled {
BOOL enabled;
// TODO(salakar): Option to disable auto init
// TODO(salakar): If disabled; when the default app is initialized from JS land then init crashlytics (register a block handler somehow in RNFBApp?)
if ([FIRApp defaultApp] == nil) {
[FIRApp configure];
}
if ([[RNFBJSON shared] contains:KEY_CRASHLYTICS_DEBUG_ENABLED]) {
[Crashlytics sharedInstance].debugMode = [[RNFBJSON shared] getBooleanValue:KEY_CRASHLYTICS_DEBUG_ENABLED defaultValue:NO];
}
[Fabric with:@[[Crashlytics class]]];
});
}
if ([[RNFBPreferences shared] contains:KEY_CRASHLYTICS_AUTO_COLLECTION_ENABLED]) {
enabled = [[RNFBPreferences shared] getBooleanValue:KEY_CRASHLYTICS_AUTO_COLLECTION_ENABLED defaultValue:YES];
} else if ([[RNFBJSON shared] contains:KEY_CRASHLYTICS_AUTO_COLLECTION_ENABLED]) {
enabled = [[RNFBJSON shared] getBooleanValue:KEY_CRASHLYTICS_AUTO_COLLECTION_ENABLED defaultValue:YES];
} else {
enabled = [RNFBMeta getBooleanValue:KEY_CRASHLYTICS_AUTO_COLLECTION_ENABLED defaultValue:YES];
}
+ (BOOL)isCrashlyticsCollectionEnabled {
BOOL enabled;
return enabled;
}
if ([[RNFBPreferences shared] contains:KEY_CRASHLYTICS_AUTO_COLLECTION_ENABLED]) {
enabled = [[RNFBPreferences shared] getBooleanValue:KEY_CRASHLYTICS_AUTO_COLLECTION_ENABLED defaultValue:YES];
} else if ([[RNFBJSON shared] contains:KEY_CRASHLYTICS_AUTO_COLLECTION_ENABLED]) {
enabled = [[RNFBJSON shared] getBooleanValue:KEY_CRASHLYTICS_AUTO_COLLECTION_ENABLED defaultValue:YES];
} else {
enabled = [RNFBMeta getBooleanValue:KEY_CRASHLYTICS_AUTO_COLLECTION_ENABLED defaultValue:YES];
+ (NSArray<FIRComponent *> *)componentsToRegister {
return @[];
}
+ (void)configureWithApp:(FIRApp *)app {
if ([app isDefaultApp]) {
// TODO(salakar): Option to disable auto init
// TODO(salakar): If disabled; when the default app is initialized from JS land then init crashlytics (register a block handler somehow in RNFBApp?)
if ([[RNFBJSON shared] contains:KEY_CRASHLYTICS_DEBUG_ENABLED]) {
[Crashlytics sharedInstance].debugMode = [[RNFBJSON shared] getBooleanValue:KEY_CRASHLYTICS_DEBUG_ENABLED defaultValue:NO];
}
return enabled;
[Fabric with:@[[Crashlytics class]]];
}
}
@end

View File

@@ -21,146 +21,147 @@
#import "RNFBCrashlyticsInitProvider.h"
#import "RCTConvert.h"
#import "RNFBPreferences.h"
#import "Crashlytics.h"
#import <Firebase/Firebase.h>
#import <Crashlytics/Crashlytics.h>
@implementation RNFBCrashlyticsModule
#pragma mark -
#pragma mark Module Setup
RCT_EXPORT_MODULE();
RCT_EXPORT_MODULE();
- (NSDictionary *)constantsToExport {
NSMutableDictionary *constants = [NSMutableDictionary new];
constants[@"isCrashlyticsCollectionEnabled"] = @([RCTConvert BOOL:@([RNFBCrashlyticsInitProvider isCrashlyticsCollectionEnabled])]);
return constants;
}
- (NSDictionary *)constantsToExport {
NSMutableDictionary *constants = [NSMutableDictionary new];
constants[@"isCrashlyticsCollectionEnabled"] = @([RCTConvert BOOL:@([RNFBCrashlyticsInitProvider isCrashlyticsCollectionEnabled])]);
return constants;
}
+ (BOOL)requiresMainQueueSetup {
return NO;
}
+ (BOOL)requiresMainQueueSetup {
return NO;
}
#pragma mark -
#pragma mark Firebase Crashlytics Methods
RCT_EXPORT_METHOD(crash) {
[[Crashlytics sharedInstance] crash];
RCT_EXPORT_METHOD(crash) {
[[Crashlytics sharedInstance] crash];
}
RCT_EXPORT_METHOD(log:
(NSString *) message) {
CLS_LOG(@"%@", message);
}
RCT_EXPORT_METHOD(logPromise:
(NSString *) message
resolver:
(RCTPromiseResolveBlock) resolve
rejecter:
(RCTPromiseRejectBlock) reject) {
CLS_LOG(@"%@", message);
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(setAttribute:
(NSString *) key
value:
(NSString *) value
resolver:
(RCTPromiseResolveBlock) resolve
rejecter:
(RCTPromiseRejectBlock) reject) {
[[Crashlytics sharedInstance] setObjectValue:value forKey:key];
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(setAttributes:
(NSDictionary *) attributes
resolver:
(RCTPromiseResolveBlock) resolve
rejecter:
(RCTPromiseRejectBlock) reject) {
NSArray *keys = [attributes allKeys];
for (NSString *key in keys) {
[[Crashlytics sharedInstance] setObjectValue:attributes[key] forKey:key];
}
RCT_EXPORT_METHOD(log:
(NSString *) message) {
CLS_LOG(@"%@", message);
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(setUserId:
(NSString *) userId
resolver:
(RCTPromiseResolveBlock) resolve
rejecter:
(RCTPromiseRejectBlock) reject) {
[[Crashlytics sharedInstance] setUserIdentifier:userId];
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(setUserName:
(NSString *) userName
resolver:
(RCTPromiseResolveBlock) resolve
rejecter:
(RCTPromiseRejectBlock) reject) {
[[Crashlytics sharedInstance] setUserName:userName];
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(setUserEmail:
(NSString *) userEmail
resolver:
(RCTPromiseResolveBlock) resolve
rejecter:
(RCTPromiseRejectBlock) reject) {
[[Crashlytics sharedInstance] setUserEmail:userEmail];
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(recordError:
(NSDictionary *) jsErrorDict) {
[self recordJavaScriptError:jsErrorDict];
}
RCT_EXPORT_METHOD(recordErrorPromise:
(NSDictionary *) jsErrorDict
resolver:
(RCTPromiseResolveBlock) resolve
rejecter:
(RCTPromiseRejectBlock) reject) {
[self recordJavaScriptError:jsErrorDict];
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(setCrashlyticsCollectionEnabled:
(BOOL) enabled) {
[[RNFBPreferences shared] setBooleanValue:@"crashlytics_auto_collection_enabled" boolValue:enabled];
}
- (void)recordJavaScriptError:(NSDictionary *)jsErrorDict {
NSString *message = jsErrorDict[@"message"];
NSDictionary *stackFrames = jsErrorDict[@"frames"];
NSMutableArray *customFrames = [[NSMutableArray alloc] init];
BOOL isUnhandledPromiseRejection = [jsErrorDict[@"isUnhandledRejection"] boolValue];
for (NSDictionary *stackFrame in stackFrames) {
CLSStackFrame *customFrame = [CLSStackFrame stackFrame];
[customFrame setSymbol:stackFrame[@"fn"]];
[customFrame setFileName:stackFrame[@"file"]];
[customFrame setLibrary:stackFrame[@"src"]];
[customFrame setOffset:(uint64_t) [stackFrame[@"col"] intValue]];
[customFrame setLineNumber:(uint32_t) [stackFrame[@"line"] intValue]];
[customFrames addObject:customFrame];
}
RCT_EXPORT_METHOD(logPromise:
(NSString *) message
resolver:
(RCTPromiseResolveBlock) resolve
rejecter:
(RCTPromiseRejectBlock) reject) {
CLS_LOG(@"%@", message);
resolve([NSNull null]);
NSString *name = @"JavaScriptError";
if (isUnhandledPromiseRejection) {
name = @"UnhandledPromiseRejection";
}
RCT_EXPORT_METHOD(setAttribute:
(NSString *) key
value:
(NSString *) value
resolver:
(RCTPromiseResolveBlock) resolve
rejecter:
(RCTPromiseRejectBlock) reject) {
[[Crashlytics sharedInstance] setObjectValue:value forKey:key];
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(setAttributes:
(NSDictionary *) attributes
resolver:
(RCTPromiseResolveBlock) resolve
rejecter:
(RCTPromiseRejectBlock) reject) {
NSArray *keys = [attributes allKeys];
for (NSString *key in keys) {
[[Crashlytics sharedInstance] setObjectValue:attributes[key] forKey:key];
}
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(setUserId:
(NSString *) userId
resolver:
(RCTPromiseResolveBlock) resolve
rejecter:
(RCTPromiseRejectBlock) reject) {
[[Crashlytics sharedInstance] setUserIdentifier:userId];
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(setUserName:
(NSString *) userName
resolver:
(RCTPromiseResolveBlock) resolve
rejecter:
(RCTPromiseRejectBlock) reject) {
[[Crashlytics sharedInstance] setUserName:userName];
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(setUserEmail:
(NSString *) userEmail
resolver:
(RCTPromiseResolveBlock) resolve
rejecter:
(RCTPromiseRejectBlock) reject) {
[[Crashlytics sharedInstance] setUserEmail:userEmail];
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(recordError:
(NSDictionary *) jsErrorDict) {
[self recordJavaScriptError:jsErrorDict];
}
RCT_EXPORT_METHOD(recordErrorPromise:
(NSDictionary *) jsErrorDict
resolver:
(RCTPromiseResolveBlock) resolve
rejecter:
(RCTPromiseRejectBlock) reject) {
[self recordJavaScriptError:jsErrorDict];
resolve([NSNull null]);
}
RCT_EXPORT_METHOD(setCrashlyticsCollectionEnabled:
(BOOL) enabled) {
[[RNFBPreferences shared] setBooleanValue:@"crashlytics_auto_collection_enabled" boolValue:enabled];
}
- (void)recordJavaScriptError:(NSDictionary *)jsErrorDict {
NSString *message = jsErrorDict[@"message"];
NSDictionary *stackFrames = jsErrorDict[@"frames"];
NSMutableArray *customFrames = [[NSMutableArray alloc] init];
BOOL isUnhandledPromiseRejection = [jsErrorDict[@"isUnhandledRejection"] boolValue];
for (NSDictionary *stackFrame in stackFrames) {
CLSStackFrame *customFrame = [CLSStackFrame stackFrame];
[customFrame setSymbol:stackFrame[@"fn"]];
[customFrame setFileName:stackFrame[@"file"]];
[customFrame setLibrary:stackFrame[@"src"]];
[customFrame setOffset:(uint64_t) [stackFrame[@"col"] intValue]];
[customFrame setLineNumber:(uint32_t) [stackFrame[@"line"] intValue]];
[customFrames addObject:customFrame];
}
NSString *name = @"JavaScriptError";
if (isUnhandledPromiseRejection) {
name = @"UnhandledPromiseRejection";
}
[[Crashlytics sharedInstance] recordCustomExceptionName:name reason:message frameArray:customFrames];
}
[[Crashlytics sharedInstance] recordCustomExceptionName:name reason:message frameArray:customFrames];
}
@end