2
0
mirror of synced 2025-01-10 14:16:27 +00:00
Evan Bacon cca3c13d2d Fixed Deadlock
Running this in a detached expo app can sometimes deadlock from thread issues.
I've replaced `dispatch_sync(dispatch_get_main_queue(), ^{});`  with `RCTUnsafeExecuteOnMainQueueSync(^{});` to fix this.

I only hit the error in the `RNFirebaseStorage.m` but it seems like the `RNFirebaseAnalytics.m` and `RNFirebase.m` modules could also have this same issue.

`RCTUnsafeExecuteOnMainQueueSync` checks to see if the method is being executed on the main thread before trying to sync to the main thread. If you try to sync on the main thread whilst on the main thread, you hit a deadlock.

You can read more about it here: https://stackoverflow.com/questions/12379059/why-is-this-dispatch-sync-call-freezing?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa

The only testing I did was in a seperate detached ExpoKit project. Running this function would cause the crash.
```js
await firebase
      .storage()
      .ref(uploadUri)
      .putFile(uri);
```
2018-06-08 14:44:48 -07:00

123 lines
3.8 KiB
Objective-C

#import "RNFirebase.h"
#import "RNFirebaseUtil.h"
#import <FirebaseCore/FirebaseCore.h>
#import <React/RCTUtils.h>
@implementation RNFirebase
RCT_EXPORT_MODULE(RNFirebase);
- (id)init {
self = [super init];
if (self != nil) {
NSLog(@"Setting up RNFirebase instance");
}
return self;
}
- (NSArray<NSString *> *)supportedEvents {
return @[];
}
/**
* Initialize a new firebase app instance or ignore if currently exists.
* @return
*/
RCT_EXPORT_METHOD(initializeApp:
(NSString *) appDisplayName
options:
(NSDictionary *) options
callback:
(RCTResponseSenderBlock) callback) {
RCTUnsafeExecuteOnMainQueueSync(^{
FIRApp *existingApp = [RNFirebaseUtil getApp:appDisplayName];
if (!existingApp) {
FIROptions *firOptions = [[FIROptions alloc] initWithGoogleAppID:[options valueForKey:@"appId"] GCMSenderID:[options valueForKey:@"messagingSenderId"]];
firOptions.APIKey = [options valueForKey:@"apiKey"];
firOptions.projectID = [options valueForKey:@"projectId"];
firOptions.clientID = [options valueForKey:@"clientId"];
firOptions.trackingID = [options valueForKey:@"trackingId"];
firOptions.databaseURL = [options valueForKey:@"databaseURL"];
firOptions.storageBucket = [options valueForKey:@"storageBucket"];
firOptions.androidClientID = [options valueForKey:@"androidClientId"];
firOptions.deepLinkURLScheme = [options valueForKey:@"deepLinkURLScheme"];
firOptions.bundleID = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"];
NSString *appName = [RNFirebaseUtil getAppName:appDisplayName];
[FIRApp configureWithName:appName options:firOptions];
}
callback(@[[NSNull null], @{@"result": @"success"}]);
});
}
/**
* Delete a firebase app
* @return
*/
RCT_EXPORT_METHOD(deleteApp:
(NSString *) appDisplayName
resolver:
(RCTPromiseResolveBlock) resolve
rejecter:
(RCTPromiseRejectBlock) reject) {
FIRApp *existingApp = [RNFirebaseUtil getApp:appDisplayName];
if (!existingApp) {
return resolve([NSNull null]);
}
[existingApp deleteApp:^(BOOL success) {
if (success) {
resolve([NSNull null]);
} else {
reject(@"app/delete-app-failed", @"Failed to delete the specified app.", nil);
}
}];
}
/**
* React native constant exports - exports native firebase apps mainly
* @return NSDictionary
*/
- (NSDictionary *)constantsToExport {
NSMutableDictionary *constants = [NSMutableDictionary new];
NSDictionary *firApps = [FIRApp allApps];
NSMutableArray *appsArray = [NSMutableArray new];
for (id key in firApps) {
NSMutableDictionary *appOptions = [NSMutableDictionary new];
FIRApp *firApp = firApps[key];
FIROptions *firOptions = [firApp options];
appOptions[@"name"] = [RNFirebaseUtil getAppDisplayName:firApp.name];
appOptions[@"apiKey"] = firOptions.APIKey;
appOptions[@"appId"] = firOptions.googleAppID;
appOptions[@"databaseURL"] = firOptions.databaseURL;
appOptions[@"messagingSenderId"] = firOptions.GCMSenderID;
appOptions[@"projectId"] = firOptions.projectID;
appOptions[@"storageBucket"] = firOptions.storageBucket;
// missing from android sdk / ios only:
appOptions[@"clientId"] = firOptions.clientID;
appOptions[@"trackingId"] = firOptions.trackingID;
appOptions[@"androidClientID"] = firOptions.androidClientID;
appOptions[@"deepLinkUrlScheme"] = firOptions.deepLinkURLScheme;
[appsArray addObject:appOptions];
}
constants[@"apps"] = appsArray;
return constants;
}
+ (BOOL)requiresMainQueueSetup
{
return YES;
}
@end