mirror of
https://github.com/zhigang1992/react-native-firebase.git
synced 2026-04-17 12:19:21 +08:00
[crashlytics][ios] Use FIRLibrary protocol functionality to detect default app configuration (fixes previous issue)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user