Merge pull request #729 from invertase/master

Ignore
This commit is contained in:
Michael Diarmid 2018-01-06 12:38:11 +00:00 committed by GitHub
commit 59d9bca7b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
61 changed files with 1427 additions and 1315 deletions

View File

@ -50,7 +50,7 @@ module.system=haste
emoji=true emoji=true
munge_underscores=false munge_underscores=true
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
@ -69,6 +69,7 @@ suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(5[0-6]\\|[1
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(5[0-6]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(5[0-6]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
suppress_comment=\\(.\\|\n\\)*\\$FlowBug.*
unsafe.enable_getters_and_setters=true unsafe.enable_getters_and_setters=true

View File

@ -1,14 +1,13 @@
<!--- <!---
- BEFORE YOU MAKE AN ISSUE - BEFORE YOU MAKE AN ISSUE
-->
<!--- The issue list of this repo is exclusively for bug reports.
1) If you're trying to request a feature then please do so via our request board:
https://react-native-firebase.canny.io/feature-requests
--->
<!--- 1) For feature requests, please use our Canny board: https://react-native-firebase.canny.io/feature-requests
2) If this is a setup issue then please make sure you've correctly followed the setup guides, most setup issues such as 'duplicate dex files', 'default app has not been initialized' etc are all down to an incorrect setup as the guides haven't been correctly followed.
2) For questions and support please use our Discord chat: https://discord.gg/t6bdqMs or Stack Overflow: https://stackoverflow.com/questions/tagged/react-native-firebase
3) If this is a setup issue then please make sure you've correctly followed the setup guides, most setup issues such as 'duplicate dex files', 'default app has not been initialized' etc are all down to an incorrect setup as the guides haven't been correctly followed.
--> -->
### Issue ### Issue
@ -38,4 +37,4 @@
6. Firebase Module: 6. Firebase Module:
<!-- Love react-native-firebase? Please consider supporting our collective: <!-- Love react-native-firebase? Please consider supporting our collective:
👉 https://opencollective.com/react-native-firebase/donate --> 👉 https://opencollective.com/react-native-firebase/donate -->

View File

@ -1,4 +1,5 @@
#import "RNFirebase.h" #import "RNFirebase.h"
#import "RNFirebaseUtil.h"
#import <FirebaseCore/FirebaseCore.h> #import <FirebaseCore/FirebaseCore.h>
@implementation RNFirebase @implementation RNFirebase
@ -21,14 +22,14 @@ RCT_EXPORT_MODULE(RNFirebase);
* @return * @return
*/ */
RCT_EXPORT_METHOD(initializeApp: RCT_EXPORT_METHOD(initializeApp:
(NSString *) appName (NSString *) appDisplayName
options: options:
(NSDictionary *) options (NSDictionary *) options
callback: callback:
(RCTResponseSenderBlock) callback) { (RCTResponseSenderBlock) callback) {
dispatch_sync(dispatch_get_main_queue(), ^{ dispatch_sync(dispatch_get_main_queue(), ^{
FIRApp *existingApp = [FIRApp appNamed:appName]; FIRApp *existingApp = [RNFirebaseUtil getApp:appDisplayName];
if (!existingApp) { if (!existingApp) {
FIROptions *firOptions = [[FIROptions alloc] initWithGoogleAppID:[options valueForKey:@"appId"] GCMSenderID:[options valueForKey:@"messagingSenderId"]]; FIROptions *firOptions = [[FIROptions alloc] initWithGoogleAppID:[options valueForKey:@"appId"] GCMSenderID:[options valueForKey:@"messagingSenderId"]];
@ -43,6 +44,7 @@ RCT_EXPORT_METHOD(initializeApp:
firOptions.deepLinkURLScheme = [options valueForKey:@"deepLinkURLScheme"]; firOptions.deepLinkURLScheme = [options valueForKey:@"deepLinkURLScheme"];
firOptions.bundleID = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"]; firOptions.bundleID = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"];
NSString *appName = [RNFirebaseUtil getAppName:appDisplayName];
[FIRApp configureWithName:appName options:firOptions]; [FIRApp configureWithName:appName options:firOptions];
} }
@ -55,13 +57,13 @@ RCT_EXPORT_METHOD(initializeApp:
* @return * @return
*/ */
RCT_EXPORT_METHOD(deleteApp: RCT_EXPORT_METHOD(deleteApp:
(NSString *) appName (NSString *) appDisplayName
resolver: resolver:
(RCTPromiseResolveBlock) resolve (RCTPromiseResolveBlock) resolve
rejecter: rejecter:
(RCTPromiseRejectBlock) reject) { (RCTPromiseRejectBlock) reject) {
FIRApp *existingApp = [FIRApp appNamed:appName]; FIRApp *existingApp = [RNFirebaseUtil getApp:appDisplayName];
if (!existingApp) { if (!existingApp) {
return resolve([NSNull null]); return resolve([NSNull null]);
@ -90,7 +92,7 @@ RCT_EXPORT_METHOD(deleteApp:
NSMutableDictionary *appOptions = [NSMutableDictionary new]; NSMutableDictionary *appOptions = [NSMutableDictionary new];
FIRApp *firApp = firApps[key]; FIRApp *firApp = firApps[key];
FIROptions *firOptions = [firApp options]; FIROptions *firOptions = [firApp options];
appOptions[@"name"] = firApp.name; appOptions[@"name"] = [RNFirebaseUtil getAppDisplayName:firApp.name];
appOptions[@"apiKey"] = firOptions.APIKey; appOptions[@"apiKey"] = firOptions.APIKey;
appOptions[@"appId"] = firOptions.googleAppID; appOptions[@"appId"] = firOptions.googleAppID;
appOptions[@"databaseURL"] = firOptions.databaseURL; appOptions[@"databaseURL"] = firOptions.databaseURL;

View File

@ -3,11 +3,15 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import <React/RCTEventEmitter.h> #import <React/RCTEventEmitter.h>
#import <Firebase.h>
@interface RNFirebaseUtil : NSObject @interface RNFirebaseUtil : NSObject
+ (FIRApp *)getApp:(NSString *)appDisplayName;
+ (NSString *)getAppName:(NSString *)appDisplayName;
+ (NSString *)getAppDisplayName:(NSString *)appName;
+ (void)sendJSEvent:(RCTEventEmitter *)emitter name:(NSString *)name body:(NSDictionary *)body; + (void)sendJSEvent:(RCTEventEmitter *)emitter name:(NSString *)name body:(NSDictionary *)body;
+ (void)sendJSEventWithAppName:(RCTEventEmitter *)emitter appName:(NSString *)appName name:(NSString *)name body:(NSDictionary *)body; + (void)sendJSEventWithAppName:(RCTEventEmitter *)emitter app:(FIRApp *)app name:(NSString *)name body:(NSDictionary *)body;
@end @end

View File

@ -2,6 +2,28 @@
@implementation RNFirebaseUtil @implementation RNFirebaseUtil
static NSString *const DEFAULT_APP_DISPLAY_NAME = @"[DEFAULT]";
static NSString *const DEFAULT_APP_NAME = @"__FIRAPP_DEFAULT";
+ (FIRApp *)getApp:(NSString *)appDisplayName {
NSString *appName = [RNFirebaseUtil getAppName:appDisplayName];
return [FIRApp appNamed:appName];
}
+ (NSString *)getAppName:(NSString *)appDisplayName {
if ([appDisplayName isEqualToString:DEFAULT_APP_DISPLAY_NAME]) {
return DEFAULT_APP_NAME;
}
return appDisplayName;
}
+ (NSString *)getAppDisplayName:(NSString *)appName {
if ([appName isEqualToString:DEFAULT_APP_NAME]) {
return DEFAULT_APP_DISPLAY_NAME;
}
return appName;
}
+ (void)sendJSEvent:(RCTEventEmitter *)emitter name:(NSString *)name body:(NSDictionary *)body { + (void)sendJSEvent:(RCTEventEmitter *)emitter name:(NSString *)name body:(NSDictionary *)body {
@try { @try {
// TODO: Temporary fix for https://github.com/invertase/react-native-firebase/issues/233 // TODO: Temporary fix for https://github.com/invertase/react-native-firebase/issues/233
@ -14,10 +36,10 @@
} }
} }
+ (void)sendJSEventWithAppName:(RCTEventEmitter *)emitter appName:(NSString *)appName name:(NSString *)name body:(NSDictionary *)body { + (void)sendJSEventWithAppName:(RCTEventEmitter *)emitter app:(FIRApp *)app name:(NSString *)name body:(NSDictionary *)body {
// Add the appName to the body // Add the appName to the body
NSMutableDictionary *newBody = [body mutableCopy]; NSMutableDictionary *newBody = [body mutableCopy];
newBody[@"appName"] = appName; newBody[@"appName"] = [RNFirebaseUtil getAppDisplayName:app.name];
[RNFirebaseUtil sendJSEvent:emitter name:name body:newBody]; [RNFirebaseUtil sendJSEvent:emitter name:name body:newBody];
} }

View File

@ -23,19 +23,19 @@ RCT_EXPORT_MODULE();
*/ */
RCT_EXPORT_METHOD(addAuthStateListener: RCT_EXPORT_METHOD(addAuthStateListener:
(NSString *) appName) { (NSString *) appDisplayName) {
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
if (![_authStateHandlers valueForKey:appName]) { if (![_authStateHandlers valueForKey:firApp.name]) {
FIRApp *firApp = [FIRApp appNamed:appName];
FIRAuthStateDidChangeListenerHandle newListenerHandle = [[FIRAuth authWithApp:firApp] addAuthStateDidChangeListener:^(FIRAuth *_Nonnull auth, FIRUser *_Nullable user) { FIRAuthStateDidChangeListenerHandle newListenerHandle = [[FIRAuth authWithApp:firApp] addAuthStateDidChangeListener:^(FIRAuth *_Nonnull auth, FIRUser *_Nullable user) {
if (user != nil) { if (user != nil) {
[RNFirebaseUtil sendJSEventWithAppName:self appName:appName name:AUTH_CHANGED_EVENT body:@{@"authenticated": @(true), @"user": [self firebaseUserToDict:user]}]; [RNFirebaseUtil sendJSEventWithAppName:self app:firApp name:AUTH_CHANGED_EVENT body:@{@"authenticated": @(true), @"user": [self firebaseUserToDict:user]}];
} else { } else {
[RNFirebaseUtil sendJSEventWithAppName:self appName:appName name:AUTH_CHANGED_EVENT body:@{@"authenticated": @(false)}]; [RNFirebaseUtil sendJSEventWithAppName:self app:firApp name:AUTH_CHANGED_EVENT body:@{@"authenticated": @(false)}];
} }
}]; }];
_authStateHandlers[appName] = [NSValue valueWithNonretainedObject:newListenerHandle]; _authStateHandlers[firApp.name] = [NSValue valueWithNonretainedObject:newListenerHandle];
} }
} }
@ -44,12 +44,12 @@ RCT_EXPORT_METHOD(addAuthStateListener:
*/ */
RCT_EXPORT_METHOD(removeAuthStateListener: RCT_EXPORT_METHOD(removeAuthStateListener:
(NSString *) appName) { (NSString *) appDisplayName) {
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
if ([_authStateHandlers valueForKey:appName]) { if ([_authStateHandlers valueForKey:firApp.name]) {
FIRApp *firApp = [FIRApp appNamed:appName]; [[FIRAuth authWithApp:firApp] removeAuthStateDidChangeListener:[_authStateHandlers valueForKey:firApp.name]];
[[FIRAuth authWithApp:firApp] removeAuthStateDidChangeListener:[_authStateHandlers valueForKey:appName]]; [_authStateHandlers removeObjectForKey:firApp.name];
[_authStateHandlers removeObjectForKey:appName];
} }
} }
@ -58,19 +58,19 @@ RCT_EXPORT_METHOD(removeAuthStateListener:
*/ */
RCT_EXPORT_METHOD(addIdTokenListener: RCT_EXPORT_METHOD(addIdTokenListener:
(NSString *) appName) { (NSString *) appDisplayName) {
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
if (![_idTokenHandlers valueForKey:appName]) { if (![_idTokenHandlers valueForKey:firApp.name]) {
FIRApp *firApp = [FIRApp appNamed:appName];
FIRIDTokenDidChangeListenerHandle newListenerHandle = [[FIRAuth authWithApp:firApp] addIDTokenDidChangeListener:^(FIRAuth * _Nonnull auth, FIRUser * _Nullable user) { FIRIDTokenDidChangeListenerHandle newListenerHandle = [[FIRAuth authWithApp:firApp] addIDTokenDidChangeListener:^(FIRAuth * _Nonnull auth, FIRUser * _Nullable user) {
if (user != nil) { if (user != nil) {
[RNFirebaseUtil sendJSEventWithAppName:self appName:appName name:AUTH_ID_TOKEN_CHANGED_EVENT body:@{@"authenticated": @(true), @"user": [self firebaseUserToDict:user]}]; [RNFirebaseUtil sendJSEventWithAppName:self app:firApp name:AUTH_ID_TOKEN_CHANGED_EVENT body:@{@"authenticated": @(true), @"user": [self firebaseUserToDict:user]}];
} else { } else {
[RNFirebaseUtil sendJSEventWithAppName:self appName:appName name:AUTH_ID_TOKEN_CHANGED_EVENT body:@{@"authenticated": @(false)}]; [RNFirebaseUtil sendJSEventWithAppName:self app:firApp name:AUTH_ID_TOKEN_CHANGED_EVENT body:@{@"authenticated": @(false)}];
} }
}]; }];
_idTokenHandlers[appName] = [NSValue valueWithNonretainedObject:newListenerHandle]; _idTokenHandlers[firApp.name] = [NSValue valueWithNonretainedObject:newListenerHandle];
} }
} }
@ -79,11 +79,12 @@ RCT_EXPORT_METHOD(addIdTokenListener:
*/ */
RCT_EXPORT_METHOD(removeIdTokenListener: RCT_EXPORT_METHOD(removeIdTokenListener:
(NSString *) appName) { (NSString *) appDisplayName) {
if ([_idTokenHandlers valueForKey:appName]) { FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
FIRApp *firApp = [FIRApp appNamed:appName];
[[FIRAuth authWithApp:firApp] removeIDTokenDidChangeListener:[_idTokenHandlers valueForKey:appName]]; if ([_idTokenHandlers valueForKey:firApp.name]) {
[_idTokenHandlers removeObjectForKey:appName]; [[FIRAuth authWithApp:firApp] removeIDTokenDidChangeListener:[_idTokenHandlers valueForKey:firApp.name]];
[_idTokenHandlers removeObjectForKey:firApp.name];
} }
} }
@ -97,12 +98,12 @@ RCT_EXPORT_METHOD(removeIdTokenListener:
@return @return
*/ */
RCT_EXPORT_METHOD(signOut: RCT_EXPORT_METHOD(signOut:
(NSString *) appName (NSString *) appDisplayName
resolver: resolver:
(RCTPromiseResolveBlock) resolve (RCTPromiseResolveBlock) resolve
rejecter: rejecter:
(RCTPromiseRejectBlock) reject) { (RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [FIRApp appNamed:appName]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
FIRUser *user = [FIRAuth authWithApp:firApp].currentUser; FIRUser *user = [FIRAuth authWithApp:firApp].currentUser;
@ -125,12 +126,12 @@ RCT_EXPORT_METHOD(signOut:
@return @return
*/ */
RCT_EXPORT_METHOD(signInAnonymously: RCT_EXPORT_METHOD(signInAnonymously:
(NSString *) appName (NSString *) appDisplayName
resolver: resolver:
(RCTPromiseResolveBlock) resolve (RCTPromiseResolveBlock) resolve
rejecter: rejecter:
(RCTPromiseRejectBlock) reject) { (RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [FIRApp appNamed:appName]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
[[FIRAuth authWithApp:firApp] signInAnonymouslyWithCompletion:^(FIRUser *user, NSError *error) { [[FIRAuth authWithApp:firApp] signInAnonymouslyWithCompletion:^(FIRUser *user, NSError *error) {
if (error) { if (error) {
@ -152,7 +153,7 @@ RCT_EXPORT_METHOD(signInAnonymously:
@return return @return return
*/ */
RCT_EXPORT_METHOD(signInWithEmailAndPassword: RCT_EXPORT_METHOD(signInWithEmailAndPassword:
(NSString *) appName (NSString *) appDisplayName
email: email:
(NSString *) email (NSString *) email
pass: pass:
@ -161,7 +162,7 @@ RCT_EXPORT_METHOD(signInWithEmailAndPassword:
(RCTPromiseResolveBlock) resolve (RCTPromiseResolveBlock) resolve
rejecter: rejecter:
(RCTPromiseRejectBlock) reject) { (RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [FIRApp appNamed:appName]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
[[FIRAuth authWithApp:firApp] signInWithEmail:email password:password completion:^(FIRUser *user, NSError *error) { [[FIRAuth authWithApp:firApp] signInWithEmail:email password:password completion:^(FIRUser *user, NSError *error) {
if (error) { if (error) {
@ -182,7 +183,7 @@ RCT_EXPORT_METHOD(signInWithEmailAndPassword:
@return return @return return
*/ */
RCT_EXPORT_METHOD(createUserWithEmailAndPassword: RCT_EXPORT_METHOD(createUserWithEmailAndPassword:
(NSString *) appName (NSString *) appDisplayName
email: email:
(NSString *) email (NSString *) email
pass: pass:
@ -191,7 +192,7 @@ RCT_EXPORT_METHOD(createUserWithEmailAndPassword:
(RCTPromiseResolveBlock) resolve (RCTPromiseResolveBlock) resolve
rejecter: rejecter:
(RCTPromiseRejectBlock) reject) { (RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [FIRApp appNamed:appName]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
[[FIRAuth authWithApp:firApp] createUserWithEmail:email password:password completion:^(FIRUser *user, NSError *error) { [[FIRAuth authWithApp:firApp] createUserWithEmail:email password:password completion:^(FIRUser *user, NSError *error) {
if (error) { if (error) {
@ -210,12 +211,12 @@ RCT_EXPORT_METHOD(createUserWithEmailAndPassword:
@return return @return return
*/ */
RCT_EXPORT_METHOD(delete: RCT_EXPORT_METHOD(delete:
(NSString *) appName (NSString *) appDisplayName
resolver: resolver:
(RCTPromiseResolveBlock) resolve (RCTPromiseResolveBlock) resolve
rejecter: rejecter:
(RCTPromiseRejectBlock) reject) { (RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [FIRApp appNamed:appName]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
FIRUser *user = [FIRAuth authWithApp:firApp].currentUser; FIRUser *user = [FIRAuth authWithApp:firApp].currentUser;
if (user) { if (user) {
@ -239,12 +240,12 @@ RCT_EXPORT_METHOD(delete:
@return return @return return
*/ */
RCT_EXPORT_METHOD(reload: RCT_EXPORT_METHOD(reload:
(NSString *) appName (NSString *) appDisplayName
resolver: resolver:
(RCTPromiseResolveBlock) resolve (RCTPromiseResolveBlock) resolve
rejecter: rejecter:
(RCTPromiseRejectBlock) reject) { (RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [FIRApp appNamed:appName]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
FIRUser *user = [FIRAuth authWithApp:firApp].currentUser; FIRUser *user = [FIRAuth authWithApp:firApp].currentUser;
@ -262,11 +263,11 @@ RCT_EXPORT_METHOD(reload:
@param RCTPromiseRejectBlock reject @param RCTPromiseRejectBlock reject
@return return @return return
*/ */
RCT_EXPORT_METHOD(sendEmailVerification:(NSString *) appName RCT_EXPORT_METHOD(sendEmailVerification:(NSString *) appDisplayName
actionCodeSettings:(NSDictionary *) actionCodeSettings actionCodeSettings:(NSDictionary *) actionCodeSettings
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [FIRApp appNamed:appName]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
FIRUser *user = [FIRAuth authWithApp:firApp].currentUser; FIRUser *user = [FIRAuth authWithApp:firApp].currentUser;
if (user) { if (user) {
@ -298,14 +299,14 @@ RCT_EXPORT_METHOD(sendEmailVerification:(NSString *) appName
@return return @return return
*/ */
RCT_EXPORT_METHOD(updateEmail: RCT_EXPORT_METHOD(updateEmail:
(NSString *) appName (NSString *) appDisplayName
email: email:
(NSString *) email (NSString *) email
resolver: resolver:
(RCTPromiseResolveBlock) resolve (RCTPromiseResolveBlock) resolve
rejecter: rejecter:
(RCTPromiseRejectBlock) reject) { (RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [FIRApp appNamed:appName]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
FIRUser *user = [FIRAuth authWithApp:firApp].currentUser; FIRUser *user = [FIRAuth authWithApp:firApp].currentUser;
if (user) { if (user) {
@ -330,14 +331,14 @@ RCT_EXPORT_METHOD(updateEmail:
@return return @return return
*/ */
RCT_EXPORT_METHOD(updatePassword: RCT_EXPORT_METHOD(updatePassword:
(NSString *) appName (NSString *) appDisplayName
password: password:
(NSString *) password (NSString *) password
resolver: resolver:
(RCTPromiseResolveBlock) resolve (RCTPromiseResolveBlock) resolve
rejecter: rejecter:
(RCTPromiseRejectBlock) reject) { (RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [FIRApp appNamed:appName]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
FIRUser *user = [FIRAuth authWithApp:firApp].currentUser; FIRUser *user = [FIRAuth authWithApp:firApp].currentUser;
@ -364,14 +365,14 @@ RCT_EXPORT_METHOD(updatePassword:
@return return @return return
*/ */
RCT_EXPORT_METHOD(updateProfile: RCT_EXPORT_METHOD(updateProfile:
(NSString *) appName (NSString *) appDisplayName
props: props:
(NSDictionary *) props (NSDictionary *) props
resolver: resolver:
(RCTPromiseResolveBlock) resolve (RCTPromiseResolveBlock) resolve
rejecter: rejecter:
(RCTPromiseRejectBlock) reject) { (RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [FIRApp appNamed:appName]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
FIRUser *user = [FIRAuth authWithApp:firApp].currentUser; FIRUser *user = [FIRAuth authWithApp:firApp].currentUser;
@ -412,14 +413,14 @@ RCT_EXPORT_METHOD(updateProfile:
@return @return
*/ */
RCT_EXPORT_METHOD(getToken: RCT_EXPORT_METHOD(getToken:
(NSString *) appName (NSString *) appDisplayName
forceRefresh: forceRefresh:
(BOOL) forceRefresh (BOOL) forceRefresh
resolver: resolver:
(RCTPromiseResolveBlock) resolve (RCTPromiseResolveBlock) resolve
rejecter: rejecter:
(RCTPromiseRejectBlock) reject) { (RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [FIRApp appNamed:appName]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
FIRUser *user = [FIRAuth authWithApp:firApp].currentUser; FIRUser *user = [FIRAuth authWithApp:firApp].currentUser;
@ -447,7 +448,7 @@ RCT_EXPORT_METHOD(getToken:
@return @return
*/ */
RCT_EXPORT_METHOD(signInWithCredential: RCT_EXPORT_METHOD(signInWithCredential:
(NSString *) appName (NSString *) appDisplayName
provider: provider:
(NSString *) provider (NSString *) provider
token: token:
@ -458,7 +459,7 @@ RCT_EXPORT_METHOD(signInWithCredential:
(RCTPromiseResolveBlock) resolve (RCTPromiseResolveBlock) resolve
rejecter: rejecter:
(RCTPromiseRejectBlock) reject) { (RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [FIRApp appNamed:appName]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
FIRAuthCredential *credential = [self getCredentialForProvider:provider token:authToken secret:authSecret]; FIRAuthCredential *credential = [self getCredentialForProvider:provider token:authToken secret:authSecret];
@ -485,7 +486,7 @@ RCT_EXPORT_METHOD(signInWithCredential:
@return @return
*/ */
RCT_EXPORT_METHOD(confirmPasswordReset: RCT_EXPORT_METHOD(confirmPasswordReset:
(NSString *) appName (NSString *) appDisplayName
code: code:
(NSString *) code (NSString *) code
newPassword: newPassword:
@ -494,8 +495,8 @@ RCT_EXPORT_METHOD(confirmPasswordReset:
(RCTPromiseResolveBlock) resolve (RCTPromiseResolveBlock) resolve
rejecter: rejecter:
(RCTPromiseRejectBlock) reject) { (RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [FIRApp appNamed:appName]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
[[FIRAuth authWithApp:firApp] confirmPasswordResetWithCode:code newPassword:newPassword completion:^(NSError *_Nullable error) { [[FIRAuth authWithApp:firApp] confirmPasswordResetWithCode:code newPassword:newPassword completion:^(NSError *_Nullable error) {
if (error) { if (error) {
[self promiseRejectAuthException:reject error:error]; [self promiseRejectAuthException:reject error:error];
@ -515,15 +516,15 @@ RCT_EXPORT_METHOD(confirmPasswordReset:
* @return * @return
*/ */
RCT_EXPORT_METHOD(applyActionCode: RCT_EXPORT_METHOD(applyActionCode:
(NSString *) appName (NSString *) appDisplayName
code: code:
(NSString *) code (NSString *) code
resolver: resolver:
(RCTPromiseResolveBlock) resolve (RCTPromiseResolveBlock) resolve
rejecter: rejecter:
(RCTPromiseRejectBlock) reject) { (RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [FIRApp appNamed:appName]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
[[FIRAuth authWithApp:firApp] applyActionCode:code completion:^(NSError *_Nullable error) { [[FIRAuth authWithApp:firApp] applyActionCode:code completion:^(NSError *_Nullable error) {
if (error) { if (error) {
[self promiseRejectAuthException:reject error:error]; [self promiseRejectAuthException:reject error:error];
@ -542,15 +543,15 @@ RCT_EXPORT_METHOD(applyActionCode:
* @return * @return
*/ */
RCT_EXPORT_METHOD(checkActionCode: RCT_EXPORT_METHOD(checkActionCode:
(NSString *) appName (NSString *) appDisplayName
code: code:
(NSString *) code (NSString *) code
resolver: resolver:
(RCTPromiseResolveBlock) resolve (RCTPromiseResolveBlock) resolve
rejecter: rejecter:
(RCTPromiseRejectBlock) reject) { (RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [FIRApp appNamed:appName]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
[[FIRAuth authWithApp:firApp] checkActionCode:code completion:^(FIRActionCodeInfo *_Nullable info, NSError *_Nullable error) { [[FIRAuth authWithApp:firApp] checkActionCode:code completion:^(FIRActionCodeInfo *_Nullable info, NSError *_Nullable error) {
if (error) { if (error) {
[self promiseRejectAuthException:reject error:error]; [self promiseRejectAuthException:reject error:error];
@ -586,12 +587,12 @@ RCT_EXPORT_METHOD(checkActionCode:
@param RCTPromiseRejectBlock reject @param RCTPromiseRejectBlock reject
@return @return
*/ */
RCT_EXPORT_METHOD(sendPasswordResetEmail:(NSString *) appName RCT_EXPORT_METHOD(sendPasswordResetEmail:(NSString *) appDisplayName
email:(NSString *) email email:(NSString *) email
actionCodeSettings:(NSDictionary *) actionCodeSettings actionCodeSettings:(NSDictionary *) actionCodeSettings
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [FIRApp appNamed:appName]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
id handler = ^(NSError *_Nullable error) { id handler = ^(NSError *_Nullable error) {
if (error) { if (error) {
@ -600,7 +601,7 @@ RCT_EXPORT_METHOD(sendPasswordResetEmail:(NSString *) appName
[self promiseNoUser:resolve rejecter:reject isError:NO]; [self promiseNoUser:resolve rejecter:reject isError:NO];
} }
}; };
if (actionCodeSettings) { if (actionCodeSettings) {
FIRActionCodeSettings *settings = [self buildActionCodeSettings:actionCodeSettings]; FIRActionCodeSettings *settings = [self buildActionCodeSettings:actionCodeSettings];
[[FIRAuth authWithApp:firApp] sendPasswordResetWithEmail:email actionCodeSettings:settings completion:handler]; [[FIRAuth authWithApp:firApp] sendPasswordResetWithEmail:email actionCodeSettings:settings completion:handler];
@ -617,12 +618,12 @@ RCT_EXPORT_METHOD(sendPasswordResetEmail:(NSString *) appName
@return @return
*/ */
RCT_EXPORT_METHOD(getCurrentUser: RCT_EXPORT_METHOD(getCurrentUser:
(NSString *) appName (NSString *) appDisplayName
resolver: resolver:
(RCTPromiseResolveBlock) resolve (RCTPromiseResolveBlock) resolve
rejecter: rejecter:
(RCTPromiseRejectBlock) reject) { (RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [FIRApp appNamed:appName]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
FIRUser *user = [FIRAuth authWithApp:firApp].currentUser; FIRUser *user = [FIRAuth authWithApp:firApp].currentUser;
[self promiseWithUser:resolve rejecter:reject user:user]; [self promiseWithUser:resolve rejecter:reject user:user];
@ -637,14 +638,14 @@ RCT_EXPORT_METHOD(getCurrentUser:
@return @return
*/ */
RCT_EXPORT_METHOD(signInWithCustomToken: RCT_EXPORT_METHOD(signInWithCustomToken:
(NSString *) appName (NSString *) appDisplayName
customToken: customToken:
(NSString *) customToken (NSString *) customToken
resolver: resolver:
(RCTPromiseResolveBlock) resolve (RCTPromiseResolveBlock) resolve
rejecter: rejecter:
(RCTPromiseRejectBlock) reject) { (RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [FIRApp appNamed:appName]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
[[FIRAuth authWithApp:firApp] signInWithCustomToken:customToken completion:^(FIRUser *user, NSError *error) { [[FIRAuth authWithApp:firApp] signInWithCustomToken:customToken completion:^(FIRUser *user, NSError *error) {
if (error) { if (error) {
@ -663,11 +664,11 @@ RCT_EXPORT_METHOD(signInWithCustomToken:
@param RCTPromiseRejectBlock reject @param RCTPromiseRejectBlock reject
@return @return
*/ */
RCT_EXPORT_METHOD(signInWithPhoneNumber:(NSString *) appName RCT_EXPORT_METHOD(signInWithPhoneNumber:(NSString *) appDisplayName
phoneNumber:(NSString *) phoneNumber phoneNumber:(NSString *) phoneNumber
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [FIRApp appNamed:appName]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
[[FIRPhoneAuthProvider providerWithAuth:[FIRAuth authWithApp:firApp]] verifyPhoneNumber:phoneNumber UIDelegate:nil completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) { [[FIRPhoneAuthProvider providerWithAuth:[FIRAuth authWithApp:firApp]] verifyPhoneNumber:phoneNumber UIDelegate:nil completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) {
if (error) { if (error) {
@ -684,17 +685,17 @@ RCT_EXPORT_METHOD(signInWithPhoneNumber:(NSString *) appName
/** /**
verifyPhoneNumber verifyPhoneNumber
@param string phoneNumber @param string phoneNumber
@param RCTPromiseResolveBlock resolve @param RCTPromiseResolveBlock resolve
@param RCTPromiseRejectBlock reject @param RCTPromiseRejectBlock reject
@return @return
*/ */
RCT_EXPORT_METHOD(verifyPhoneNumber:(NSString *) appName RCT_EXPORT_METHOD(verifyPhoneNumber:(NSString *) appDisplayName
phoneNumber:(NSString *) phoneNumber phoneNumber:(NSString *) phoneNumber
requestKey:(NSString *) requestKey) { requestKey:(NSString *) requestKey) {
FIRApp *firApp = [FIRApp appNamed:appName]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
[[FIRPhoneAuthProvider providerWithAuth:[FIRAuth authWithApp:firApp]] verifyPhoneNumber:phoneNumber UIDelegate:nil completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) { [[FIRPhoneAuthProvider providerWithAuth:[FIRAuth authWithApp:firApp]] verifyPhoneNumber:phoneNumber UIDelegate:nil completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) {
if (error) { if (error) {
NSDictionary * jsError = [self getJSError:(error)]; NSDictionary * jsError = [self getJSError:(error)];
@ -703,7 +704,7 @@ RCT_EXPORT_METHOD(verifyPhoneNumber:(NSString *) appName
@"requestKey":requestKey, @"requestKey":requestKey,
@"state": @{@"error": jsError}, @"state": @{@"error": jsError},
}; };
[RNFirebaseUtil sendJSEventWithAppName:self appName:appName name:PHONE_AUTH_STATE_CHANGED_EVENT body:body]; [RNFirebaseUtil sendJSEventWithAppName:self app:firApp name:PHONE_AUTH_STATE_CHANGED_EVENT body:body];
} else { } else {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:verificationID forKey:@"authVerificationID"]; [defaults setObject:verificationID forKey:@"authVerificationID"];
@ -712,16 +713,16 @@ RCT_EXPORT_METHOD(verifyPhoneNumber:(NSString *) appName
@"requestKey":requestKey, @"requestKey":requestKey,
@"state": @{@"verificationId": verificationID}, @"state": @{@"verificationId": verificationID},
}; };
[RNFirebaseUtil sendJSEventWithAppName:self appName:appName name:PHONE_AUTH_STATE_CHANGED_EVENT body:body]; [RNFirebaseUtil sendJSEventWithAppName:self app:firApp name:PHONE_AUTH_STATE_CHANGED_EVENT body:body];
} }
}]; }];
} }
RCT_EXPORT_METHOD(_confirmVerificationCode:(NSString *) appName RCT_EXPORT_METHOD(_confirmVerificationCode:(NSString *) appDisplayName
verificationCode:(NSString *) verificationCode verificationCode:(NSString *) verificationCode
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [FIRApp appNamed:appName]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *verificationId = [defaults stringForKey:@"authVerificationID"]; NSString *verificationId = [defaults stringForKey:@"authVerificationID"];
FIRAuthCredential *credential = [[FIRPhoneAuthProvider provider] credentialWithVerificationID:verificationId verificationCode:verificationCode]; FIRAuthCredential *credential = [[FIRPhoneAuthProvider provider] credentialWithVerificationID:verificationId verificationCode:verificationCode];
@ -746,7 +747,7 @@ RCT_EXPORT_METHOD(_confirmVerificationCode:(NSString *) appName
@return @return
*/ */
RCT_EXPORT_METHOD(link: RCT_EXPORT_METHOD(link:
(NSString *) appName (NSString *) appDisplayName
provider: provider:
(NSString *) provider (NSString *) provider
authToken: authToken:
@ -757,7 +758,7 @@ RCT_EXPORT_METHOD(link:
(RCTPromiseResolveBlock) resolve (RCTPromiseResolveBlock) resolve
rejecter: rejecter:
(RCTPromiseRejectBlock) reject) { (RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [FIRApp appNamed:appName]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
FIRAuthCredential *credential = [self getCredentialForProvider:provider token:authToken secret:authSecret]; FIRAuthCredential *credential = [self getCredentialForProvider:provider token:authToken secret:authSecret];
@ -791,14 +792,14 @@ RCT_EXPORT_METHOD(link:
@return @return
*/ */
RCT_EXPORT_METHOD(unlink: RCT_EXPORT_METHOD(unlink:
(NSString *) appName (NSString *) appDisplayName
providerId: providerId:
(NSString *) providerId (NSString *) providerId
resolver: resolver:
(RCTPromiseResolveBlock) resolve (RCTPromiseResolveBlock) resolve
rejecter: rejecter:
(RCTPromiseRejectBlock) reject) { (RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [FIRApp appNamed:appName]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
FIRUser *user = [FIRAuth authWithApp:firApp].currentUser; FIRUser *user = [FIRAuth authWithApp:firApp].currentUser;
if (user) { if (user) {
@ -825,7 +826,7 @@ RCT_EXPORT_METHOD(unlink:
@return @return
*/ */
RCT_EXPORT_METHOD(reauthenticate: RCT_EXPORT_METHOD(reauthenticate:
(NSString *) appName (NSString *) appDisplayName
provider: provider:
(NSString *) provider (NSString *) provider
authToken: authToken:
@ -836,7 +837,7 @@ RCT_EXPORT_METHOD(reauthenticate:
(RCTPromiseResolveBlock) resolve (RCTPromiseResolveBlock) resolve
rejecter: rejecter:
(RCTPromiseRejectBlock) reject) { (RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [FIRApp appNamed:appName]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
FIRAuthCredential *credential = [self getCredentialForProvider:provider token:authToken secret:authSecret]; FIRAuthCredential *credential = [self getCredentialForProvider:provider token:authToken secret:authSecret];
@ -869,14 +870,14 @@ RCT_EXPORT_METHOD(reauthenticate:
@return @return
*/ */
RCT_EXPORT_METHOD(fetchProvidersForEmail: RCT_EXPORT_METHOD(fetchProvidersForEmail:
(NSString *) appName (NSString *) appDisplayName
email: email:
(NSString *) email (NSString *) email
resolver: resolver:
(RCTPromiseResolveBlock) resolve (RCTPromiseResolveBlock) resolve
rejecter: rejecter:
(RCTPromiseRejectBlock) reject) { (RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [FIRApp appNamed:appName]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
[[FIRAuth authWithApp:firApp] fetchProvidersForEmail:email completion:^(NSArray<NSString *> *_Nullable providers, NSError *_Nullable error) { [[FIRAuth authWithApp:firApp] fetchProvidersForEmail:email completion:^(NSArray<NSString *> *_Nullable providers, NSError *_Nullable error) {
if (error) { if (error) {
@ -962,14 +963,14 @@ RCT_EXPORT_METHOD(fetchProvidersForEmail:
/** /**
Reject a promise with an auth exception Reject a promise with an auth exception
@param error NSError @param error NSError
*/ */
- (NSDictionary *)getJSError:(NSError *)error { - (NSDictionary *)getJSError:(NSError *)error {
NSString *code = @"auth/unknown"; NSString *code = @"auth/unknown";
NSString *message = [error localizedDescription]; NSString *message = [error localizedDescription];
NSString *nativeErrorMessage = [error localizedDescription]; NSString *nativeErrorMessage = [error localizedDescription];
switch (error.code) { switch (error.code) {
case FIRAuthErrorCodeInvalidCustomToken: case FIRAuthErrorCodeInvalidCustomToken:
code = @"auth/invalid-custom-token"; code = @"auth/invalid-custom-token";
@ -1043,7 +1044,7 @@ RCT_EXPORT_METHOD(fetchProvidersForEmail:
code = @"auth/internal-error"; code = @"auth/internal-error";
message = @"An internal error has occurred, please try again."; message = @"An internal error has occurred, please try again.";
break; break;
// unsure of the below codes so leaving them as the default error message // unsure of the below codes so leaving them as the default error message
case FIRAuthErrorCodeTooManyRequests: case FIRAuthErrorCodeTooManyRequests:
code = @"auth/too-many-requests"; code = @"auth/too-many-requests";
@ -1078,7 +1079,7 @@ RCT_EXPORT_METHOD(fetchProvidersForEmail:
default: default:
break; break;
} }
return @{ return @{
@"code": code, @"code": code,
@"message": message, @"message": message,

View File

@ -16,7 +16,7 @@
+ (void)handlePromise:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject databaseError:(NSError *)databaseError; + (void)handlePromise:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject databaseError:(NSError *)databaseError;
+ (FIRDatabase *)getDatabaseForApp:(NSString *)appName; + (FIRDatabase *)getDatabaseForApp:(NSString *)appDisplayName;
+ (NSDictionary *)getJSError:(NSError *)nativeError; + (NSDictionary *)getJSError:(NSError *)nativeError;

View File

@ -22,38 +22,38 @@ RCT_EXPORT_MODULE();
return self; return self;
} }
RCT_EXPORT_METHOD(goOnline:(NSString *) appName) { RCT_EXPORT_METHOD(goOnline:(NSString *) appDisplayName) {
[[RNFirebaseDatabase getDatabaseForApp:appName] goOnline]; [[RNFirebaseDatabase getDatabaseForApp:appDisplayName] goOnline];
} }
RCT_EXPORT_METHOD(goOffline:(NSString *) appName) { RCT_EXPORT_METHOD(goOffline:(NSString *) appDisplayName) {
[[RNFirebaseDatabase getDatabaseForApp:appName] goOffline]; [[RNFirebaseDatabase getDatabaseForApp:appDisplayName] goOffline];
} }
RCT_EXPORT_METHOD(setPersistence:(NSString *) appName RCT_EXPORT_METHOD(setPersistence:(NSString *) appDisplayName
state:(BOOL) state) { state:(BOOL) state) {
[RNFirebaseDatabase getDatabaseForApp:appName].persistenceEnabled = state; [RNFirebaseDatabase getDatabaseForApp:appDisplayName].persistenceEnabled = state;
} }
RCT_EXPORT_METHOD(setPersistenceCacheSizeBytes:(NSString *) appName RCT_EXPORT_METHOD(setPersistenceCacheSizeBytes:(NSString *) appDisplayName
size:(NSInteger *) size) { size:(NSInteger *) size) {
[RNFirebaseDatabase getDatabaseForApp:appName].persistenceCacheSizeBytes = (NSUInteger)size; [RNFirebaseDatabase getDatabaseForApp:appDisplayName].persistenceCacheSizeBytes = (NSUInteger)size;
} }
RCT_EXPORT_METHOD(enableLogging:(BOOL) enabled) { RCT_EXPORT_METHOD(enableLogging:(BOOL) enabled) {
[FIRDatabase setLoggingEnabled:enabled]; [FIRDatabase setLoggingEnabled:enabled];
} }
RCT_EXPORT_METHOD(keepSynced:(NSString *) appName RCT_EXPORT_METHOD(keepSynced:(NSString *) appDisplayName
key:(NSString *) key key:(NSString *) key
path:(NSString *) path path:(NSString *) path
modifiers:(NSArray *) modifiers modifiers:(NSArray *) modifiers
state:(BOOL) state) { state:(BOOL) state) {
FIRDatabaseQuery *query = [self getInternalReferenceForApp:appName key:key path:path modifiers:modifiers].query; FIRDatabaseQuery *query = [self getInternalReferenceForApp:appDisplayName key:key path:path modifiers:modifiers].query;
[query keepSynced:state]; [query keepSynced:state];
} }
RCT_EXPORT_METHOD(transactionTryCommit:(NSString *) appName RCT_EXPORT_METHOD(transactionTryCommit:(NSString *) appDisplayName
transactionId:(nonnull NSNumber *) transactionId transactionId:(nonnull NSNumber *) transactionId
updates:(NSDictionary *) updates) { updates:(NSDictionary *) updates) {
__block NSMutableDictionary *transactionState; __block NSMutableDictionary *transactionState;
@ -82,7 +82,7 @@ RCT_EXPORT_METHOD(transactionTryCommit:(NSString *) appName
} }
RCT_EXPORT_METHOD(transactionStart:(NSString *) appName RCT_EXPORT_METHOD(transactionStart:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
transactionId:(nonnull NSNumber *) transactionId transactionId:(nonnull NSNumber *) transactionId
applyLocally:(BOOL) applyLocally) { applyLocally:(BOOL) applyLocally) {
@ -90,13 +90,13 @@ RCT_EXPORT_METHOD(transactionStart:(NSString *) appName
NSMutableDictionary *transactionState = [NSMutableDictionary new]; NSMutableDictionary *transactionState = [NSMutableDictionary new];
dispatch_semaphore_t sema = dispatch_semaphore_create(0); dispatch_semaphore_t sema = dispatch_semaphore_create(0);
transactionState[@"semaphore"] = sema; transactionState[@"semaphore"] = sema;
FIRDatabaseReference *ref = [self getReferenceForAppPath:appName path:path]; FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName path:path];
[ref runTransactionBlock:^FIRTransactionResult * _Nonnull(FIRMutableData * [ref runTransactionBlock:^FIRTransactionResult * _Nonnull(FIRMutableData *
_Nonnull currentData) { _Nonnull currentData) {
dispatch_barrier_async(_transactionQueue, ^{ dispatch_barrier_async(_transactionQueue, ^{
[_transactions setValue:transactionState forKey:transactionId]; [_transactions setValue:transactionState forKey:transactionId];
NSDictionary *updateMap = [self createTransactionUpdateMap:appName transactionId:transactionId updatesData:currentData]; NSDictionary *updateMap = [self createTransactionUpdateMap:appDisplayName transactionId:transactionId updatesData:currentData];
[RNFirebaseUtil sendJSEvent:self name:DATABASE_TRANSACTION_EVENT body:updateMap]; [RNFirebaseUtil sendJSEvent:self name:DATABASE_TRANSACTION_EVENT body:updateMap];
}); });
@ -123,7 +123,7 @@ RCT_EXPORT_METHOD(transactionStart:(NSString *) appName
} }
andCompletionBlock: andCompletionBlock:
^(NSError *_Nullable databaseError, BOOL committed, FIRDataSnapshot *_Nullable snapshot) { ^(NSError *_Nullable databaseError, BOOL committed, FIRDataSnapshot *_Nullable snapshot) {
NSDictionary *resultMap = [self createTransactionResultMap:appName transactionId:transactionId error:databaseError committed:committed snapshot:snapshot]; NSDictionary *resultMap = [self createTransactionResultMap:appDisplayName transactionId:transactionId error:databaseError committed:committed snapshot:snapshot];
[RNFirebaseUtil sendJSEvent:self name:DATABASE_TRANSACTION_EVENT body:resultMap]; [RNFirebaseUtil sendJSEvent:self name:DATABASE_TRANSACTION_EVENT body:resultMap];
} }
withLocalEvents: withLocalEvents:
@ -131,117 +131,117 @@ RCT_EXPORT_METHOD(transactionStart:(NSString *) appName
}); });
} }
RCT_EXPORT_METHOD(onDisconnectSet:(NSString *) appName RCT_EXPORT_METHOD(onDisconnectSet:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
props:(NSDictionary *) props props:(NSDictionary *) props
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
FIRDatabaseReference *ref = [self getReferenceForAppPath:appName path:path]; FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName path:path];
[ref onDisconnectSetValue:props[@"value"] withCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) { [ref onDisconnectSetValue:props[@"value"] withCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) {
[RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error]; [RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error];
}]; }];
} }
RCT_EXPORT_METHOD(onDisconnectUpdate:(NSString *) appName RCT_EXPORT_METHOD(onDisconnectUpdate:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
props:(NSDictionary *) props props:(NSDictionary *) props
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
FIRDatabaseReference *ref = [self getReferenceForAppPath:appName path:path]; FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName path:path];
[ref onDisconnectUpdateChildValues:props withCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) { [ref onDisconnectUpdateChildValues:props withCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) {
[RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error]; [RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error];
}]; }];
} }
RCT_EXPORT_METHOD(onDisconnectRemove:(NSString *) appName RCT_EXPORT_METHOD(onDisconnectRemove:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
FIRDatabaseReference *ref = [self getReferenceForAppPath:appName path:path]; FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName path:path];
[ref onDisconnectRemoveValueWithCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) { [ref onDisconnectRemoveValueWithCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) {
[RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error]; [RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error];
}]; }];
} }
RCT_EXPORT_METHOD(onDisconnectCancel:(NSString *) appName RCT_EXPORT_METHOD(onDisconnectCancel:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
FIRDatabaseReference *ref = [self getReferenceForAppPath:appName path:path]; FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName path:path];
[ref cancelDisconnectOperationsWithCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) { [ref cancelDisconnectOperationsWithCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) {
[RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error]; [RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error];
}]; }];
} }
RCT_EXPORT_METHOD(set:(NSString *) appName RCT_EXPORT_METHOD(set:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
props:(NSDictionary *) props props:(NSDictionary *) props
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
FIRDatabaseReference *ref = [self getReferenceForAppPath:appName path:path]; FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName path:path];
[ref setValue:[props valueForKey:@"value"] withCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) { [ref setValue:[props valueForKey:@"value"] withCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) {
[RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error]; [RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error];
}]; }];
} }
RCT_EXPORT_METHOD(setPriority:(NSString *) appName RCT_EXPORT_METHOD(setPriority:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
priority:(NSDictionary *) priority priority:(NSDictionary *) priority
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
FIRDatabaseReference *ref = [self getReferenceForAppPath:appName path:path]; FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName path:path];
[ref setPriority:[priority valueForKey:@"value"] withCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull ref) { [ref setPriority:[priority valueForKey:@"value"] withCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull ref) {
[RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error]; [RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error];
}]; }];
} }
RCT_EXPORT_METHOD(setWithPriority:(NSString *) appName RCT_EXPORT_METHOD(setWithPriority:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
data:(NSDictionary *) data data:(NSDictionary *) data
priority:(NSDictionary *) priority priority:(NSDictionary *) priority
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
FIRDatabaseReference *ref = [self getReferenceForAppPath:appName path:path]; FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName path:path];
[ref setValue:[data valueForKey:@"value"] andPriority:[priority valueForKey:@"value"] withCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull ref) { [ref setValue:[data valueForKey:@"value"] andPriority:[priority valueForKey:@"value"] withCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull ref) {
[RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error]; [RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error];
}]; }];
} }
RCT_EXPORT_METHOD(update:(NSString *) appName RCT_EXPORT_METHOD(update:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
props:(NSDictionary *) props props:(NSDictionary *) props
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
FIRDatabaseReference *ref = [self getReferenceForAppPath:appName path:path]; FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName path:path];
[ref updateChildValues:props withCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) { [ref updateChildValues:props withCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) {
[RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error]; [RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error];
}]; }];
} }
RCT_EXPORT_METHOD(remove:(NSString *) appName RCT_EXPORT_METHOD(remove:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
FIRDatabaseReference *ref = [self getReferenceForAppPath:appName path:path]; FIRDatabaseReference *ref = [self getReferenceForAppPath:appDisplayName path:path];
[ref removeValueWithCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) { [ref removeValueWithCompletionBlock:^(NSError *_Nullable error, FIRDatabaseReference *_Nonnull _ref) {
[RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error]; [RNFirebaseDatabase handlePromise:resolve rejecter:reject databaseError:error];
}]; }];
} }
RCT_EXPORT_METHOD(once:(NSString *) appName RCT_EXPORT_METHOD(once:(NSString *) appDisplayName
key:(NSString *) key key:(NSString *) key
path:(NSString *) path path:(NSString *) path
modifiers:(NSArray *) modifiers modifiers:(NSArray *) modifiers
eventName:(NSString *) eventName eventName:(NSString *) eventName
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
RNFirebaseDatabaseReference *ref = [self getInternalReferenceForApp:appName key:key path:path modifiers:modifiers]; RNFirebaseDatabaseReference *ref = [self getInternalReferenceForApp:appDisplayName key:key path:path modifiers:modifiers];
[ref once:eventName resolver:resolve rejecter:reject]; [ref once:eventName resolver:resolve rejecter:reject];
} }
RCT_EXPORT_METHOD(on:(NSString *) appName RCT_EXPORT_METHOD(on:(NSString *) appDisplayName
props:(NSDictionary *) props) { props:(NSDictionary *) props) {
RNFirebaseDatabaseReference *ref = [self getCachedInternalReferenceForApp:appName props:props]; RNFirebaseDatabaseReference *ref = [self getCachedInternalReferenceForApp:appDisplayName props:props];
[ref on:props[@"eventType"] registration:props[@"registration"]]; [ref on:props[@"eventType"] registration:props[@"registration"]];
} }
@ -271,20 +271,20 @@ RCT_EXPORT_METHOD(off:(NSString *) key
} }
} }
+ (FIRDatabase *)getDatabaseForApp:(NSString *)appName { + (FIRDatabase *)getDatabaseForApp:(NSString *)appDisplayName {
FIRApp *app = [FIRApp appNamed:appName]; FIRApp *app = [RNFirebaseUtil getApp:appDisplayName];
return [FIRDatabase databaseForApp:app]; return [FIRDatabase databaseForApp:app];
} }
- (FIRDatabaseReference *)getReferenceForAppPath:(NSString *)appName path:(NSString *)path { - (FIRDatabaseReference *)getReferenceForAppPath:(NSString *)appDisplayName path:(NSString *)path {
return [[RNFirebaseDatabase getDatabaseForApp:appName] referenceWithPath:path]; return [[RNFirebaseDatabase getDatabaseForApp:appDisplayName] referenceWithPath:path];
} }
- (RNFirebaseDatabaseReference *)getInternalReferenceForApp:(NSString *)appName key:(NSString *)key path:(NSString *)path modifiers:(NSArray *)modifiers { - (RNFirebaseDatabaseReference *)getInternalReferenceForApp:(NSString *)appDisplayName key:(NSString *)key path:(NSString *)path modifiers:(NSArray *)modifiers {
return [[RNFirebaseDatabaseReference alloc] initWithPathAndModifiers:self app:appName key:key refPath:path modifiers:modifiers]; return [[RNFirebaseDatabaseReference alloc] initWithPathAndModifiers:self appDisplayName:appDisplayName key:key refPath:path modifiers:modifiers];
} }
- (RNFirebaseDatabaseReference *)getCachedInternalReferenceForApp:(NSString *)appName props:(NSDictionary *)props { - (RNFirebaseDatabaseReference *)getCachedInternalReferenceForApp:(NSString *)appDisplayName props:(NSDictionary *)props {
NSString *key = props[@"key"]; NSString *key = props[@"key"];
NSString *path = props[@"path"]; NSString *path = props[@"path"];
NSDictionary *modifiers = props[@"modifiers"]; NSDictionary *modifiers = props[@"modifiers"];
@ -292,7 +292,7 @@ RCT_EXPORT_METHOD(off:(NSString *) key
RNFirebaseDatabaseReference *ref = _dbReferences[key]; RNFirebaseDatabaseReference *ref = _dbReferences[key];
if (ref == nil) { if (ref == nil) {
ref = [[RNFirebaseDatabaseReference alloc] initWithPathAndModifiers:self app:appName key:key refPath:path modifiers:modifiers]; ref = [[RNFirebaseDatabaseReference alloc] initWithPathAndModifiers:self appDisplayName:appDisplayName key:key refPath:path modifiers:modifiers];
_dbReferences[key] = ref; _dbReferences[key] = ref;
} }
return ref; return ref;
@ -380,20 +380,20 @@ RCT_EXPORT_METHOD(off:(NSString *) key
return errorMap; return errorMap;
} }
- (NSDictionary *)createTransactionUpdateMap:(NSString *)appName transactionId:(NSNumber *)transactionId updatesData:(FIRMutableData *)updatesData { - (NSDictionary *)createTransactionUpdateMap:(NSString *)appDisplayName transactionId:(NSNumber *)transactionId updatesData:(FIRMutableData *)updatesData {
NSMutableDictionary *updatesMap = [[NSMutableDictionary alloc] init]; NSMutableDictionary *updatesMap = [[NSMutableDictionary alloc] init];
[updatesMap setValue:transactionId forKey:@"id"]; [updatesMap setValue:transactionId forKey:@"id"];
[updatesMap setValue:@"update" forKey:@"type"]; [updatesMap setValue:@"update" forKey:@"type"];
[updatesMap setValue:appName forKey:@"appName"]; [updatesMap setValue:appDisplayName forKey:@"appName"];
[updatesMap setValue:updatesData.value forKey:@"value"]; [updatesMap setValue:updatesData.value forKey:@"value"];
return updatesMap; return updatesMap;
} }
- (NSDictionary *)createTransactionResultMap:(NSString *)appName transactionId:(NSNumber *)transactionId error:(NSError *)error committed:(BOOL)committed snapshot:(FIRDataSnapshot *)snapshot { - (NSDictionary *)createTransactionResultMap:(NSString *)appDisplayName transactionId:(NSNumber *)transactionId error:(NSError *)error committed:(BOOL)committed snapshot:(FIRDataSnapshot *)snapshot {
NSMutableDictionary *resultMap = [[NSMutableDictionary alloc] init]; NSMutableDictionary *resultMap = [[NSMutableDictionary alloc] init];
[resultMap setValue:transactionId forKey:@"id"]; [resultMap setValue:transactionId forKey:@"id"];
[resultMap setValue:appName forKey:@"appName"]; [resultMap setValue:appDisplayName forKey:@"appName"];
// TODO: no timeout on iOS // TODO: no timeout on iOS
[resultMap setValue:@(committed) forKey:@"committed"]; [resultMap setValue:@(committed) forKey:@"committed"];
// TODO: no interrupted on iOS // TODO: no interrupted on iOS

View File

@ -12,12 +12,12 @@
@interface RNFirebaseDatabaseReference : NSObject @interface RNFirebaseDatabaseReference : NSObject
@property RCTEventEmitter *emitter; @property RCTEventEmitter *emitter;
@property FIRDatabaseQuery *query; @property FIRDatabaseQuery *query;
@property NSString *app; @property NSString *appDisplayName;
@property NSString *key; @property NSString *key;
@property NSString *path; @property NSString *path;
@property NSMutableDictionary *listeners; @property NSMutableDictionary *listeners;
- (id)initWithPathAndModifiers:(RCTEventEmitter *)emitter app:(NSString *)app key:(NSString *)key refPath:(NSString *)refPath modifiers:(NSArray *)modifiers; - (id)initWithPathAndModifiers:(RCTEventEmitter *)emitter appDisplayName:(NSString *)appDisplayName key:(NSString *)key refPath:(NSString *)refPath modifiers:(NSArray *)modifiers;
- (void)on:(NSString *) eventName registration:(NSDictionary *) registration; - (void)on:(NSString *) eventName registration:(NSDictionary *) registration;
- (void)once:(NSString *) eventType resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject; - (void)once:(NSString *) eventType resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
- (void)removeEventListener:(NSString *)eventRegistrationKey; - (void)removeEventListener:(NSString *)eventRegistrationKey;

View File

@ -5,14 +5,14 @@
#if __has_include(<FirebaseDatabase/FIRDatabase.h>) #if __has_include(<FirebaseDatabase/FIRDatabase.h>)
- (id)initWithPathAndModifiers:(RCTEventEmitter *)emitter - (id)initWithPathAndModifiers:(RCTEventEmitter *)emitter
app:(NSString *) app appDisplayName:(NSString *) appDisplayName
key:(NSString *) key key:(NSString *) key
refPath:(NSString *) refPath refPath:(NSString *) refPath
modifiers:(NSArray *) modifiers { modifiers:(NSArray *) modifiers {
self = [super init]; self = [super init];
if (self) { if (self) {
_emitter = emitter; _emitter = emitter;
_app = app; _appDisplayName = appDisplayName;
_key = key; _key = key;
_path = refPath; _path = refPath;
_listeners = [[NSMutableDictionary alloc] init]; _listeners = [[NSMutableDictionary alloc] init];
@ -123,7 +123,7 @@
- (FIRDatabaseQuery *)buildQueryAtPathWithModifiers:(NSString *) path - (FIRDatabaseQuery *)buildQueryAtPathWithModifiers:(NSString *) path
modifiers:(NSArray *)modifiers { modifiers:(NSArray *)modifiers {
FIRDatabase *firebaseDatabase = [RNFirebaseDatabase getDatabaseForApp:_app]; FIRDatabase *firebaseDatabase = [RNFirebaseDatabase getDatabaseForApp:_appDisplayName];
FIRDatabaseQuery *query = [[firebaseDatabase reference] child:path]; FIRDatabaseQuery *query = [[firebaseDatabase reference] child:path];
for (NSDictionary *modifier in modifiers) { for (NSDictionary *modifier in modifiers) {

View File

@ -13,7 +13,7 @@
+ (void)promiseRejectException:(RCTPromiseRejectBlock)reject error:(NSError *)error; + (void)promiseRejectException:(RCTPromiseRejectBlock)reject error:(NSError *)error;
+ (FIRFirestore *)getFirestoreForApp:(NSString *)appName; + (FIRFirestore *)getFirestoreForApp:(NSString *)appDisplayName;
+ (NSDictionary *)getJSError:(NSError *)nativeError; + (NSDictionary *)getJSError:(NSError *)nativeError;
@end @end

View File

@ -22,17 +22,17 @@ RCT_EXPORT_METHOD(enableLogging:(BOOL) enabled) {
[FIRFirestore enableLogging:enabled]; [FIRFirestore enableLogging:enabled];
} }
RCT_EXPORT_METHOD(collectionGet:(NSString *) appName RCT_EXPORT_METHOD(collectionGet:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
filters:(NSArray *) filters filters:(NSArray *) filters
orders:(NSArray *) orders orders:(NSArray *) orders
options:(NSDictionary *) options options:(NSDictionary *) options
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
[[self getCollectionForAppPath:appName path:path filters:filters orders:orders options:options] get:resolve rejecter:reject]; [[self getCollectionForAppPath:appDisplayName path:path filters:filters orders:orders options:options] get:resolve rejecter:reject];
} }
RCT_EXPORT_METHOD(collectionOffSnapshot:(NSString *) appName RCT_EXPORT_METHOD(collectionOffSnapshot:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
filters:(NSArray *) filters filters:(NSArray *) filters
orders:(NSArray *) orders orders:(NSArray *) orders
@ -41,22 +41,22 @@ RCT_EXPORT_METHOD(collectionOffSnapshot:(NSString *) appName
[RNFirebaseFirestoreCollectionReference offSnapshot:listenerId]; [RNFirebaseFirestoreCollectionReference offSnapshot:listenerId];
} }
RCT_EXPORT_METHOD(collectionOnSnapshot:(NSString *) appName RCT_EXPORT_METHOD(collectionOnSnapshot:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
filters:(NSArray *) filters filters:(NSArray *) filters
orders:(NSArray *) orders orders:(NSArray *) orders
options:(NSDictionary *) options options:(NSDictionary *) options
listenerId:(nonnull NSString *) listenerId listenerId:(nonnull NSString *) listenerId
queryListenOptions:(NSDictionary *) queryListenOptions) { queryListenOptions:(NSDictionary *) queryListenOptions) {
RNFirebaseFirestoreCollectionReference *ref = [self getCollectionForAppPath:appName path:path filters:filters orders:orders options:options]; RNFirebaseFirestoreCollectionReference *ref = [self getCollectionForAppPath:appDisplayName path:path filters:filters orders:orders options:options];
[ref onSnapshot:listenerId queryListenOptions:queryListenOptions]; [ref onSnapshot:listenerId queryListenOptions:queryListenOptions];
} }
RCT_EXPORT_METHOD(documentBatch:(NSString *) appName RCT_EXPORT_METHOD(documentBatch:(NSString *) appDisplayName
writes:(NSArray *) writes writes:(NSArray *) writes
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
FIRFirestore *firestore = [RNFirebaseFirestore getFirestoreForApp:appName]; FIRFirestore *firestore = [RNFirebaseFirestore getFirestoreForApp:appDisplayName];
FIRWriteBatch *batch = [firestore batch]; FIRWriteBatch *batch = [firestore batch];
for (NSDictionary *write in writes) { for (NSDictionary *write in writes) {
@ -89,56 +89,56 @@ RCT_EXPORT_METHOD(documentBatch:(NSString *) appName
}]; }];
} }
RCT_EXPORT_METHOD(documentDelete:(NSString *) appName RCT_EXPORT_METHOD(documentDelete:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
[[self getDocumentForAppPath:appName path:path] delete:resolve rejecter:reject]; [[self getDocumentForAppPath:appDisplayName path:path] delete:resolve rejecter:reject];
} }
RCT_EXPORT_METHOD(documentGet:(NSString *) appName RCT_EXPORT_METHOD(documentGet:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
[[self getDocumentForAppPath:appName path:path] get:resolve rejecter:reject]; [[self getDocumentForAppPath:appDisplayName path:path] get:resolve rejecter:reject];
} }
RCT_EXPORT_METHOD(documentGetAll:(NSString *) appName RCT_EXPORT_METHOD(documentGetAll:(NSString *) appDisplayName
documents:(NSString *) documents documents:(NSString *) documents
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
// Not supported on iOS out of the box // Not supported on iOS out of the box
} }
RCT_EXPORT_METHOD(documentOffSnapshot:(NSString *) appName RCT_EXPORT_METHOD(documentOffSnapshot:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
listenerId:(nonnull NSString *) listenerId) { listenerId:(nonnull NSString *) listenerId) {
[RNFirebaseFirestoreDocumentReference offSnapshot:listenerId]; [RNFirebaseFirestoreDocumentReference offSnapshot:listenerId];
} }
RCT_EXPORT_METHOD(documentOnSnapshot:(NSString *) appName RCT_EXPORT_METHOD(documentOnSnapshot:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
listenerId:(nonnull NSString *) listenerId listenerId:(nonnull NSString *) listenerId
docListenOptions:(NSDictionary *) docListenOptions) { docListenOptions:(NSDictionary *) docListenOptions) {
RNFirebaseFirestoreDocumentReference *ref = [self getDocumentForAppPath:appName path:path]; RNFirebaseFirestoreDocumentReference *ref = [self getDocumentForAppPath:appDisplayName path:path];
[ref onSnapshot:listenerId docListenOptions:docListenOptions]; [ref onSnapshot:listenerId docListenOptions:docListenOptions];
} }
RCT_EXPORT_METHOD(documentSet:(NSString *) appName RCT_EXPORT_METHOD(documentSet:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
data:(NSDictionary *) data data:(NSDictionary *) data
options:(NSDictionary *) options options:(NSDictionary *) options
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
[[self getDocumentForAppPath:appName path:path] set:data options:options resolver:resolve rejecter:reject]; [[self getDocumentForAppPath:appDisplayName path:path] set:data options:options resolver:resolve rejecter:reject];
} }
RCT_EXPORT_METHOD(documentUpdate:(NSString *) appName RCT_EXPORT_METHOD(documentUpdate:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
data:(NSDictionary *) data data:(NSDictionary *) data
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
[[self getDocumentForAppPath:appName path:path] update:data resolver:resolve rejecter:reject]; [[self getDocumentForAppPath:appDisplayName path:path] update:data resolver:resolve rejecter:reject];
} }
/* /*
@ -149,17 +149,17 @@ RCT_EXPORT_METHOD(documentUpdate:(NSString *) appName
reject([jsError valueForKey:@"code"], [jsError valueForKey:@"message"], error); reject([jsError valueForKey:@"code"], [jsError valueForKey:@"message"], error);
} }
+ (FIRFirestore *)getFirestoreForApp:(NSString *)appName { + (FIRFirestore *)getFirestoreForApp:(NSString *)appDisplayName {
FIRApp *app = [FIRApp appNamed:appName]; FIRApp *app = [RNFirebaseUtil getApp:appDisplayName];
return [FIRFirestore firestoreForApp:app]; return [FIRFirestore firestoreForApp:app];
} }
- (RNFirebaseFirestoreCollectionReference *)getCollectionForAppPath:(NSString *)appName path:(NSString *)path filters:(NSArray *)filters orders:(NSArray *)orders options:(NSDictionary *)options { - (RNFirebaseFirestoreCollectionReference *)getCollectionForAppPath:(NSString *)appDisplayName path:(NSString *)path filters:(NSArray *)filters orders:(NSArray *)orders options:(NSDictionary *)options {
return [[RNFirebaseFirestoreCollectionReference alloc] initWithPathAndModifiers:self app:appName path:path filters:filters orders:orders options:options]; return [[RNFirebaseFirestoreCollectionReference alloc] initWithPathAndModifiers:self appDisplayName:appDisplayName path:path filters:filters orders:orders options:options];
} }
- (RNFirebaseFirestoreDocumentReference *)getDocumentForAppPath:(NSString *)appName path:(NSString *)path { - (RNFirebaseFirestoreDocumentReference *)getDocumentForAppPath:(NSString *)appDisplayName path:(NSString *)path {
return [[RNFirebaseFirestoreDocumentReference alloc] initWithPath:self app:appName path:path]; return [[RNFirebaseFirestoreDocumentReference alloc] initWithPath:self appDisplayName:appDisplayName path:path];
} }
// TODO: Move to error util for use in other modules // TODO: Move to error util for use in other modules

View File

@ -13,14 +13,14 @@
@interface RNFirebaseFirestoreCollectionReference : NSObject @interface RNFirebaseFirestoreCollectionReference : NSObject
@property RCTEventEmitter *emitter; @property RCTEventEmitter *emitter;
@property NSString *app; @property NSString *appDisplayName;
@property NSString *path; @property NSString *path;
@property NSArray *filters; @property NSArray *filters;
@property NSArray *orders; @property NSArray *orders;
@property NSDictionary *options; @property NSDictionary *options;
@property FIRQuery *query; @property FIRQuery *query;
- (id)initWithPathAndModifiers:(RCTEventEmitter *)emitter app:(NSString *)app path:(NSString *)path filters:(NSArray *)filters orders:(NSArray *)orders options:(NSDictionary *)options; - (id)initWithPathAndModifiers:(RCTEventEmitter *)emitter appDisplayName:(NSString *)appDisplayName path:(NSString *)path filters:(NSArray *)filters orders:(NSArray *)orders options:(NSDictionary *)options;
- (void)get:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject; - (void)get:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
+ (void)offSnapshot:(NSString *)listenerId; + (void)offSnapshot:(NSString *)listenerId;
- (void)onSnapshot:(NSString *)listenerId queryListenOptions:(NSDictionary *) queryListenOptions; - (void)onSnapshot:(NSString *)listenerId queryListenOptions:(NSDictionary *) queryListenOptions;

View File

@ -7,7 +7,7 @@
static NSMutableDictionary *_listeners; static NSMutableDictionary *_listeners;
- (id)initWithPathAndModifiers:(RCTEventEmitter *) emitter - (id)initWithPathAndModifiers:(RCTEventEmitter *) emitter
app:(NSString *) app appDisplayName:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
filters:(NSArray *) filters filters:(NSArray *) filters
orders:(NSArray *) orders orders:(NSArray *) orders
@ -15,7 +15,7 @@ static NSMutableDictionary *_listeners;
self = [super init]; self = [super init];
if (self) { if (self) {
_emitter = emitter; _emitter = emitter;
_app = app; _appDisplayName = appDisplayName;
_path = path; _path = path;
_filters = filters; _filters = filters;
_orders = orders; _orders = orders;
@ -64,7 +64,7 @@ queryListenOptions:(NSDictionary *) queryListenOptions {
[self handleQuerySnapshotEvent:listenerId querySnapshot:snapshot]; [self handleQuerySnapshotEvent:listenerId querySnapshot:snapshot];
} }
}; };
FIRQueryListenOptions *options = [[FIRQueryListenOptions alloc] init]; FIRQueryListenOptions *options = [[FIRQueryListenOptions alloc] init];
if (queryListenOptions) { if (queryListenOptions) {
if (queryListenOptions[@"includeDocumentMetadataChanges"]) { if (queryListenOptions[@"includeDocumentMetadataChanges"]) {
@ -74,14 +74,14 @@ queryListenOptions:(NSDictionary *) queryListenOptions {
[options includeQueryMetadataChanges:TRUE]; [options includeQueryMetadataChanges:TRUE];
} }
} }
id<FIRListenerRegistration> listener = [_query addSnapshotListenerWithOptions:options listener:listenerBlock]; id<FIRListenerRegistration> listener = [_query addSnapshotListenerWithOptions:options listener:listenerBlock];
_listeners[listenerId] = listener; _listeners[listenerId] = listener;
} }
} }
- (FIRQuery *)buildQuery { - (FIRQuery *)buildQuery {
FIRFirestore *firestore = [RNFirebaseFirestore getFirestoreForApp:_app]; FIRFirestore *firestore = [RNFirebaseFirestore getFirestoreForApp:_appDisplayName];
FIRQuery *query = (FIRQuery*)[firestore collectionWithPath:_path]; FIRQuery *query = (FIRQuery*)[firestore collectionWithPath:_path];
query = [self applyFilters:firestore query:query]; query = [self applyFilters:firestore query:query];
query = [self applyOrders:query]; query = [self applyOrders:query];
@ -152,7 +152,7 @@ queryListenOptions:(NSDictionary *) queryListenOptions {
- (void)handleQuerySnapshotError:(NSString *)listenerId - (void)handleQuerySnapshotError:(NSString *)listenerId
error:(NSError *)error { error:(NSError *)error {
NSMutableDictionary *event = [[NSMutableDictionary alloc] init]; NSMutableDictionary *event = [[NSMutableDictionary alloc] init];
[event setValue:_app forKey:@"appName"]; [event setValue:_appDisplayName forKey:@"appName"];
[event setValue:_path forKey:@"path"]; [event setValue:_path forKey:@"path"];
[event setValue:listenerId forKey:@"listenerId"]; [event setValue:listenerId forKey:@"listenerId"];
[event setValue:[RNFirebaseFirestore getJSError:error] forKey:@"error"]; [event setValue:[RNFirebaseFirestore getJSError:error] forKey:@"error"];
@ -163,7 +163,7 @@ queryListenOptions:(NSDictionary *) queryListenOptions {
- (void)handleQuerySnapshotEvent:(NSString *)listenerId - (void)handleQuerySnapshotEvent:(NSString *)listenerId
querySnapshot:(FIRQuerySnapshot *)querySnapshot { querySnapshot:(FIRQuerySnapshot *)querySnapshot {
NSMutableDictionary *event = [[NSMutableDictionary alloc] init]; NSMutableDictionary *event = [[NSMutableDictionary alloc] init];
[event setValue:_app forKey:@"appName"]; [event setValue:_appDisplayName forKey:@"appName"];
[event setValue:_path forKey:@"path"]; [event setValue:_path forKey:@"path"];
[event setValue:listenerId forKey:@"listenerId"]; [event setValue:listenerId forKey:@"listenerId"];
[event setValue:[RNFirebaseFirestoreCollectionReference snapshotToDictionary:querySnapshot] forKey:@"querySnapshot"]; [event setValue:[RNFirebaseFirestoreCollectionReference snapshotToDictionary:querySnapshot] forKey:@"querySnapshot"];

View File

@ -13,11 +13,11 @@
@interface RNFirebaseFirestoreDocumentReference : NSObject @interface RNFirebaseFirestoreDocumentReference : NSObject
@property RCTEventEmitter *emitter; @property RCTEventEmitter *emitter;
@property NSString *app; @property NSString *appDisplayName;
@property NSString *path; @property NSString *path;
@property FIRDocumentReference *ref; @property FIRDocumentReference *ref;
- (id)initWithPath:(RCTEventEmitter *)emitter app:(NSString *)app path:(NSString *)path; - (id)initWithPath:(RCTEventEmitter *)emitter appDisplayName:(NSString *)appDisplayName path:(NSString *)path;
- (void)delete:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject; - (void)delete:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
- (void)get:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject; - (void)get:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
+ (void)offSnapshot:(NSString *)listenerId; + (void)offSnapshot:(NSString *)listenerId;

View File

@ -7,14 +7,14 @@
static NSMutableDictionary *_listeners; static NSMutableDictionary *_listeners;
- (id)initWithPath:(RCTEventEmitter *)emitter - (id)initWithPath:(RCTEventEmitter *)emitter
app:(NSString *) app appDisplayName:(NSString *) appDisplayName
path:(NSString *) path { path:(NSString *) path {
self = [super init]; self = [super init];
if (self) { if (self) {
_emitter = emitter; _emitter = emitter;
_app = app; _appDisplayName = appDisplayName;
_path = path; _path = path;
_ref = [[RNFirebaseFirestore getFirestoreForApp:_app] documentWithPath:_path]; _ref = [[RNFirebaseFirestore getFirestoreForApp:_appDisplayName] documentWithPath:_path];
} }
// Initialise the static listeners object if required // Initialise the static listeners object if required
if (!_listeners) { if (!_listeners) {
@ -78,7 +78,7 @@ static NSMutableDictionary *_listeners;
options:(NSDictionary *) options options:(NSDictionary *) options
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject { rejecter:(RCTPromiseRejectBlock) reject {
NSDictionary *dictionary = [RNFirebaseFirestoreDocumentReference parseJSMap:[RNFirebaseFirestore getFirestoreForApp:_app] jsMap:data]; NSDictionary *dictionary = [RNFirebaseFirestoreDocumentReference parseJSMap:[RNFirebaseFirestore getFirestoreForApp:_appDisplayName] jsMap:data];
if (options && options[@"merge"]) { if (options && options[@"merge"]) {
[_ref setData:dictionary options:[FIRSetOptions merge] completion:^(NSError * _Nullable error) { [_ref setData:dictionary options:[FIRSetOptions merge] completion:^(NSError * _Nullable error) {
[RNFirebaseFirestoreDocumentReference handleWriteResponse:error resolver:resolve rejecter:reject]; [RNFirebaseFirestoreDocumentReference handleWriteResponse:error resolver:resolve rejecter:reject];
@ -93,7 +93,7 @@ static NSMutableDictionary *_listeners;
- (void)update:(NSDictionary *) data - (void)update:(NSDictionary *) data
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject { rejecter:(RCTPromiseRejectBlock) reject {
NSDictionary *dictionary = [RNFirebaseFirestoreDocumentReference parseJSMap:[RNFirebaseFirestore getFirestoreForApp:_app] jsMap:data]; NSDictionary *dictionary = [RNFirebaseFirestoreDocumentReference parseJSMap:[RNFirebaseFirestore getFirestoreForApp:_appDisplayName] jsMap:data];
[_ref updateData:dictionary completion:^(NSError * _Nullable error) { [_ref updateData:dictionary completion:^(NSError * _Nullable error) {
[RNFirebaseFirestoreDocumentReference handleWriteResponse:error resolver:resolve rejecter:reject]; [RNFirebaseFirestoreDocumentReference handleWriteResponse:error resolver:resolve rejecter:reject];
}]; }];
@ -131,7 +131,7 @@ static NSMutableDictionary *_listeners;
- (void)handleDocumentSnapshotError:(NSString *)listenerId - (void)handleDocumentSnapshotError:(NSString *)listenerId
error:(NSError *)error { error:(NSError *)error {
NSMutableDictionary *event = [[NSMutableDictionary alloc] init]; NSMutableDictionary *event = [[NSMutableDictionary alloc] init];
[event setValue:_app forKey:@"appName"]; [event setValue:_appDisplayName forKey:@"appName"];
[event setValue:_path forKey:@"path"]; [event setValue:_path forKey:@"path"];
[event setValue:listenerId forKey:@"listenerId"]; [event setValue:listenerId forKey:@"listenerId"];
[event setValue:[RNFirebaseFirestore getJSError:error] forKey:@"error"]; [event setValue:[RNFirebaseFirestore getJSError:error] forKey:@"error"];
@ -142,7 +142,7 @@ static NSMutableDictionary *_listeners;
- (void)handleDocumentSnapshotEvent:(NSString *)listenerId - (void)handleDocumentSnapshotEvent:(NSString *)listenerId
documentSnapshot:(FIRDocumentSnapshot *)documentSnapshot { documentSnapshot:(FIRDocumentSnapshot *)documentSnapshot {
NSMutableDictionary *event = [[NSMutableDictionary alloc] init]; NSMutableDictionary *event = [[NSMutableDictionary alloc] init];
[event setValue:_app forKey:@"appName"]; [event setValue:_appDisplayName forKey:@"appName"];
[event setValue:_path forKey:@"path"]; [event setValue:_path forKey:@"path"];
[event setValue:listenerId forKey:@"listenerId"]; [event setValue:listenerId forKey:@"listenerId"];
[event setValue:[RNFirebaseFirestoreDocumentReference snapshotToDictionary:documentSnapshot] forKey:@"documentSnapshot"]; [event setValue:[RNFirebaseFirestoreDocumentReference snapshotToDictionary:documentSnapshot] forKey:@"documentSnapshot"];

View File

@ -23,11 +23,11 @@ RCT_EXPORT_MODULE(RNFirebaseStorage);
@url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#delete @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#delete
@param NSString path @param NSString path
*/ */
RCT_EXPORT_METHOD(delete:(NSString *) appName RCT_EXPORT_METHOD(delete:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
FIRStorageReference *fileRef = [self getReference:path appName:appName]; FIRStorageReference *fileRef = [self getReference:path appDisplayName:appDisplayName];
[fileRef deleteWithCompletion:^(NSError *_Nullable error) { [fileRef deleteWithCompletion:^(NSError *_Nullable error) {
if (error != nil) { if (error != nil) {
@ -44,11 +44,11 @@ RCT_EXPORT_METHOD(delete:(NSString *) appName
@url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#getDownloadURL @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#getDownloadURL
@param NSString path @param NSString path
*/ */
RCT_EXPORT_METHOD(getDownloadURL:(NSString *) appName RCT_EXPORT_METHOD(getDownloadURL:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
FIRStorageReference *fileRef = [self getReference:path appName:appName]; FIRStorageReference *fileRef = [self getReference:path appDisplayName:appDisplayName];
[fileRef downloadURLWithCompletion:^(NSURL *_Nullable URL, NSError *_Nullable error) { [fileRef downloadURLWithCompletion:^(NSURL *_Nullable URL, NSError *_Nullable error) {
if (error != nil) { if (error != nil) {
@ -65,11 +65,11 @@ RCT_EXPORT_METHOD(getDownloadURL:(NSString *) appName
@url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#getMetadata @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#getMetadata
@param NSString path @param NSString path
*/ */
RCT_EXPORT_METHOD(getMetadata:(NSString *) appName RCT_EXPORT_METHOD(getMetadata:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
FIRStorageReference *fileRef = [self getReference:path appName:appName]; FIRStorageReference *fileRef = [self getReference:path appDisplayName:appDisplayName];
[fileRef metadataWithCompletion:^(FIRStorageMetadata *_Nullable metadata, NSError *_Nullable error) { [fileRef metadataWithCompletion:^(FIRStorageMetadata *_Nullable metadata, NSError *_Nullable error) {
if (error != nil) { if (error != nil) {
@ -87,12 +87,12 @@ RCT_EXPORT_METHOD(getMetadata:(NSString *) appName
@param NSString path @param NSString path
@param NSDictionary metadata @param NSDictionary metadata
*/ */
RCT_EXPORT_METHOD(updateMetadata:(NSString *) appName RCT_EXPORT_METHOD(updateMetadata:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
metadata:(NSDictionary *) metadata metadata:(NSDictionary *) metadata
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
FIRStorageReference *fileRef = [self getReference:path appName:appName]; FIRStorageReference *fileRef = [self getReference:path appDisplayName:appDisplayName];
FIRStorageMetadata *firmetadata = [self buildMetadataFromMap:metadata]; FIRStorageMetadata *firmetadata = [self buildMetadataFromMap:metadata];
[fileRef updateMetadata:firmetadata completion:^(FIRStorageMetadata *_Nullable metadata, NSError *_Nullable error) { [fileRef updateMetadata:firmetadata completion:^(FIRStorageMetadata *_Nullable metadata, NSError *_Nullable error) {
@ -111,12 +111,12 @@ RCT_EXPORT_METHOD(updateMetadata:(NSString *) appName
@param NSString path @param NSString path
@param NSString localPath @param NSString localPath
*/ */
RCT_EXPORT_METHOD(downloadFile:(NSString *) appName RCT_EXPORT_METHOD(downloadFile:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
localPath:(NSString *) localPath localPath:(NSString *) localPath
resolver:(RCTPromiseResolveBlock) resolve resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) { rejecter:(RCTPromiseRejectBlock) reject) {
FIRStorageReference *fileRef = [self getReference:path appName:appName]; FIRStorageReference *fileRef = [self getReference:path appDisplayName:appDisplayName];
NSURL *localFile = [NSURL fileURLWithPath:localPath]; NSURL *localFile = [NSURL fileURLWithPath:localPath];
FIRStorageDownloadTask *downloadTask = [fileRef writeToFile:localFile]; FIRStorageDownloadTask *downloadTask = [fileRef writeToFile:localFile];
@ -124,25 +124,25 @@ RCT_EXPORT_METHOD(downloadFile:(NSString *) appName
[downloadTask observeStatus:FIRStorageTaskStatusResume handler:^(FIRStorageTaskSnapshot *snapshot) { [downloadTask observeStatus:FIRStorageTaskStatusResume handler:^(FIRStorageTaskSnapshot *snapshot) {
// download resumed, also fires when the upload starts // download resumed, also fires when the upload starts
NSDictionary *event = [self getDownloadTaskAsDictionary:snapshot]; NSDictionary *event = [self getDownloadTaskAsDictionary:snapshot];
[self sendJSEvent:appName type:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event]; [self sendJSEvent:appDisplayName type:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event];
}]; }];
[downloadTask observeStatus:FIRStorageTaskStatusPause handler:^(FIRStorageTaskSnapshot *snapshot) { [downloadTask observeStatus:FIRStorageTaskStatusPause handler:^(FIRStorageTaskSnapshot *snapshot) {
// download paused // download paused
NSDictionary *event = [self getDownloadTaskAsDictionary:snapshot]; NSDictionary *event = [self getDownloadTaskAsDictionary:snapshot];
[self sendJSEvent:appName type:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event]; [self sendJSEvent:appDisplayName type:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event];
}]; }];
[downloadTask observeStatus:FIRStorageTaskStatusProgress handler:^(FIRStorageTaskSnapshot *snapshot) { [downloadTask observeStatus:FIRStorageTaskStatusProgress handler:^(FIRStorageTaskSnapshot *snapshot) {
// download reported progress // download reported progress
NSDictionary *event = [self getDownloadTaskAsDictionary:snapshot]; NSDictionary *event = [self getDownloadTaskAsDictionary:snapshot];
[self sendJSEvent:appName type:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event]; [self sendJSEvent:appDisplayName type:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event];
}]; }];
[downloadTask observeStatus:FIRStorageTaskStatusSuccess handler:^(FIRStorageTaskSnapshot *snapshot) { [downloadTask observeStatus:FIRStorageTaskStatusSuccess handler:^(FIRStorageTaskSnapshot *snapshot) {
// download completed successfully // download completed successfully
NSDictionary *resp = [self getDownloadTaskAsDictionary:snapshot]; NSDictionary *resp = [self getDownloadTaskAsDictionary:snapshot];
[self sendJSEvent:appName type:STORAGE_EVENT path:path title:STORAGE_DOWNLOAD_SUCCESS props:resp]; [self sendJSEvent:appDisplayName type:STORAGE_EVENT path:path title:STORAGE_DOWNLOAD_SUCCESS props:resp];
resolve(resp); resolve(resp);
}]; }];
@ -161,9 +161,10 @@ RCT_EXPORT_METHOD(downloadFile:(NSString *) appName
@url https://firebase.google.com/docs/reference/js/firebase.storage.Storage#setMaxDownloadRetryTime @url https://firebase.google.com/docs/reference/js/firebase.storage.Storage#setMaxDownloadRetryTime
@param NSNumber milliseconds @param NSNumber milliseconds
*/ */
RCT_EXPORT_METHOD(setMaxDownloadRetryTime:(NSString *) appName RCT_EXPORT_METHOD(setMaxDownloadRetryTime:(NSString *) appDisplayName
milliseconds:(NSNumber *) milliseconds) { milliseconds:(NSNumber *) milliseconds) {
[[FIRStorage storageForApp:[FIRApp appNamed:appName]] setMaxDownloadRetryTime:[milliseconds doubleValue]]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
[[FIRStorage storageForApp:firApp] setMaxDownloadRetryTime:[milliseconds doubleValue]];
} }
/** /**
@ -172,9 +173,10 @@ RCT_EXPORT_METHOD(setMaxDownloadRetryTime:(NSString *) appName
@url https://firebase.google.com/docs/reference/js/firebase.storage.Storage#setMaxOperationRetryTime @url https://firebase.google.com/docs/reference/js/firebase.storage.Storage#setMaxOperationRetryTime
@param NSNumber milliseconds @param NSNumber milliseconds
*/ */
RCT_EXPORT_METHOD(setMaxOperationRetryTime:(NSString *) appName RCT_EXPORT_METHOD(setMaxOperationRetryTime:(NSString *) appDisplayName
milliseconds:(NSNumber *) milliseconds) { milliseconds:(NSNumber *) milliseconds) {
[[FIRStorage storageForApp:[FIRApp appNamed:appName]] setMaxOperationRetryTime:[milliseconds doubleValue]]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
[[FIRStorage storageForApp:firApp] setMaxOperationRetryTime:[milliseconds doubleValue]];
} }
/** /**
@ -182,9 +184,10 @@ RCT_EXPORT_METHOD(setMaxOperationRetryTime:(NSString *) appName
@url https://firebase.google.com/docs/reference/js/firebase.storage.Storage#setMaxUploadRetryTime @url https://firebase.google.com/docs/reference/js/firebase.storage.Storage#setMaxUploadRetryTime
*/ */
RCT_EXPORT_METHOD(setMaxUploadRetryTime:(NSString *) appName RCT_EXPORT_METHOD(setMaxUploadRetryTime:(NSString *) appDisplayName
milliseconds:(NSNumber *) milliseconds) { milliseconds:(NSNumber *) milliseconds) {
[[FIRStorage storageForApp:[FIRApp appNamed:appName]] setMaxUploadRetryTime:[milliseconds doubleValue]]; FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
[[FIRStorage storageForApp:firApp] setMaxUploadRetryTime:[milliseconds doubleValue]];
} }
/** /**
@ -195,7 +198,7 @@ RCT_EXPORT_METHOD(setMaxUploadRetryTime:(NSString *) appName
@param NSString localPath @param NSString localPath
@param NSDictionary metadata @param NSDictionary metadata
*/ */
RCT_EXPORT_METHOD(putFile:(NSString *) appName RCT_EXPORT_METHOD(putFile:(NSString *) appDisplayName
path:(NSString *) path path:(NSString *) path
localPath:(NSString *) localPath localPath:(NSString *) localPath
metadata:(NSDictionary *) metadata metadata:(NSDictionary *) metadata
@ -224,7 +227,7 @@ RCT_EXPORT_METHOD(putFile:(NSString *) appName
if (info[PHImageErrorKey] == nil) { if (info[PHImageErrorKey] == nil) {
if (UTTypeConformsTo((__bridge CFStringRef)dataUTI, kUTTypeJPEG)) { if (UTTypeConformsTo((__bridge CFStringRef)dataUTI, kUTTypeJPEG)) {
firmetadata.contentType = [self utiToMimeType:dataUTI]; firmetadata.contentType = [self utiToMimeType:dataUTI];
[self uploadData:appName data:imageData firmetadata:firmetadata path:path resolver:resolve rejecter:reject]; [self uploadData:appDisplayName data:imageData firmetadata:firmetadata path:path resolver:resolve rejecter:reject];
} else { } else {
// if the image UTI is not JPEG then convert to JPEG, e.g. HEI // if the image UTI is not JPEG then convert to JPEG, e.g. HEI
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL); CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL);
@ -236,7 +239,7 @@ RCT_EXPORT_METHOD(putFile:(NSString *) appName
CGImageDestinationFinalize(destination); CGImageDestinationFinalize(destination);
// Manually set mimetype to JPEG // Manually set mimetype to JPEG
firmetadata.contentType = @"image/jpeg"; firmetadata.contentType = @"image/jpeg";
[self uploadData:appName data:[NSData dataWithData:imageDataJPEG] firmetadata:firmetadata path:path resolver:resolve rejecter:reject]; [self uploadData:appDisplayName data:[NSData dataWithData:imageDataJPEG] firmetadata:firmetadata path:path resolver:resolve rejecter:reject];
} }
} else { } else {
reject(@"storage/request-image-data-failed", @"Could not obtain image data for the specified file.", nil); reject(@"storage/request-image-data-failed", @"Could not obtain image data for the specified file.", nil);
@ -260,7 +263,7 @@ RCT_EXPORT_METHOD(putFile:(NSString *) appName
[exportSession exportAsynchronouslyWithCompletionHandler:^{ [exportSession exportAsynchronouslyWithCompletionHandler:^{
if (exportSession.status == AVAssetExportSessionStatusCompleted) { if (exportSession.status == AVAssetExportSessionStatusCompleted) {
firmetadata.contentType = [self utiToMimeType:exportSession.outputFileType]; firmetadata.contentType = [self utiToMimeType:exportSession.outputFileType];
[self uploadFile:appName url:tempUrl firmetadata:firmetadata path:path resolver:resolve rejecter:reject]; [self uploadFile:appDisplayName url:tempUrl firmetadata:firmetadata path:path resolver:resolve rejecter:reject];
// we're not cleaning up the temporary file at the moment, just relying on the OS to do that in it's own time - todo? // we're not cleaning up the temporary file at the moment, just relying on the OS to do that in it's own time - todo?
} else { } else {
reject(@"storage/temporary-file-failure", @"Unable to create temporary file for upload.", nil); reject(@"storage/temporary-file-failure", @"Unable to create temporary file for upload.", nil);
@ -274,7 +277,7 @@ RCT_EXPORT_METHOD(putFile:(NSString *) appName
} else { } else {
// TODO: Content type for file? // TODO: Content type for file?
NSData *data = [[NSFileManager defaultManager] contentsAtPath:localPath]; NSData *data = [[NSFileManager defaultManager] contentsAtPath:localPath];
[self uploadData:appName data:data firmetadata:firmetadata path:path resolver:resolve rejecter:reject]; [self uploadData:appDisplayName data:data firmetadata:firmetadata path:path resolver:resolve rejecter:reject];
} }
} }
@ -288,42 +291,42 @@ RCT_EXPORT_METHOD(putFile:(NSString *) appName
return (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)dataUTI, kUTTagClassMIMEType); return (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)dataUTI, kUTTagClassMIMEType);
} }
- (void)uploadFile:(NSString *)appName url:(NSURL *)url firmetadata:(FIRStorageMetadata *)firmetadata path:(NSString *)path resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject { - (void)uploadFile:(NSString *)appDisplayName url:(NSURL *)url firmetadata:(FIRStorageMetadata *)firmetadata path:(NSString *)path resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
FIRStorageReference *fileRef = [self getReference:path appName:appName]; FIRStorageReference *fileRef = [self getReference:path appDisplayName:appDisplayName];
FIRStorageUploadTask *uploadTask = [fileRef putFile:url metadata:firmetadata]; FIRStorageUploadTask *uploadTask = [fileRef putFile:url metadata:firmetadata];
[self addUploadObservers:appName uploadTask:uploadTask path:path resolver:resolve rejecter:reject]; [self addUploadObservers:appDisplayName uploadTask:uploadTask path:path resolver:resolve rejecter:reject];
} }
- (void)uploadData:(NSString *)appName data:(NSData *)data firmetadata:(FIRStorageMetadata *)firmetadata path:(NSString *)path resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject { - (void)uploadData:(NSString *)appDisplayName data:(NSData *)data firmetadata:(FIRStorageMetadata *)firmetadata path:(NSString *)path resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
FIRStorageReference *fileRef = [self getReference:path appName:appName]; FIRStorageReference *fileRef = [self getReference:path appDisplayName:appDisplayName];
FIRStorageUploadTask *uploadTask = [fileRef putData:data metadata:firmetadata]; FIRStorageUploadTask *uploadTask = [fileRef putData:data metadata:firmetadata];
[self addUploadObservers:appName uploadTask:uploadTask path:path resolver:resolve rejecter:reject]; [self addUploadObservers:appDisplayName uploadTask:uploadTask path:path resolver:resolve rejecter:reject];
} }
- (void)addUploadObservers:(NSString *)appName uploadTask:(FIRStorageUploadTask *)uploadTask path:(NSString *)path resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject { - (void)addUploadObservers:(NSString *)appDisplayName uploadTask:(FIRStorageUploadTask *)uploadTask path:(NSString *)path resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
// listen for state changes, errors, and completion of the upload. // listen for state changes, errors, and completion of the upload.
[uploadTask observeStatus:FIRStorageTaskStatusResume handler:^(FIRStorageTaskSnapshot *snapshot) { [uploadTask observeStatus:FIRStorageTaskStatusResume handler:^(FIRStorageTaskSnapshot *snapshot) {
// upload resumed, also fires when the upload starts // upload resumed, also fires when the upload starts
NSDictionary *event = [self getUploadTaskAsDictionary:snapshot]; NSDictionary *event = [self getUploadTaskAsDictionary:snapshot];
[self sendJSEvent:appName type:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event]; [self sendJSEvent:appDisplayName type:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event];
}]; }];
[uploadTask observeStatus:FIRStorageTaskStatusPause handler:^(FIRStorageTaskSnapshot *snapshot) { [uploadTask observeStatus:FIRStorageTaskStatusPause handler:^(FIRStorageTaskSnapshot *snapshot) {
// upload paused // upload paused
NSDictionary *event = [self getUploadTaskAsDictionary:snapshot]; NSDictionary *event = [self getUploadTaskAsDictionary:snapshot];
[self sendJSEvent:appName type:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event]; [self sendJSEvent:appDisplayName type:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event];
}]; }];
[uploadTask observeStatus:FIRStorageTaskStatusProgress handler:^(FIRStorageTaskSnapshot *snapshot) { [uploadTask observeStatus:FIRStorageTaskStatusProgress handler:^(FIRStorageTaskSnapshot *snapshot) {
// upload reported progress // upload reported progress
NSDictionary *event = [self getUploadTaskAsDictionary:snapshot]; NSDictionary *event = [self getUploadTaskAsDictionary:snapshot];
[self sendJSEvent:appName type:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event]; [self sendJSEvent:appDisplayName type:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event];
}]; }];
[uploadTask observeStatus:FIRStorageTaskStatusSuccess handler:^(FIRStorageTaskSnapshot *snapshot) { [uploadTask observeStatus:FIRStorageTaskStatusSuccess handler:^(FIRStorageTaskSnapshot *snapshot) {
// upload completed successfully // upload completed successfully
NSDictionary *resp = [self getUploadTaskAsDictionary:snapshot]; NSDictionary *resp = [self getUploadTaskAsDictionary:snapshot];
[self sendJSEvent:appName type:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:resp]; [self sendJSEvent:appDisplayName type:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:resp];
[self sendJSEvent:appName type:STORAGE_EVENT path:path title:STORAGE_UPLOAD_SUCCESS props:resp]; [self sendJSEvent:appDisplayName type:STORAGE_EVENT path:path title:STORAGE_UPLOAD_SUCCESS props:resp];
resolve(resp); resolve(resp);
}]; }];
@ -335,12 +338,13 @@ RCT_EXPORT_METHOD(putFile:(NSString *) appName
} }
- (FIRStorageReference *)getReference:(NSString *)path - (FIRStorageReference *)getReference:(NSString *)path
appName:(NSString *)appName { appDisplayName:(NSString *)appDisplayName {
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
if ([path hasPrefix:@"url::"]) { if ([path hasPrefix:@"url::"]) {
NSString *url = [path substringFromIndex:5]; NSString *url = [path substringFromIndex:5];
return [[FIRStorage storageForApp:[FIRApp appNamed:appName]] referenceForURL:url]; return [[FIRStorage storageForApp:firApp] referenceForURL:url];
} else { } else {
return [[FIRStorage storageForApp:[FIRApp appNamed:appName]] referenceWithPath:path]; return [[FIRStorage storageForApp:firApp] referenceWithPath:path];
} }
} }
@ -387,13 +391,13 @@ RCT_EXPORT_METHOD(putFile:(NSString *) appName
return @[STORAGE_EVENT, STORAGE_ERROR]; return @[STORAGE_EVENT, STORAGE_ERROR];
} }
- (void)sendJSError:(NSString *)appName error:(NSError *)error path:(NSString *)path { - (void)sendJSError:(NSString *)appDisplayName error:(NSError *)error path:(NSString *)path {
NSDictionary *evt = @{@"path": path, @"message": [error debugDescription]}; NSDictionary *evt = @{@"path": path, @"message": [error debugDescription]};
[self sendJSEvent:appName type:STORAGE_ERROR path:path title:STORAGE_ERROR props:evt]; [self sendJSEvent:appDisplayName type:STORAGE_ERROR path:path title:STORAGE_ERROR props:evt];
} }
- (void)sendJSEvent:(NSString *)appName type:(NSString *)type path:(NSString *)path title:(NSString *)title props:(NSDictionary *)props { - (void)sendJSEvent:(NSString *)appDisplayName type:(NSString *)type path:(NSString *)path title:(NSString *)title props:(NSDictionary *)props {
[RNFirebaseUtil sendJSEvent:self name:type body:@{@"eventName": title, @"appName": appName, @"path": path, @"body": props}]; [RNFirebaseUtil sendJSEvent:self name:type body:@{@"eventName": title, @"appName": appDisplayName, @"path": path, @"body": props}];
} }
/** /**

49
lib/index.d.ts vendored
View File

@ -64,6 +64,10 @@ declare module "react-native-firebase" {
*/ */
crash(): RNFirebase.crash.Crash; crash(): RNFirebase.crash.Crash;
static fabric: {
crashlytics(): RNFirebase.crashlytics.Crashlytics;
};
apps: Array<string>; apps: Array<string>;
googleApiAvailability: RNFirebase.GoogleApiAvailabilityType; googleApiAvailability: RNFirebase.GoogleApiAvailabilityType;
@ -846,5 +850,50 @@ declare module "react-native-firebase" {
[key: string]: any; [key: string]: any;
} }
} }
namespace crashlytics {
interface Crashlytics {
/**
* Forces a crash. Useful for testing your application is set up correctly.
*/
crash(): void;
/**
* Logs a message that will appear in any subsequent crash reports.
*/
log(message: string): void;
/**
* Logs a non fatal exception.
*/
recordError(code: number, message: string): void;
/**
* Set a boolean value to show alongside any subsequent crash reports.
*/
setBoolValue(key: string, value: boolean): void;
/**
* Set a float value to show alongside any subsequent crash reports.
*/
setFloatValue(key: string, value: number): void;
/**
* Set an integer value to show alongside any subsequent crash reports.
*/
setIntValue(key: string, value: number): void;
/**
* Set a string value to show alongside any subsequent crash reports.
*/
setStringValue(key: string, value: string): void;
/**
* Set the user ID to show alongside any subsequent crash reports.
*/
setUserIdentifier(userId: string): void;
}
}
} }
} }

View File

@ -1,8 +1,8 @@
/** /**
* @flow * @flow
*/ */
import Firebase from './modules/core/firebase'; import firebase from './modules/core/firebase';
export const AdMob = require('./modules/admob'); export type { default as User } from './modules/auth/User';
export default Firebase; export default firebase;

View File

@ -1,6 +1,7 @@
import { NativeModules, Platform } from 'react-native'; import { NativeModules, Platform } from 'react-native';
import { statics } from './'; import { statics } from './';
import AdRequest from './AdRequest'; import AdRequest from './AdRequest';
import { SharedEventEmitter } from '../../utils/events';
import { nativeToJSError } from '../../utils'; import { nativeToJSError } from '../../utils';
const FirebaseAdMob = NativeModules.RNFirebaseAdMob; const FirebaseAdMob = NativeModules.RNFirebaseAdMob;
@ -23,8 +24,8 @@ export default class Interstitial {
this.admob = admob; this.admob = admob;
this.adUnit = adUnit; this.adUnit = adUnit;
this.loaded = false; this.loaded = false;
this.admob.removeAllListeners(`interstitial_${adUnit}`); SharedEventEmitter.removeAllListeners(`interstitial_${adUnit}`);
this.admob.on(`interstitial_${adUnit}`, this._onInterstitialEvent); SharedEventEmitter.addListener(`interstitial_${adUnit}`, this._onInterstitialEvent);
} }
/** /**
@ -48,8 +49,8 @@ export default class Interstitial {
default: default:
} }
this.admob.emit(eventType, emitData); SharedEventEmitter.emit(eventType, emitData);
this.admob.emit(`interstitial:${this.adUnit}:*`, emitData); SharedEventEmitter.emit(`interstitial:${this.adUnit}:*`, emitData);
}; };
/** /**
@ -97,7 +98,7 @@ export default class Interstitial {
return null; return null;
} }
const sub = this.admob.on(`interstitial:${this.adUnit}:${eventType}`, listenerCb); const sub = SharedEventEmitter.addListener(`interstitial:${this.adUnit}:${eventType}`, listenerCb);
subscriptions.push(sub); subscriptions.push(sub);
return sub; return sub;
} }

View File

@ -1,6 +1,7 @@
import { NativeModules } from 'react-native'; import { NativeModules } from 'react-native';
import { statics } from './'; import { statics } from './';
import AdRequest from './AdRequest'; import AdRequest from './AdRequest';
import { SharedEventEmitter } from '../../utils/events';
import { nativeToJSError } from '../../utils'; import { nativeToJSError } from '../../utils';
const FirebaseAdMob = NativeModules.RNFirebaseAdMob; const FirebaseAdMob = NativeModules.RNFirebaseAdMob;
@ -18,8 +19,8 @@ export default class RewardedVideo {
this.admob = admob; this.admob = admob;
this.adUnit = adUnit; this.adUnit = adUnit;
this.loaded = false; this.loaded = false;
this.admob.removeAllListeners(`rewarded_video_${adUnit}`); SharedEventEmitter.removeAllListeners(`rewarded_video_${adUnit}`);
this.admob.on(`rewarded_video_${adUnit}`, this._onRewardedVideoEvent); SharedEventEmitter.addListener(`rewarded_video_${adUnit}`, this._onRewardedVideoEvent);
} }
/** /**
@ -43,8 +44,8 @@ export default class RewardedVideo {
default: default:
} }
this.admob.emit(eventType, emitData); SharedEventEmitter.emit(eventType, emitData);
this.admob.emit(`rewarded_video:${this.adUnit}:*`, emitData); SharedEventEmitter.emit(`rewarded_video:${this.adUnit}:*`, emitData);
}; };
/** /**
@ -97,7 +98,7 @@ export default class RewardedVideo {
return null; return null;
} }
const sub = this.admob.on(`rewarded_video:${this.adUnit}:${eventType}`, listenerCb); const sub = SharedEventEmitter.addListener(`rewarded_video:${this.adUnit}:${eventType}`, listenerCb);
subscriptions.push(sub); subscriptions.push(sub);
return sub; return sub;
} }

View File

@ -2,7 +2,10 @@
* @flow * @flow
* AdMob representation wrapper * AdMob representation wrapper
*/ */
import ModuleBase from './../../utils/ModuleBase'; import { SharedEventEmitter } from '../../utils/events';
import { getLogger } from '../../utils/log';
import { getNativeModule } from '../../utils/native';
import ModuleBase from '../../utils/ModuleBase';
import Interstitial from './Interstitial'; import Interstitial from './Interstitial';
import RewardedVideo from './RewardedVideo'; import RewardedVideo from './RewardedVideo';
@ -16,7 +19,7 @@ import EventTypes, {
RewardedVideoEventTypes, RewardedVideoEventTypes,
} from './EventTypes'; } from './EventTypes';
import type FirebaseApp from '../core/firebase-app'; import type App from '../core/firebase-app';
type NativeEvent = { type NativeEvent = {
adUnit: string, adUnit: string,
@ -24,61 +27,70 @@ type NativeEvent = {
type: string, type: string,
} }
export default class AdMob extends ModuleBase { const NATIVE_EVENTS = [
static _NAMESPACE = 'admob'; 'interstitial_event',
static _NATIVE_MODULE = 'RNFirebaseAdMob'; 'rewarded_video_event',
];
export const MODULE_NAME = 'RNFirebaseAdmob';
export const NAMESPACE = 'admob';
export default class AdMob extends ModuleBase {
_appId: ?string; _appId: ?string;
_initialized: boolean; _initialized: boolean;
constructor(firebaseApp: FirebaseApp, options: Object = {}) { constructor(app: App) {
super(firebaseApp, options, true); super(app, {
events: NATIVE_EVENTS,
moduleName: MODULE_NAME,
namespace: NAMESPACE,
});
this._initialized = false; this._initialized = false;
this._appId = null; this._appId = null;
this._eventEmitter.addListener('interstitial_event', this._onInterstitialEvent.bind(this)); SharedEventEmitter.addListener('interstitial_event', this._onInterstitialEvent.bind(this));
this._eventEmitter.addListener('rewarded_video_event', this._onRewardedVideoEvent.bind(this)); SharedEventEmitter.addListener('rewarded_video_event', this._onRewardedVideoEvent.bind(this));
} }
_onInterstitialEvent(event: NativeEvent): void { _onInterstitialEvent(event: NativeEvent): void {
const { adUnit } = event; const { adUnit } = event;
const jsEventType = `interstitial_${adUnit}`; const jsEventType = `interstitial_${adUnit}`;
if (!this.hasListeners(jsEventType)) { if (!SharedEventEmitter.hasListeners(jsEventType)) {
// TODO // TODO
} }
this.emit(jsEventType, event); SharedEventEmitter.emit(jsEventType, event);
} }
_onRewardedVideoEvent(event: NativeEvent): void { _onRewardedVideoEvent(event: NativeEvent): void {
const { adUnit } = event; const { adUnit } = event;
const jsEventType = `rewarded_video_${adUnit}`; const jsEventType = `rewarded_video_${adUnit}`;
if (!this.hasListeners(jsEventType)) { if (!SharedEventEmitter.hasListeners(jsEventType)) {
// TODO // TODO
} }
this.emit(jsEventType, event); SharedEventEmitter.emit(jsEventType, event);
} }
initialize(appId: string): void { initialize(appId: string): void {
if (this._initialized) { if (this._initialized) {
this.log.warn('AdMob has already been initialized!'); getLogger(this).warn('AdMob has already been initialized!');
} else { } else {
this._initialized = true; this._initialized = true;
this._appId = appId; this._appId = appId;
this._native.initialize(appId); getNativeModule(this).initialize(appId);
} }
} }
openDebugMenu(): void { openDebugMenu(): void {
if (!this._initialized) { if (!this._initialized) {
this.log.warn('AdMob needs to be initialized before opening the dev menu!'); getLogger(this).warn('AdMob needs to be initialized before opening the dev menu!');
} else { } else {
this.log.info('Opening debug menu'); getLogger(this).info('Opening debug menu');
this._native.openDebugMenu(this._appId); getNativeModule(this).openDebugMenu(this._appId);
} }
} }
@ -89,10 +101,6 @@ export default class AdMob extends ModuleBase {
rewarded(adUnit: string): RewardedVideo { rewarded(adUnit: string): RewardedVideo {
return new RewardedVideo(this, adUnit); return new RewardedVideo(this, adUnit);
} }
get namespace(): string {
return 'firebase:admob';
}
} }
export const statics = { export const statics = {

View File

@ -2,9 +2,10 @@
* @flow * @flow
* Analytics representation wrapper * Analytics representation wrapper
*/ */
import ModuleBase from './../../utils/ModuleBase'; import ModuleBase from '../../utils/ModuleBase';
import { getNativeModule } from '../../utils/native';
import type FirebaseApp from '../core/firebase-app'; import type App from '../core/firebase-app';
const AlphaNumericUnderscore = /^[a-zA-Z0-9_]+$/; const AlphaNumericUnderscore = /^[a-zA-Z0-9_]+$/;
@ -24,12 +25,15 @@ const ReservedEventNames = [
'user_engagement', 'user_engagement',
]; ];
export default class Analytics extends ModuleBase { export const MODULE_NAME = 'RNFirebaseAnalytics';
static _NAMESPACE = 'analytics'; export const NAMESPACE = 'analytics';
static _NATIVE_MODULE = 'RNFirebaseAnalytics';
constructor(firebaseApp: FirebaseApp, options: Object = {}) { export default class Analytics extends ModuleBase {
super(firebaseApp, options); constructor(app: App) {
super(app, {
moduleName: MODULE_NAME,
namespace: NAMESPACE,
});
} }
/** /**
@ -57,7 +61,7 @@ export default class Analytics extends ModuleBase {
// types are supported. String parameter values can be up to 36 characters long. The "firebase_" // types are supported. String parameter values can be up to 36 characters long. The "firebase_"
// prefix is reserved and should not be used for parameter names. // prefix is reserved and should not be used for parameter names.
this._native.logEvent(name, params); getNativeModule(this).logEvent(name, params);
} }
/** /**
@ -65,7 +69,7 @@ export default class Analytics extends ModuleBase {
* @param enabled * @param enabled
*/ */
setAnalyticsCollectionEnabled(enabled: boolean): void { setAnalyticsCollectionEnabled(enabled: boolean): void {
this._native.setAnalyticsCollectionEnabled(enabled); getNativeModule(this).setAnalyticsCollectionEnabled(enabled);
} }
/** /**
@ -74,7 +78,7 @@ export default class Analytics extends ModuleBase {
* @param screenClassOverride * @param screenClassOverride
*/ */
setCurrentScreen(screenName: string, screenClassOverride: string): void { setCurrentScreen(screenName: string, screenClassOverride: string): void {
this._native.setCurrentScreen(screenName, screenClassOverride); getNativeModule(this).setCurrentScreen(screenName, screenClassOverride);
} }
/** /**
@ -82,7 +86,7 @@ export default class Analytics extends ModuleBase {
* @param milliseconds * @param milliseconds
*/ */
setMinimumSessionDuration(milliseconds: number = 10000): void { setMinimumSessionDuration(milliseconds: number = 10000): void {
this._native.setMinimumSessionDuration(milliseconds); getNativeModule(this).setMinimumSessionDuration(milliseconds);
} }
/** /**
@ -90,7 +94,7 @@ export default class Analytics extends ModuleBase {
* @param milliseconds * @param milliseconds
*/ */
setSessionTimeoutDuration(milliseconds: number = 1800000): void { setSessionTimeoutDuration(milliseconds: number = 1800000): void {
this._native.setSessionTimeoutDuration(milliseconds); getNativeModule(this).setSessionTimeoutDuration(milliseconds);
} }
/** /**
@ -98,7 +102,7 @@ export default class Analytics extends ModuleBase {
* @param id * @param id
*/ */
setUserId(id: string): void { setUserId(id: string): void {
this._native.setUserId(id); getNativeModule(this).setUserId(id);
} }
/** /**
@ -107,7 +111,7 @@ export default class Analytics extends ModuleBase {
* @param value * @param value
*/ */
setUserProperty(name: string, value: string): void { setUserProperty(name: string, value: string): void {
this._native.setUserProperty(name, value); getNativeModule(this).setUserProperty(name, value);
} }
/** /**
@ -117,7 +121,7 @@ export default class Analytics extends ModuleBase {
*/ */
setUserProperties(object: Object): void { setUserProperties(object: Object): void {
for (const property of Object.keys(object)) { for (const property of Object.keys(object)) {
this._native.setUserProperty(property, object[property]); getNativeModule(this).setUserProperty(property, object[property]);
} }
} }
} }

View File

@ -2,6 +2,7 @@
* @flow * @flow
* ConfirmationResult representation wrapper * ConfirmationResult representation wrapper
*/ */
import { getNativeModule } from '../../utils/native';
import type Auth from './'; import type Auth from './';
import type User from './User'; import type User from './User';
@ -25,7 +26,7 @@ export default class ConfirmationResult {
* @return {*} * @return {*}
*/ */
confirm(verificationCode: string): Promise<?User> { confirm(verificationCode: string): Promise<?User> {
return this._auth._interceptUserValue(this._auth._native._confirmVerificationCode(verificationCode)); return this._auth._interceptUserValue(getNativeModule(this._auth)._confirmVerificationCode(verificationCode));
} }
get verificationId(): string | null { get verificationId(): string | null {

View File

@ -1,6 +1,8 @@
// @flow // @flow
import INTERNALS from '../../utils/internals'; import INTERNALS from '../../utils/internals';
import { generatePushID, isFunction, isAndroid, isIOS, isString, nativeToJSError } from './../../utils'; import { SharedEventEmitter } from '../../utils/events';
import { generatePushID, isFunction, isAndroid, isIOS, isString, nativeToJSError } from '../../utils';
import { getNativeModule } from '../../utils/native';
import type Auth from './'; import type Auth from './';
@ -19,7 +21,7 @@ type PhoneAuthError = {
}; };
export default class PhoneAuthListener { export default class PhoneAuthListener {
_auth: Object; _auth: Auth;
_timeout: number; _timeout: number;
_publicEvents: Object; _publicEvents: Object;
_internalEvents: Object; _internalEvents: Object;
@ -68,7 +70,7 @@ export default class PhoneAuthListener {
// start verification flow natively // start verification flow natively
if (isAndroid) { if (isAndroid) {
this._auth._native.verifyPhoneNumber( getNativeModule(this._auth).verifyPhoneNumber(
phoneNumber, phoneNumber,
this._phoneAuthRequestKey, this._phoneAuthRequestKey,
this._timeout, this._timeout,
@ -76,7 +78,7 @@ export default class PhoneAuthListener {
} }
if (isIOS) { if (isIOS) {
this._auth._native.verifyPhoneNumber( getNativeModule(this._auth).verifyPhoneNumber(
phoneNumber, phoneNumber,
this._phoneAuthRequestKey, this._phoneAuthRequestKey,
); );
@ -92,7 +94,8 @@ export default class PhoneAuthListener {
for (let i = 0, len = events.length; i < len; i++) { for (let i = 0, len = events.length; i < len; i++) {
const type = events[i]; const type = events[i];
this._auth.once(this._internalEvents[type], this[`_${type}Handler`].bind(this)); // $FlowBug: Flow doesn't support indexable signatures on classes: https://github.com/facebook/flow/issues/1323
SharedEventEmitter.once(this._internalEvents[type], this[`_${type}Handler`].bind(this));
} }
} }
@ -102,7 +105,7 @@ export default class PhoneAuthListener {
* @private * @private
*/ */
_addUserObserver(observer) { _addUserObserver(observer) {
this._auth.on(this._publicEvents.event, observer); SharedEventEmitter.addListener(this._publicEvents.event, observer);
} }
/** /**
@ -111,7 +114,7 @@ export default class PhoneAuthListener {
* @private * @private
*/ */
_emitToObservers(snapshot: PhoneAuthSnapshot) { _emitToObservers(snapshot: PhoneAuthSnapshot) {
this._auth.emit(this._publicEvents.event, snapshot); SharedEventEmitter.emit(this._publicEvents.event, snapshot);
} }
/** /**
@ -120,9 +123,9 @@ export default class PhoneAuthListener {
* @private * @private
*/ */
_emitToErrorCb(snapshot) { _emitToErrorCb(snapshot) {
const error = snapshot.error; const { error } = snapshot;
if (this._reject) this._reject(error); if (this._reject) this._reject(error);
this._auth.emit(this._publicEvents.error, error); SharedEventEmitter.emit(this._publicEvents.error, error);
} }
/** /**
@ -132,7 +135,7 @@ export default class PhoneAuthListener {
*/ */
_emitToSuccessCb(snapshot) { _emitToSuccessCb(snapshot) {
if (this._resolve) this._resolve(snapshot); if (this._resolve) this._resolve(snapshot);
this._auth.emit(this._publicEvents.success, snapshot); SharedEventEmitter.emit(this._publicEvents.success, snapshot);
} }
/** /**
@ -143,12 +146,12 @@ export default class PhoneAuthListener {
setTimeout(() => { // move to next event loop - not sure if needed setTimeout(() => { // move to next event loop - not sure if needed
// internal listeners // internal listeners
Object.values(this._internalEvents).forEach((event) => { Object.values(this._internalEvents).forEach((event) => {
this._auth.removeAllListeners(event); SharedEventEmitter.removeAllListeners(event);
}); });
// user observer listeners // user observer listeners
Object.values(this._publicEvents).forEach((publicEvent) => { Object.values(this._publicEvents).forEach((publicEvent) => {
this._auth.removeAllListeners(publicEvent); SharedEventEmitter.removeAllListeners(publicEvent);
}); });
}, 0); }, 0);
} }
@ -279,11 +282,11 @@ export default class PhoneAuthListener {
this._addUserObserver(observer); this._addUserObserver(observer);
if (isFunction(errorCb)) { if (isFunction(errorCb)) {
this._auth.once(this._publicEvents.error, errorCb); SharedEventEmitter.once(this._publicEvents.error, errorCb);
} }
if (isFunction(successCb)) { if (isFunction(successCb)) {
this._auth.once(this._publicEvents.success, successCb); SharedEventEmitter.once(this._publicEvents.success, successCb);
} }
return this; return this;
@ -295,6 +298,7 @@ export default class PhoneAuthListener {
*/ */
then(fn: () => PhoneAuthSnapshot) { then(fn: () => PhoneAuthSnapshot) {
this._promiseDeferred(); this._promiseDeferred();
// $FlowFixMe: Unsure how to annotate `bind` here
if (this._promise) return this._promise.then.bind(this._promise)(fn); if (this._promise) return this._promise.then.bind(this._promise)(fn);
return undefined; // will never get here - just to keep flow happy return undefined; // will never get here - just to keep flow happy
} }
@ -305,6 +309,7 @@ export default class PhoneAuthListener {
*/ */
catch(fn: () => Error) { catch(fn: () => Error) {
this._promiseDeferred(); this._promiseDeferred();
// $FlowFixMe: Unsure how to annotate `bind` here
if (this._promise) return this._promise.catch.bind(this._promise)(fn); if (this._promise) return this._promise.catch.bind(this._promise)(fn);
return undefined; // will never get here - just to keep flow happy return undefined; // will never get here - just to keep flow happy
} }

View File

@ -3,6 +3,7 @@
* User representation wrapper * User representation wrapper
*/ */
import INTERNALS from '../../utils/internals'; import INTERNALS from '../../utils/internals';
import { getNativeModule } from '../../utils/native';
import type Auth from './'; import type Auth from './';
import type { ActionCodeSettings, AuthCredential } from '../../types'; import type { ActionCodeSettings, AuthCredential } from '../../types';
@ -92,7 +93,7 @@ export default class User {
*/ */
delete(): Promise<void> { delete(): Promise<void> {
return this._auth return this._auth
._interceptUndefinedUserValue(this._auth._native.delete()); ._interceptUndefinedUserValue(getNativeModule(this._auth).delete());
} }
/** /**
@ -100,7 +101,7 @@ export default class User {
* @return {Promise} * @return {Promise}
*/ */
getIdToken(forceRefresh: boolean = false): Promise<string> { getIdToken(forceRefresh: boolean = false): Promise<string> {
return this._auth._native.getToken(forceRefresh); return getNativeModule(this._auth).getToken(forceRefresh);
} }
/** /**
@ -109,7 +110,7 @@ export default class User {
*/ */
linkWithCredential(credential: AuthCredential): Promise<User> { linkWithCredential(credential: AuthCredential): Promise<User> {
return this._auth return this._auth
._interceptUserValue(this._auth._native.link(credential.providerId, credential.token, credential.secret)); ._interceptUserValue(getNativeModule(this._auth).link(credential.providerId, credential.token, credential.secret));
} }
/** /**
@ -118,7 +119,7 @@ export default class User {
*/ */
reauthenticateWithCredential(credential: AuthCredential): Promise<void> { reauthenticateWithCredential(credential: AuthCredential): Promise<void> {
return this._auth return this._auth
._interceptUndefinedUserValue(this._auth._native.reauthenticate(credential.providerId, credential.token, credential.secret)); ._interceptUndefinedUserValue(getNativeModule(this._auth).reauthenticate(credential.providerId, credential.token, credential.secret));
} }
/** /**
@ -127,7 +128,7 @@ export default class User {
*/ */
reload(): Promise<void> { reload(): Promise<void> {
return this._auth return this._auth
._interceptUndefinedUserValue(this._auth._native.reload()); ._interceptUndefinedUserValue(getNativeModule(this._auth).reload());
} }
/** /**
@ -135,7 +136,7 @@ export default class User {
*/ */
sendEmailVerification(actionCodeSettings?: ActionCodeSettings): Promise<void> { sendEmailVerification(actionCodeSettings?: ActionCodeSettings): Promise<void> {
return this._auth return this._auth
._interceptUndefinedUserValue(this._auth._native.sendEmailVerification(actionCodeSettings)); ._interceptUndefinedUserValue(getNativeModule(this._auth).sendEmailVerification(actionCodeSettings));
} }
toJSON(): Object { toJSON(): Object {
@ -148,7 +149,7 @@ export default class User {
* @return {Promise.<TResult>|*} * @return {Promise.<TResult>|*}
*/ */
unlink(providerId: string): Promise<User> { unlink(providerId: string): Promise<User> {
return this._auth._interceptUserValue(this._auth._native.unlink(providerId)); return this._auth._interceptUserValue(getNativeModule(this._auth).unlink(providerId));
} }
/** /**
@ -159,7 +160,7 @@ export default class User {
*/ */
updateEmail(email: string): Promise<void> { updateEmail(email: string): Promise<void> {
return this._auth return this._auth
._interceptUndefinedUserValue(this._auth._native.updateEmail(email)); ._interceptUndefinedUserValue(getNativeModule(this._auth).updateEmail(email));
} }
/** /**
@ -169,7 +170,7 @@ export default class User {
*/ */
updatePassword(password: string): Promise<void> { updatePassword(password: string): Promise<void> {
return this._auth return this._auth
._interceptUndefinedUserValue(this._auth._native.updatePassword(password)); ._interceptUndefinedUserValue(getNativeModule(this._auth).updatePassword(password));
} }
/** /**
@ -179,7 +180,7 @@ export default class User {
*/ */
updateProfile(updates: Object = {}): Promise<void> { updateProfile(updates: Object = {}): Promise<void> {
return this._auth return this._auth
._interceptUndefinedUserValue(this._auth._native.updateProfile(updates)); ._interceptUndefinedUserValue(getNativeModule(this._auth).updateProfile(updates));
} }
/** /**
@ -189,7 +190,7 @@ export default class User {
*/ */
getToken(forceRefresh: boolean = false): Promise<Object> { getToken(forceRefresh: boolean = false): Promise<Object> {
console.warn('Deprecated firebase.User.prototype.getToken in favor of firebase.User.prototype.getIdToken.'); console.warn('Deprecated firebase.User.prototype.getToken in favor of firebase.User.prototype.getIdToken.');
return this._auth._native.getToken(forceRefresh); return getNativeModule(this._auth).getToken(forceRefresh);
} }
/** /**

View File

@ -4,6 +4,9 @@
*/ */
import User from './User'; import User from './User';
import ModuleBase from '../../utils/ModuleBase'; import ModuleBase from '../../utils/ModuleBase';
import { getAppEventName, SharedEventEmitter } from '../../utils/events';
import { getLogger } from '../../utils/log';
import { getNativeModule } from '../../utils/native';
import INTERNALS from '../../utils/internals'; import INTERNALS from '../../utils/internals';
import ConfirmationResult from './ConfirmationResult'; import ConfirmationResult from './ConfirmationResult';
@ -18,48 +21,57 @@ import FacebookAuthProvider from './providers/FacebookAuthProvider';
import PhoneAuthListener from './PhoneAuthListener'; import PhoneAuthListener from './PhoneAuthListener';
import type { ActionCodeSettings, AuthCredential } from '../../types'; import type { ActionCodeSettings, AuthCredential } from '../../types';
import type FirebaseApp from '../core/firebase-app'; import type App from '../core/firebase-app';
type AuthResult = { type AuthResult = {
authenticated: boolean, authenticated: boolean,
user: Object|null user: Object|null
} | null; } | null;
export default class Auth extends ModuleBase { const NATIVE_EVENTS = [
static _NAMESPACE = 'auth'; 'auth_state_changed',
static _NATIVE_MODULE = 'RNFirebaseAuth'; 'phone_auth_state_changed',
];
export const MODULE_NAME = 'RNFirebaseAuth';
export const NAMESPACE = 'auth';
export default class Auth extends ModuleBase {
_authResult: AuthResult | null; _authResult: AuthResult | null;
_user: User | null; _user: User | null;
constructor(firebaseApp: FirebaseApp, options: Object = {}) { constructor(app: App) {
super(firebaseApp, options, true); super(app, {
events: NATIVE_EVENTS,
moduleName: MODULE_NAME,
namespace: NAMESPACE,
});
this._user = null; this._user = null;
this._authResult = null; this._authResult = null;
this.addListener( SharedEventEmitter.addListener(
// sub to internal native event - this fans out to // sub to internal native event - this fans out to
// public event name: onAuthStateChanged // public event name: onAuthStateChanged
super._getAppEventName('auth_state_changed'), getAppEventName(this, 'auth_state_changed'),
this._onInternalAuthStateChanged.bind(this), this._onInternalAuthStateChanged.bind(this),
); );
this.addListener( SharedEventEmitter.addListener(
// sub to internal native event - this fans out to // sub to internal native event - this fans out to
// public events based on event.type // public events based on event.type
super._getAppEventName('phone_auth_state_changed'), getAppEventName(this, 'phone_auth_state_changed'),
this._onInternalPhoneAuthStateChanged.bind(this), this._onInternalPhoneAuthStateChanged.bind(this),
); );
this.addListener( SharedEventEmitter.addListener(
// sub to internal native event - this fans out to // sub to internal native event - this fans out to
// public event name: onIdTokenChanged // public event name: onIdTokenChanged
super._getAppEventName('auth_id_token_changed'), getAppEventName(this, 'auth_id_token_changed'),
this._onInternalIdTokenChanged.bind(this), this._onInternalIdTokenChanged.bind(this),
); );
this._native.addAuthStateListener(); getNativeModule(this).addAuthStateListener();
this._native.addIdTokenListener(); getNativeModule(this).addIdTokenListener();
} }
/** /**
@ -69,13 +81,13 @@ export default class Auth extends ModuleBase {
*/ */
_onInternalPhoneAuthStateChanged(event: Object) { _onInternalPhoneAuthStateChanged(event: Object) {
const eventKey = `phone:auth:${event.requestKey}:${event.type}`; const eventKey = `phone:auth:${event.requestKey}:${event.type}`;
this.emit(eventKey, event.state); SharedEventEmitter.emit(eventKey, event.state);
} }
_setAuthState(auth: AuthResult) { _setAuthState(auth: AuthResult) {
this._authResult = auth; this._authResult = auth;
this._user = auth && auth.user ? new User(this, auth.user) : null; this._user = auth && auth.user ? new User(this, auth.user) : null;
this.emit(this._getAppEventName('onUserChanged'), this._user); SharedEventEmitter.emit(getAppEventName(this, 'onUserChanged'), this._user);
} }
/** /**
@ -85,7 +97,7 @@ export default class Auth extends ModuleBase {
*/ */
_onInternalAuthStateChanged(auth: AuthResult) { _onInternalAuthStateChanged(auth: AuthResult) {
this._setAuthState(auth); this._setAuthState(auth);
this.emit(this._getAppEventName('onAuthStateChanged'), this._user); SharedEventEmitter.emit(getAppEventName(this, 'onAuthStateChanged'), this._user);
} }
/** /**
@ -96,7 +108,7 @@ export default class Auth extends ModuleBase {
*/ */
_onInternalIdTokenChanged(auth: AuthResult) { _onInternalIdTokenChanged(auth: AuthResult) {
this._setAuthState(auth); this._setAuthState(auth);
this.emit(this._getAppEventName('onIdTokenChanged'), this._user); SharedEventEmitter.emit(getAppEventName(this, 'onIdTokenChanged'), this._user);
} }
/** /**
@ -129,8 +141,8 @@ export default class Auth extends ModuleBase {
* @param listener * @param listener
*/ */
onAuthStateChanged(listener: Function) { onAuthStateChanged(listener: Function) {
this.log.info('Creating onAuthStateChanged listener'); getLogger(this).info('Creating onAuthStateChanged listener');
this.on(this._getAppEventName('onAuthStateChanged'), listener); SharedEventEmitter.addListener(getAppEventName(this, 'onAuthStateChanged'), listener);
if (this._authResult) listener(this._user || null); if (this._authResult) listener(this._user || null);
return this._offAuthStateChanged.bind(this, listener); return this._offAuthStateChanged.bind(this, listener);
} }
@ -140,8 +152,8 @@ export default class Auth extends ModuleBase {
* @param listener * @param listener
*/ */
_offAuthStateChanged(listener: Function) { _offAuthStateChanged(listener: Function) {
this.log.info('Removing onAuthStateChanged listener'); getLogger(this).info('Removing onAuthStateChanged listener');
this.removeListener(this._getAppEventName('onAuthStateChanged'), listener); SharedEventEmitter.removeListener(getAppEventName(this, 'onAuthStateChanged'), listener);
} }
/** /**
@ -149,8 +161,8 @@ export default class Auth extends ModuleBase {
* @param listener * @param listener
*/ */
onIdTokenChanged(listener: Function) { onIdTokenChanged(listener: Function) {
this.log.info('Creating onIdTokenChanged listener'); getLogger(this).info('Creating onIdTokenChanged listener');
this.on(this._getAppEventName('onIdTokenChanged'), listener); SharedEventEmitter.addListener(getAppEventName(this, 'onIdTokenChanged'), listener);
if (this._authResult) listener(this._user || null); if (this._authResult) listener(this._user || null);
return this._offIdTokenChanged.bind(this, listener); return this._offIdTokenChanged.bind(this, listener);
} }
@ -160,8 +172,8 @@ export default class Auth extends ModuleBase {
* @param listener * @param listener
*/ */
_offIdTokenChanged(listener: Function) { _offIdTokenChanged(listener: Function) {
this.log.info('Removing onIdTokenChanged listener'); getLogger(this).info('Removing onIdTokenChanged listener');
this.removeListener(this._getAppEventName('onIdTokenChanged'), listener); SharedEventEmitter.removeListener(getAppEventName(this, 'onIdTokenChanged'), listener);
} }
/** /**
@ -169,8 +181,8 @@ export default class Auth extends ModuleBase {
* @param listener * @param listener
*/ */
onUserChanged(listener: Function) { onUserChanged(listener: Function) {
this.log.info('Creating onUserChanged listener'); getLogger(this).info('Creating onUserChanged listener');
this.on(this._getAppEventName('onUserChanged'), listener); SharedEventEmitter.addListener(getAppEventName(this, 'onUserChanged'), listener);
if (this._authResult) listener(this._user || null); if (this._authResult) listener(this._user || null);
return this._offUserChanged.bind(this, listener); return this._offUserChanged.bind(this, listener);
} }
@ -180,8 +192,8 @@ export default class Auth extends ModuleBase {
* @param listener * @param listener
*/ */
_offUserChanged(listener: Function) { _offUserChanged(listener: Function) {
this.log.info('Removing onUserChanged listener'); getLogger(this).info('Removing onUserChanged listener');
this.removeListener(this._getAppEventName('onUserChanged'), listener); SharedEventEmitter.removeListener(getAppEventName(this, 'onUserChanged'), listener);
} }
/** /**
@ -189,7 +201,7 @@ export default class Auth extends ModuleBase {
* @return {Promise} * @return {Promise}
*/ */
signOut(): Promise<void> { signOut(): Promise<void> {
return this._interceptUndefinedUserValue(this._native.signOut()); return this._interceptUndefinedUserValue(getNativeModule(this).signOut());
} }
/** /**
@ -197,7 +209,7 @@ export default class Auth extends ModuleBase {
* @return {Promise} A promise resolved upon completion * @return {Promise} A promise resolved upon completion
*/ */
signInAnonymously(): Promise<User> { signInAnonymously(): Promise<User> {
return this._interceptUserValue(this._native.signInAnonymously()); return this._interceptUserValue(getNativeModule(this).signInAnonymously());
} }
/** /**
@ -207,7 +219,7 @@ export default class Auth extends ModuleBase {
* @return {Promise} A promise indicating the completion * @return {Promise} A promise indicating the completion
*/ */
createUserWithEmailAndPassword(email: string, password: string): Promise<User> { createUserWithEmailAndPassword(email: string, password: string): Promise<User> {
return this._interceptUserValue(this._native.createUserWithEmailAndPassword(email, password)); return this._interceptUserValue(getNativeModule(this).createUserWithEmailAndPassword(email, password));
} }
/** /**
@ -217,7 +229,7 @@ export default class Auth extends ModuleBase {
* @return {Promise} A promise that is resolved upon completion * @return {Promise} A promise that is resolved upon completion
*/ */
signInWithEmailAndPassword(email: string, password: string): Promise<User> { signInWithEmailAndPassword(email: string, password: string): Promise<User> {
return this._interceptUserValue(this._native.signInWithEmailAndPassword(email, password)); return this._interceptUserValue(getNativeModule(this).signInWithEmailAndPassword(email, password));
} }
/** /**
@ -226,7 +238,7 @@ export default class Auth extends ModuleBase {
* @return {Promise} A promise resolved upon completion * @return {Promise} A promise resolved upon completion
*/ */
signInWithCustomToken(customToken: string): Promise<User> { signInWithCustomToken(customToken: string): Promise<User> {
return this._interceptUserValue(this._native.signInWithCustomToken(customToken)); return this._interceptUserValue(getNativeModule(this).signInWithCustomToken(customToken));
} }
/** /**
@ -235,7 +247,7 @@ export default class Auth extends ModuleBase {
*/ */
signInWithCredential(credential: AuthCredential): Promise<User> { signInWithCredential(credential: AuthCredential): Promise<User> {
return this._interceptUserValue( return this._interceptUserValue(
this._native.signInWithCredential( getNativeModule(this).signInWithCredential(
credential.providerId, credential.token, credential.secret, credential.providerId, credential.token, credential.secret,
), ),
); );
@ -246,7 +258,7 @@ export default class Auth extends ModuleBase {
* *
*/ */
signInWithPhoneNumber(phoneNumber: string): Promise<ConfirmationResult> { signInWithPhoneNumber(phoneNumber: string): Promise<ConfirmationResult> {
return this._native.signInWithPhoneNumber(phoneNumber).then((result) => { return getNativeModule(this).signInWithPhoneNumber(phoneNumber).then((result) => {
return new ConfirmationResult(this, result.verificationId); return new ConfirmationResult(this, result.verificationId);
}); });
} }
@ -269,7 +281,7 @@ export default class Auth extends ModuleBase {
* @param {string} email The email to send password reset instructions * @param {string} email The email to send password reset instructions
*/ */
sendPasswordResetEmail(email: string, actionCodeSettings?: ActionCodeSettings): Promise<void> { sendPasswordResetEmail(email: string, actionCodeSettings?: ActionCodeSettings): Promise<void> {
return this._native.sendPasswordResetEmail(email, actionCodeSettings); return getNativeModule(this).sendPasswordResetEmail(email, actionCodeSettings);
} }
/** /**
@ -281,7 +293,7 @@ export default class Auth extends ModuleBase {
* @return {Promise.<Null>} * @return {Promise.<Null>}
*/ */
confirmPasswordReset(code: string, newPassword: string): Promise<void> { confirmPasswordReset(code: string, newPassword: string): Promise<void> {
return this._native.confirmPasswordReset(code, newPassword); return getNativeModule(this).confirmPasswordReset(code, newPassword);
} }
/** /**
@ -292,7 +304,7 @@ export default class Auth extends ModuleBase {
* @return {Promise.<Null>} * @return {Promise.<Null>}
*/ */
applyActionCode(code: string): Promise<void> { applyActionCode(code: string): Promise<void> {
return this._native.applyActionCode(code); return getNativeModule(this).applyActionCode(code);
} }
/** /**
@ -303,7 +315,7 @@ export default class Auth extends ModuleBase {
* @return {Promise.<any>|Promise<ActionCodeInfo>} * @return {Promise.<any>|Promise<ActionCodeInfo>}
*/ */
checkActionCode(code: string): Promise<void> { checkActionCode(code: string): Promise<void> {
return this._native.checkActionCode(code); return getNativeModule(this).checkActionCode(code);
} }
/** /**
@ -311,7 +323,7 @@ export default class Auth extends ModuleBase {
* @return {Promise} * @return {Promise}
*/ */
getCurrentUser(): Promise<User | null> { getCurrentUser(): Promise<User | null> {
return this._interceptUserValue(this._native.getCurrentUser()); return this._interceptUserValue(getNativeModule(this).getCurrentUser());
} }
/** /**
@ -319,7 +331,7 @@ export default class Auth extends ModuleBase {
* @return {Promise} * @return {Promise}
*/ */
fetchProvidersForEmail(email: string): Promise<Array<String>> { fetchProvidersForEmail(email: string): Promise<Array<String>> {
return this._native.fetchProvidersForEmail(email); return getNativeModule(this).fetchProvidersForEmail(email);
} }
/** /**
@ -330,32 +342,28 @@ export default class Auth extends ModuleBase {
return this._user; return this._user;
} }
get namespace(): string {
return 'firebase:auth';
}
/** /**
* KNOWN UNSUPPORTED METHODS * KNOWN UNSUPPORTED METHODS
*/ */
getRedirectResult() { getRedirectResult() {
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD(Auth, 'getRedirectResult')); throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD('auth', 'getRedirectResult'));
} }
setPersistence() { setPersistence() {
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD(Auth, 'setPersistence')); throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD('auth', 'setPersistence'));
} }
signInAndRetrieveDataWithCredential() { signInAndRetrieveDataWithCredential() {
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD(Auth, 'signInAndRetrieveDataWithCredential')); throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD('auth', 'signInAndRetrieveDataWithCredential'));
} }
signInWithPopup() { signInWithPopup() {
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD(Auth, 'signInWithPopup')); throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD('auth', 'signInWithPopup'));
} }
signInWithRedirect() { signInWithRedirect() {
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD(Auth, 'signInWithRedirect')); throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD('auth', 'signInWithRedirect'));
} }
} }

View File

@ -2,9 +2,11 @@
* @flow * @flow
* Remote Config representation wrapper * Remote Config representation wrapper
*/ */
import ModuleBase from './../../utils/ModuleBase'; import { getLogger } from '../../utils/log';
import ModuleBase from '../../utils/ModuleBase';
import { getNativeModule } from '../../utils/native';
import type FirebaseApp from '../core/firebase-app'; import type App from '../core/firebase-app';
type NativeValue = { type NativeValue = {
stringValue?: string, stringValue?: string,
@ -14,17 +16,20 @@ type NativeValue = {
source: 'remoteConfigSourceRemote' | 'remoteConfigSourceDefault' | ' remoteConfigSourceStatic', source: 'remoteConfigSourceRemote' | 'remoteConfigSourceDefault' | ' remoteConfigSourceStatic',
} }
export const MODULE_NAME = 'RNFirebaseRemoteConfig';
export const NAMESPACE = 'config';
/** /**
* @class Config * @class Config
*/ */
export default class RemoteConfig extends ModuleBase { export default class RemoteConfig extends ModuleBase {
static _NAMESPACE = 'config';
static _NATIVE_MODULE = 'RNFirebaseRemoteConfig';
_developerModeEnabled: boolean; _developerModeEnabled: boolean;
constructor(firebaseApp: FirebaseApp, options: Object = {}) { constructor(app: App) {
super(firebaseApp, options); super(app, {
moduleName: MODULE_NAME,
namespace: NAMESPACE,
});
this._developerModeEnabled = false; this._developerModeEnabled = false;
} }
@ -39,7 +44,7 @@ export default class RemoteConfig extends ModuleBase {
source: nativeValue.source, source: nativeValue.source,
val() { val() {
if (nativeValue.boolValue !== null && (nativeValue.stringValue === 'true' || nativeValue.stringValue === 'false' || nativeValue.stringValue === null)) return nativeValue.boolValue; if (nativeValue.boolValue !== null && (nativeValue.stringValue === 'true' || nativeValue.stringValue === 'false' || nativeValue.stringValue === null)) return nativeValue.boolValue;
if (nativeValue.numberValue !== null && (nativeValue.stringValue == null || nativeValue.stringValue === '' || `${nativeValue.numberValue}` === nativeValue.stringValue)) return nativeValue.numberValue; if (nativeValue.numberValue !== null && nativeValue.numberValue !== undefined && (nativeValue.stringValue == null || nativeValue.stringValue === '' || nativeValue.numberValue.toString() === nativeValue.stringValue)) return nativeValue.numberValue;
if (nativeValue.dataValue !== nativeValue.stringValue && (nativeValue.stringValue == null || nativeValue.stringValue === '')) return nativeValue.dataValue; if (nativeValue.dataValue !== nativeValue.stringValue && (nativeValue.stringValue == null || nativeValue.stringValue === '')) return nativeValue.dataValue;
return nativeValue.stringValue; return nativeValue.stringValue;
}, },
@ -51,8 +56,8 @@ export default class RemoteConfig extends ModuleBase {
*/ */
enableDeveloperMode() { enableDeveloperMode() {
if (!this._developerModeEnabled) { if (!this._developerModeEnabled) {
this.log.debug('Enabled developer mode'); getLogger(this).debug('Enabled developer mode');
this._native.enableDeveloperMode(); getNativeModule(this).enableDeveloperMode();
this._developerModeEnabled = true; this._developerModeEnabled = true;
} }
} }
@ -64,11 +69,11 @@ export default class RemoteConfig extends ModuleBase {
*/ */
fetch(expiration?: number) { fetch(expiration?: number) {
if (expiration !== undefined) { if (expiration !== undefined) {
this.log.debug(`Fetching remote config data with expiration ${expiration.toString()}`); getLogger(this).debug(`Fetching remote config data with expiration ${expiration.toString()}`);
return this._native.fetchWithExpirationDuration(expiration); return getNativeModule(this).fetchWithExpirationDuration(expiration);
} }
this.log.debug('Fetching remote config data'); getLogger(this).debug('Fetching remote config data');
return this._native.fetch(); return getNativeModule(this).fetch();
} }
/** /**
@ -78,8 +83,8 @@ export default class RemoteConfig extends ModuleBase {
* rejects if no Fetched Config was found, or the Fetched Config was already activated. * rejects if no Fetched Config was found, or the Fetched Config was already activated.
*/ */
activateFetched() { activateFetched() {
this.log.debug('Activating remote config'); getLogger(this).debug('Activating remote config');
return this._native.activateFetched(); return getNativeModule(this).activateFetched();
} }
/** /**
@ -96,7 +101,7 @@ export default class RemoteConfig extends ModuleBase {
* } * }
*/ */
getValue(key: String) { getValue(key: String) {
return this._native return getNativeModule(this)
.getValue(key || '') .getValue(key || '')
.then(this._nativeValueToJS); .then(this._nativeValueToJS);
} }
@ -116,7 +121,7 @@ export default class RemoteConfig extends ModuleBase {
* } * }
*/ */
getValues(keys: Array<String>) { getValues(keys: Array<String>) {
return this._native return getNativeModule(this)
.getValues(keys || []) .getValues(keys || [])
.then((nativeValues) => { .then((nativeValues) => {
const values: { [String]: Object } = {}; const values: { [String]: Object } = {};
@ -133,7 +138,7 @@ export default class RemoteConfig extends ModuleBase {
* @returns {*|Promise.<Array<String>>} * @returns {*|Promise.<Array<String>>}
*/ */
getKeysByPrefix(prefix?: String) { getKeysByPrefix(prefix?: String) {
return this._native.getKeysByPrefix(prefix); return getNativeModule(this).getKeysByPrefix(prefix);
} }
/** /**
@ -141,7 +146,7 @@ export default class RemoteConfig extends ModuleBase {
* @param defaults: A dictionary mapping a String key to a Object values. * @param defaults: A dictionary mapping a String key to a Object values.
*/ */
setDefaults(defaults: Object) { setDefaults(defaults: Object) {
this._native.setDefaults(defaults); getNativeModule(this).setDefaults(defaults);
} }
/** /**
@ -149,7 +154,7 @@ export default class RemoteConfig extends ModuleBase {
* @param resource: The plist file name or resource ID * @param resource: The plist file name or resource ID
*/ */
setDefaultsFromResource(resource: String | number) { setDefaultsFromResource(resource: String | number) {
this._native.setDefaultsFromResource(resource); getNativeModule(this).setDefaultsFromResource(resource);
} }
} }

View File

@ -3,112 +3,85 @@
*/ */
import { NativeModules } from 'react-native'; import { NativeModules } from 'react-native';
import APPS from '../../utils/apps';
import { SharedEventEmitter } from '../../utils/events';
import INTERNALS from '../../utils/internals'; import INTERNALS from '../../utils/internals';
import { isObject, isAndroid } from '../../utils'; import { isObject } from '../../utils';
import AdMob, { statics as AdMobStatics } from '../admob'; import AdMob, { NAMESPACE as AdmobNamespace } from '../admob';
import Auth, { statics as AuthStatics } from '../auth'; import Auth, { NAMESPACE as AuthNamespace } from '../auth';
import Analytics, { statics as AnalyticsStatics } from '../analytics'; import Analytics, { NAMESPACE as AnalyticsNamespace } from '../analytics';
import Config, { statics as ConfigStatics } from '../config'; import Config, { NAMESPACE as ConfigNamespace } from '../config';
import Crash, { statics as CrashStatics } from '../crash'; import Crash, { NAMESPACE as CrashNamespace } from '../crash';
import Crashlytics, { statics as CrashlyticsStatics } from '../fabric/crashlytics'; import Crashlytics, { NAMESPACE as CrashlyticsNamespace } from '../fabric/crashlytics';
import Database, { statics as DatabaseStatics } from '../database'; import Database, { NAMESPACE as DatabaseNamespace } from '../database';
import Firestore, { statics as FirestoreStatics } from '../firestore'; import Firestore, { NAMESPACE as FirestoreNamespace } from '../firestore';
import Links, { statics as LinksStatics } from '../links'; import Links, { NAMESPACE as LinksNamespace } from '../links';
import Messaging, { statics as MessagingStatics } from '../messaging'; import Messaging, { NAMESPACE as MessagingNamespace } from '../messaging';
import Performance, { statics as PerformanceStatics } from '../perf'; import Performance, { NAMESPACE as PerfNamespace } from '../perf';
import Storage, { statics as StorageStatics } from '../storage'; import Storage, { NAMESPACE as StorageNamespace } from '../storage';
import Utils, { statics as UtilsStatics } from '../utils'; import Utils, { NAMESPACE as UtilsNamespace } from '../utils';
import type { import type {
AdMobModule,
AnalyticsModule,
AuthModule,
ConfigModule,
CrashModule,
DatabaseModule,
FabricModule,
FirebaseModule,
FirebaseModuleAndStatics,
FirebaseOptions, FirebaseOptions,
FirebaseStatics,
FirestoreModule,
LinksModule,
MessagingModule,
PerformanceModule,
StorageModule,
UtilsModule,
} from '../../types'; } from '../../types';
const FirebaseCoreModule = NativeModules.RNFirebase; const FirebaseCoreModule = NativeModules.RNFirebase;
export default class FirebaseApp { export default class App {
_extendedProps: { [string] : boolean }; _extendedProps: { [string] : boolean };
_initialized: boolean; _initialized: boolean = false;
_name: string; _name: string;
_namespaces: { [string]: FirebaseModule }; _nativeInitialized: boolean = false;
_nativeInitialized: boolean;
_options: FirebaseOptions; _options: FirebaseOptions;
admob: AdMobModule; admob: () => AdMob;
analytics: AnalyticsModule; analytics: () => Analytics;
auth: AuthModule; auth: () => Auth;
config: ConfigModule; config: () => Config;
crash: CrashModule; crash: () => Crash;
database: DatabaseModule; database: () => Database;
fabric: FabricModule; fabric: {
firestore: FirestoreModule; crashlytics: () => Crashlytics,
links: LinksModule; };
messaging: MessagingModule; firestore: () => Firestore;
perf: PerformanceModule; links: () => Links;
storage: StorageModule; messaging: () => Messaging;
utils: UtilsModule; perf: () => Performance;
storage: () => Storage;
utils: () => Utils;
constructor(name: string, options: FirebaseOptions) { constructor(name: string, options: FirebaseOptions, fromNative: boolean = false) {
this._name = name; this._name = name;
this._namespaces = {};
this._options = Object.assign({}, options); this._options = Object.assign({}, options);
// native ios/android to confirm initialized if (fromNative) {
this._initialized = false;
this._nativeInitialized = false;
// modules
this.admob = this._staticsOrModuleInstance(AdMobStatics, AdMob);
this.analytics = this._staticsOrModuleInstance(AnalyticsStatics, Analytics);
this.auth = this._staticsOrModuleInstance(AuthStatics, Auth);
this.config = this._staticsOrModuleInstance(ConfigStatics, Config);
this.crash = this._staticsOrModuleInstance(CrashStatics, Crash);
this.database = this._staticsOrModuleInstance(DatabaseStatics, Database);
this.fabric = {
crashlytics: this._staticsOrModuleInstance(CrashlyticsStatics, Crashlytics),
};
this.firestore = this._staticsOrModuleInstance(FirestoreStatics, Firestore);
this.links = this._staticsOrModuleInstance(LinksStatics, Links);
this.messaging = this._staticsOrModuleInstance(MessagingStatics, Messaging);
this.perf = this._staticsOrModuleInstance(PerformanceStatics, Performance);
this.storage = this._staticsOrModuleInstance(StorageStatics, Storage);
this.utils = this._staticsOrModuleInstance(UtilsStatics, Utils);
this._extendedProps = {};
}
/**
*
* @param native
* @private
*/
_initializeApp(native: boolean = false) {
if (native) {
// for apps already initialized natively that
// we have info from RN constants
this._initialized = true; this._initialized = true;
this._nativeInitialized = true; this._nativeInitialized = true;
} else { } else if (options.databaseURL && options.apiKey) {
FirebaseCoreModule.initializeApp(this._name, this._options, (error, result) => { FirebaseCoreModule.initializeApp(this._name, this._options, (error, result) => {
this._initialized = true; this._initialized = true;
INTERNALS.SharedEventEmitter.emit(`AppReady:${this._name}`, { error, result }); SharedEventEmitter.emit(`AppReady:${this._name}`, { error, result });
}); });
} }
// modules
this.admob = APPS.appModule(this, AdmobNamespace, AdMob);
this.analytics = APPS.appModule(this, AnalyticsNamespace, Analytics);
this.auth = APPS.appModule(this, AuthNamespace, Auth);
this.config = APPS.appModule(this, ConfigNamespace, Config);
this.crash = APPS.appModule(this, CrashNamespace, Crash);
this.database = APPS.appModule(this, DatabaseNamespace, Database);
this.fabric = {
crashlytics: APPS.appModule(this, CrashlyticsNamespace, Crashlytics),
};
this.firestore = APPS.appModule(this, FirestoreNamespace, Firestore);
this.links = APPS.appModule(this, LinksNamespace, Links);
this.messaging = APPS.appModule(this, MessagingNamespace, Messaging);
this.perf = APPS.appModule(this, PerfNamespace, Performance);
this.storage = APPS.appModule(this, StorageNamespace, Storage);
this.utils = APPS.appModule(this, UtilsNamespace, Utils);
this._extendedProps = {};
} }
/** /**
@ -116,13 +89,6 @@ export default class FirebaseApp {
* @return {*} * @return {*}
*/ */
get name(): string { get name(): string {
if (this._name === INTERNALS.STRINGS.DEFAULT_APP_NAME) {
// ios and android firebase sdk's return different
// app names - so we just return what the web sdk
// would if it was default.
return '[DEFAULT]';
}
return this._name; return this._name;
} }
@ -153,6 +119,7 @@ export default class FirebaseApp {
throw new Error(INTERNALS.STRINGS.ERROR_PROTECTED_PROP(key)); throw new Error(INTERNALS.STRINGS.ERROR_PROTECTED_PROP(key));
} }
// $FlowBug: Flow doesn't support indexable signatures on classes: https://github.com/facebook/flow/issues/1323
this[key] = props[key]; this[key] = props[key];
this._extendedProps[key] = true; this._extendedProps[key] = true;
} }
@ -165,7 +132,7 @@ export default class FirebaseApp {
delete() { delete() {
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('app', 'delete')); throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('app', 'delete'));
// TODO only the ios sdk currently supports delete, add back in when android also supports it // TODO only the ios sdk currently supports delete, add back in when android also supports it
// if (this._name === INTERNALS.STRINGS.DEFAULT_APP_NAME && this._nativeInitialized) { // if (this._name === APPS.DEFAULT_APP_NAME && this._nativeInitialized) {
// return Promise.reject( // return Promise.reject(
// new Error('Unable to delete the default native firebase app instance.'), // new Error('Unable to delete the default native firebase app instance.'),
// ); // );
@ -179,42 +146,14 @@ export default class FirebaseApp {
* *
* @return {*} * @return {*}
*/ */
onReady(): Promise<FirebaseApp> { onReady(): Promise<App> {
if (this._initialized) return Promise.resolve(this); if (this._initialized) return Promise.resolve(this);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
INTERNALS.SharedEventEmitter.once(`AppReady:${this._name}`, ({ error }) => { SharedEventEmitter.once(`AppReady:${this._name}`, ({ error }) => {
if (error) return reject(new Error(error)); // error is a string as it's from native if (error) return reject(new Error(error)); // error is a string as it's from native
return resolve(this); // return app return resolve(this); // return app
}); });
}); });
} }
/**
*
* @param statics
* @param InstanceClass
* @return {function()}
* @private
*/
_staticsOrModuleInstance<M: FirebaseModule, S:FirebaseStatics>(statics: S, InstanceClass: Class<M>): FirebaseModuleAndStatics<M, S> {
const getInstance = (): M => {
const _name = `_${InstanceClass._NAMESPACE}`;
if (isAndroid && InstanceClass._NAMESPACE !== Utils._NAMESPACE && !INTERNALS.FLAGS.checkedPlayServices) {
INTERNALS.FLAGS.checkedPlayServices = true;
this.utils().checkPlayServicesAvailability();
}
if (!this._namespaces[_name]) {
this._namespaces[_name] = new InstanceClass(this, this._options);
}
return this._namespaces[_name];
};
return Object.assign(getInstance, statics, {
nativeModuleExists: !!NativeModules[InstanceClass._NATIVE_MODULE],
});
}
} }

View File

@ -2,26 +2,26 @@
* @providesModule Firebase * @providesModule Firebase
* @flow * @flow
*/ */
import { NativeModules, NativeEventEmitter } from 'react-native'; import { NativeModules } from 'react-native';
import APPS from '../../utils/apps';
import INTERNALS from '../../utils/internals'; import INTERNALS from '../../utils/internals';
import FirebaseApp from './firebase-app'; import App from './firebase-app';
import { isObject, isString } from '../../utils';
// module imports // module imports
import AdMob, { statics as AdMobStatics } from '../admob'; import { statics as AdMobStatics, MODULE_NAME as AdmobModuleName } from '../admob';
import Auth, { statics as AuthStatics } from '../auth'; import { statics as AuthStatics, MODULE_NAME as AuthModuleName } from '../auth';
import Analytics, { statics as AnalyticsStatics } from '../analytics'; import { statics as AnalyticsStatics, MODULE_NAME as AnalyticsModuleName } from '../analytics';
import Config, { statics as ConfigStatics } from '../config'; import { statics as ConfigStatics, MODULE_NAME as ConfigModuleName } from '../config';
import Crash, { statics as CrashStatics } from '../crash'; import { statics as CrashStatics, MODULE_NAME as CrashModuleName } from '../crash';
import Crashlytics, { statics as CrashlyticsStatics } from '../fabric/crashlytics'; import { statics as CrashlyticsStatics, MODULE_NAME as CrashlyticsModuleName } from '../fabric/crashlytics';
import Database, { statics as DatabaseStatics } from '../database'; import { statics as DatabaseStatics, MODULE_NAME as DatabaseModuleName } from '../database';
import Firestore, { statics as FirestoreStatics } from '../firestore'; import { statics as FirestoreStatics, MODULE_NAME as FirestoreModuleName } from '../firestore';
import Links, { statics as LinksStatics } from '../links'; import { statics as LinksStatics, MODULE_NAME as LinksModuleName } from '../links';
import Messaging, { statics as MessagingStatics } from '../messaging'; import { statics as MessagingStatics, MODULE_NAME as MessagingModuleName } from '../messaging';
import Performance, { statics as PerformanceStatics } from '../perf'; import { statics as PerformanceStatics, MODULE_NAME as PerfModuleName } from '../perf';
import Storage, { statics as StorageStatics } from '../storage'; import { statics as StorageStatics, MODULE_NAME as StorageModuleName } from '../storage';
import Utils, { statics as UtilsStatics } from '../utils'; import { statics as UtilsStatics, MODULE_NAME as UtilsModuleName } from '../utils';
import type { import type {
AdMobModule, AdMobModule,
@ -31,10 +31,7 @@ import type {
CrashModule, CrashModule,
DatabaseModule, DatabaseModule,
FabricModule, FabricModule,
FirebaseModule,
FirebaseModuleAndStatics,
FirebaseOptions, FirebaseOptions,
FirebaseStatics,
FirestoreModule, FirestoreModule,
LinksModule, LinksModule,
MessagingModule, MessagingModule,
@ -45,9 +42,7 @@ import type {
const FirebaseCoreModule = NativeModules.RNFirebase; const FirebaseCoreModule = NativeModules.RNFirebase;
class FirebaseCore { class Firebase {
_nativeEmitters: { [string]: NativeEventEmitter };
_nativeSubscriptions: { [string]: boolean };
admob: AdMobModule; admob: AdMobModule;
analytics: AnalyticsModule; analytics: AnalyticsModule;
auth: AuthModule; auth: AuthModule;
@ -63,45 +58,27 @@ class FirebaseCore {
utils: UtilsModule; utils: UtilsModule;
constructor() { constructor() {
this._nativeEmitters = {};
this._nativeSubscriptions = {};
if (!FirebaseCoreModule) { if (!FirebaseCoreModule) {
throw (new Error(INTERNALS.STRINGS.ERROR_MISSING_CORE)); throw (new Error(INTERNALS.STRINGS.ERROR_MISSING_CORE));
} }
APPS.initializeNativeApps();
this._initializeNativeApps();
// modules // modules
this.admob = this._appNamespaceOrStatics(AdMobStatics, AdMob); this.admob = APPS.moduleAndStatics('admob', AdMobStatics, AdmobModuleName);
this.analytics = this._appNamespaceOrStatics(AnalyticsStatics, Analytics); this.analytics = APPS.moduleAndStatics('analytics', AnalyticsStatics, AnalyticsModuleName);
this.auth = this._appNamespaceOrStatics(AuthStatics, Auth); this.auth = APPS.moduleAndStatics('auth', AuthStatics, AuthModuleName);
this.config = this._appNamespaceOrStatics(ConfigStatics, Config); this.config = APPS.moduleAndStatics('config', ConfigStatics, ConfigModuleName);
this.crash = this._appNamespaceOrStatics(CrashStatics, Crash); this.crash = APPS.moduleAndStatics('crash', CrashStatics, CrashModuleName);
this.database = this._appNamespaceOrStatics(DatabaseStatics, Database); this.database = APPS.moduleAndStatics('database', DatabaseStatics, DatabaseModuleName);
this.fabric = { this.fabric = {
crashlytics: this._appNamespaceOrStatics(CrashlyticsStatics, Crashlytics), crashlytics: APPS.moduleAndStatics('crashlytics', CrashlyticsStatics, CrashlyticsModuleName),
}; };
this.firestore = this._appNamespaceOrStatics(FirestoreStatics, Firestore); this.firestore = APPS.moduleAndStatics('firestore', FirestoreStatics, FirestoreModuleName);
this.links = this._appNamespaceOrStatics(LinksStatics, Links); this.links = APPS.moduleAndStatics('links', LinksStatics, LinksModuleName);
this.messaging = this._appNamespaceOrStatics(MessagingStatics, Messaging); this.messaging = APPS.moduleAndStatics('messaging', MessagingStatics, MessagingModuleName);
this.perf = this._appNamespaceOrStatics(PerformanceStatics, Performance); this.perf = APPS.moduleAndStatics('perf', PerformanceStatics, PerfModuleName);
this.storage = this._appNamespaceOrStatics(StorageStatics, Storage); this.storage = APPS.moduleAndStatics('storage', StorageStatics, StorageModuleName);
this.utils = this._appNamespaceOrStatics(UtilsStatics, Utils); this.utils = APPS.moduleAndStatics('utils', UtilsStatics, UtilsModuleName);
}
/**
* Bootstraps all native app instances that were discovered on boot
* @private
*/
_initializeNativeApps() {
for (let i = 0, len = FirebaseCoreModule.apps.length; i < len; i++) {
const app = FirebaseCoreModule.apps[i];
const options = Object.assign({}, app);
delete options.name;
INTERNALS.APPS[app.name] = new FirebaseApp(app.name, options);
INTERNALS.APPS[app.name]._initializeApp(true);
}
} }
/** /**
@ -111,58 +88,8 @@ class FirebaseCore {
* @param name * @param name
* @return {*} * @return {*}
*/ */
initializeApp(options: FirebaseOptions, name: string): FirebaseApp { initializeApp(options: FirebaseOptions, name: string): App {
if (name && !isString(name)) { return APPS.initializeApp(options, name);
throw new Error(INTERNALS.STRINGS.ERROR_INIT_STRING_NAME);
}
const _name = (name || INTERNALS.STRINGS.DEFAULT_APP_NAME).toUpperCase();
// return an existing app if found
// todo in v4 remove deprecation and throw an error
if (INTERNALS.APPS[_name]) {
console.warn(INTERNALS.STRINGS.WARN_INITIALIZE_DEPRECATION);
return INTERNALS.APPS[_name];
}
// only validate if app doesn't already exist
// to allow apps already initialized natively
// to still go through init without erroring (backwards compatibility)
if (!isObject(options)) {
throw new Error(INTERNALS.STRINGS.ERROR_INIT_OBJECT);
}
if (!options.apiKey) {
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_OPT('apiKey'));
}
if (!options.appId) {
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_OPT('appId'));
}
if (!options.databaseURL) {
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_OPT('databaseURL'));
}
if (!options.messagingSenderId) {
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_OPT('messagingSenderId'));
}
if (!options.projectId) {
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_OPT('projectId'));
}
if (!options.storageBucket) {
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_OPT('storageBucket'));
}
INTERNALS.APPS[_name] = new FirebaseApp(_name, options);
// only initialize if certain props are available
if (options.databaseURL && options.apiKey) {
INTERNALS.APPS[_name]._initializeApp();
}
return INTERNALS.APPS[_name];
} }
/** /**
@ -174,96 +101,17 @@ class FirebaseCore {
* @param name * @param name
* @return {*} * @return {*}
*/ */
app(name?: string): FirebaseApp { app(name?: string): App {
const _name = name ? name.toUpperCase() : INTERNALS.STRINGS.DEFAULT_APP_NAME; return APPS.app(name);
const app = INTERNALS.APPS[_name];
if (!app) throw new Error(INTERNALS.STRINGS.ERROR_APP_NOT_INIT(_name));
return app;
} }
/** /**
* A (read-only) array of all initialized apps. * A (read-only) array of all initialized apps.
* @return {Array} * @return {Array}
*/ */
get apps(): Array<FirebaseApp> { get apps(): Array<App> {
return Object.values(INTERNALS.APPS); return APPS.apps();
}
/*
* INTERNALS
*/
/**
* Subscribe to a native event for js side distribution by appName
* React Native events are hard set at compile - cant do dynamic event names
* so we use a single event send it to js and js then internally can prefix it
* and distribute dynamically.
*
* @param eventName
* @param nativeEmitter
* @private
*/
_subscribeForDistribution(eventName: string, nativeEmitter: NativeEventEmitter) {
if (!this._nativeSubscriptions[eventName]) {
nativeEmitter.addListener(eventName, (event) => {
if (event.appName) {
// native event has an appName property - auto prefix and internally emit
INTERNALS.SharedEventEmitter.emit(`${event.appName}-${eventName}`, event);
} else {
// standard event - no need to prefix
INTERNALS.SharedEventEmitter.emit(eventName, event);
}
});
this._nativeSubscriptions[eventName] = true;
}
}
/**
*
* @param statics
* @param InstanceClass
* @return {function(FirebaseApp=)}
* @private
*/
_appNamespaceOrStatics<M: FirebaseModule, S: FirebaseStatics>(statics: S, InstanceClass: Class<M>): FirebaseModuleAndStatics<M, S> {
const namespace = InstanceClass._NAMESPACE;
const getNamespace = (app?: FirebaseApp) => {
let _app = app;
// throw an error if it's not a valid app instance
if (_app && !(_app instanceof FirebaseApp)) throw new Error(INTERNALS.STRINGS.ERROR_NOT_APP(namespace));
// default to the 'DEFAULT' app if no arg provided - will throw an error
// if default app not initialized
else if (!_app) _app = this.app(INTERNALS.STRINGS.DEFAULT_APP_NAME);
const firebaseApp = INTERNALS.APPS[_app._name];
if (namespace === 'crashlytics') {
return firebaseApp.fabric[namespace](_app);
}
return firebaseApp[namespace](_app);
};
return Object.assign(getNamespace, statics, {
nativeModuleExists: !!NativeModules[InstanceClass._NATIVE_MODULE],
});
}
/**
*
* @param name
* @param nativeModule
* @return {*}
* @private
*/
_getOrSetNativeEmitter(name: string, nativeModule: Object): NativeEventEmitter {
if (this._nativeEmitters[name]) {
return this._nativeEmitters[name];
}
return this._nativeEmitters[name] = new NativeEventEmitter(nativeModule);
} }
} }
export default new FirebaseCore(); export default new Firebase();

View File

@ -3,16 +3,20 @@
* Crash Reporting representation wrapper * Crash Reporting representation wrapper
*/ */
import ModuleBase from '../../utils/ModuleBase'; import ModuleBase from '../../utils/ModuleBase';
import { getNativeModule } from '../../utils/native';
import type FirebaseApp from '../core/firebase-app'; import type App from '../core/firebase-app';
import type { FirebaseError } from '../../types'; import type { FirebaseError } from '../../types';
export default class Crash extends ModuleBase { export const MODULE_NAME = 'RNFirebaseCrash';
static _NAMESPACE = 'crash'; export const NAMESPACE = 'crash';
static _NATIVE_MODULE = 'RNFirebaseCrash';
constructor(firebaseApp: FirebaseApp, options: Object = {}) { export default class Crash extends ModuleBase {
super(firebaseApp, options); constructor(app: App) {
super(app, {
moduleName: MODULE_NAME,
namespace: NAMESPACE,
});
} }
/** /**
@ -20,7 +24,7 @@ export default class Crash extends ModuleBase {
* @param enabled * @param enabled
*/ */
setCrashCollectionEnabled(enabled: boolean): void { setCrashCollectionEnabled(enabled: boolean): void {
this._native.setCrashCollectionEnabled(enabled); getNativeModule(this).setCrashCollectionEnabled(enabled);
} }
/** /**
@ -28,7 +32,7 @@ export default class Crash extends ModuleBase {
* @returns {Promise.<boolean>} * @returns {Promise.<boolean>}
*/ */
isCrashCollectionEnabled(): Promise<boolean> { isCrashCollectionEnabled(): Promise<boolean> {
return this._native.isCrashCollectionEnabled(); return getNativeModule(this).isCrashCollectionEnabled();
} }
/** /**
@ -36,7 +40,7 @@ export default class Crash extends ModuleBase {
* @param {string} message * @param {string} message
*/ */
log(message: string): void { log(message: string): void {
this._native.log(message); getNativeModule(this).log(message);
} }
/** /**
@ -47,7 +51,7 @@ export default class Crash extends ModuleBase {
* @param {string} tag * @param {string} tag
*/ */
logcat(level: number, tag: string, message: string): void { logcat(level: number, tag: string, message: string): void {
this._native.logcat(level, tag, message); getNativeModule(this).logcat(level, tag, message);
} }
/** /**
@ -74,7 +78,7 @@ export default class Crash extends ModuleBase {
errorMessage = `${errorMessage} - ${stackRows[i]}\r\n`; errorMessage = `${errorMessage} - ${stackRows[i]}\r\n`;
} }
this._native.report(errorMessage); getNativeModule(this).report(errorMessage);
} }
} }

View File

@ -2,7 +2,8 @@
* @flow * @flow
* Disconnect representation wrapper * Disconnect representation wrapper
*/ */
import { typeOf } from './../../utils'; import { typeOf } from '../../utils';
import { getNativeModule } from '../../utils/native';
import type Database from './'; import type Database from './';
import type Reference from './reference'; import type Reference from './reference';
@ -32,7 +33,7 @@ export default class Disconnect {
* @returns {*} * @returns {*}
*/ */
set(value: string | Object): Promise<void> { set(value: string | Object): Promise<void> {
return this._database._native.onDisconnectSet(this.path, { type: typeOf(value), value }); return getNativeModule(this._database).onDisconnectSet(this.path, { type: typeOf(value), value });
} }
/** /**
@ -41,7 +42,7 @@ export default class Disconnect {
* @returns {*} * @returns {*}
*/ */
update(values: Object): Promise<void> { update(values: Object): Promise<void> {
return this._database._native.onDisconnectUpdate(this.path, values); return getNativeModule(this._database).onDisconnectUpdate(this.path, values);
} }
/** /**
@ -49,7 +50,7 @@ export default class Disconnect {
* @returns {*} * @returns {*}
*/ */
remove(): Promise<void> { remove(): Promise<void> {
return this._database._native.onDisconnectRemove(this.path); return getNativeModule(this._database).onDisconnectRemove(this.path);
} }
/** /**
@ -57,6 +58,6 @@ export default class Disconnect {
* @returns {*} * @returns {*}
*/ */
cancel(): Promise<void> { cancel(): Promise<void> {
return this._database._native.onDisconnectCancel(this.path); return getNativeModule(this._database).onDisconnectCancel(this.path);
} }
} }

View File

@ -6,27 +6,37 @@ import { NativeModules } from 'react-native';
import Reference from './reference'; import Reference from './reference';
import TransactionHandler from './transaction'; import TransactionHandler from './transaction';
import ModuleBase from './../../utils/ModuleBase'; import ModuleBase from '../../utils/ModuleBase';
import { getNativeModule } from '../../utils/native';
import type FirebaseApp from '../core/firebase-app'; import type App from '../core/firebase-app';
const NATIVE_EVENTS = [
'database_transaction_event',
// 'database_server_offset', // TODO
];
export const MODULE_NAME = 'RNFirebaseDatabase';
export const NAMESPACE = 'database';
/** /**
* @class Database * @class Database
*/ */
export default class Database extends ModuleBase { export default class Database extends ModuleBase {
static _NAMESPACE = 'database';
static _NATIVE_MODULE = 'RNFirebaseDatabase';
_offsetRef: Reference; _offsetRef: Reference;
_serverTimeOffset: number; _serverTimeOffset: number;
_transactionHandler: TransactionHandler; _transactionHandler: TransactionHandler;
constructor(firebaseApp: FirebaseApp, options: Object = {}) { constructor(app: App, options: Object = {}) {
super(firebaseApp, options, true); super(app, {
events: NATIVE_EVENTS,
moduleName: MODULE_NAME,
namespace: NAMESPACE,
});
this._transactionHandler = new TransactionHandler(this); this._transactionHandler = new TransactionHandler(this);
if (this._options.persistence) { if (options.persistence) {
this._native.setPersistence(this._options.persistence); getNativeModule(this).setPersistence(options.persistence);
} }
// server time listener // server time listener
@ -54,14 +64,14 @@ export default class Database extends ModuleBase {
* *
*/ */
goOnline(): void { goOnline(): void {
this._native.goOnline(); getNativeModule(this).goOnline();
} }
/** /**
* *
*/ */
goOffline(): void { goOffline(): void {
this._native.goOffline(); getNativeModule(this).goOffline();
} }
/** /**
@ -79,8 +89,8 @@ export const statics = {
TIMESTAMP: NativeModules.RNFirebaseDatabase.serverValueTimestamp || { '.sv': 'timestamp' }, TIMESTAMP: NativeModules.RNFirebaseDatabase.serverValueTimestamp || { '.sv': 'timestamp' },
} : {}, } : {},
enableLogging(enabled: boolean) { enableLogging(enabled: boolean) {
if (NativeModules[Database._NATIVE_MODULE]) { if (NativeModules[MODULE_NAME]) {
NativeModules[Database._NATIVE_MODULE].enableLogging(enabled); NativeModules[MODULE_NAME].enableLogging(enabled);
} }
}, },
}; };

View File

@ -5,6 +5,8 @@
import Query from './query.js'; import Query from './query.js';
import Snapshot from './snapshot'; import Snapshot from './snapshot';
import Disconnect from './disconnect'; import Disconnect from './disconnect';
import { getLogger } from '../../utils/log';
import { getNativeModule } from '../../utils/native';
import ReferenceBase from '../../utils/ReferenceBase'; import ReferenceBase from '../../utils/ReferenceBase';
import { import {
@ -17,10 +19,10 @@ import {
generatePushID, generatePushID,
} from '../../utils'; } from '../../utils';
import INTERNALS from '../../utils/internals'; import SyncTree from '../../utils/SyncTree';
import type Database from './';
import type { DatabaseModifier, FirebaseError } from '../../types'; import type { DatabaseModifier, FirebaseError } from '../../types';
import type SyncTree from '../../utils/SyncTree';
// track all event registrations by path // track all event registrations by path
let listeners = 0; let listeners = 0;
@ -73,18 +75,18 @@ type DatabaseListener = {
* @extends ReferenceBase * @extends ReferenceBase
*/ */
export default class Reference extends ReferenceBase { export default class Reference extends ReferenceBase {
_database: Object; _database: Database;
_promise: ?Promise<*>; _promise: ?Promise<*>;
_query: Query; _query: Query;
_refListeners: { [listenerId: number]: DatabaseListener }; _refListeners: { [listenerId: number]: DatabaseListener };
constructor(database: Object, path: string, existingModifiers?: Array<DatabaseModifier>) { constructor(database: Database, path: string, existingModifiers?: Array<DatabaseModifier>) {
super(path, database); super(path);
this._promise = null; this._promise = null;
this._refListeners = {}; this._refListeners = {};
this._database = database; this._database = database;
this._query = new Query(this, path, existingModifiers); this._query = new Query(this, path, existingModifiers);
this.log.debug('Created new Reference', this._getRefKey()); getLogger(database).debug('Created new Reference', this._getRefKey());
} }
/** /**
@ -98,7 +100,7 @@ export default class Reference extends ReferenceBase {
* @returns {*} * @returns {*}
*/ */
keepSynced(bool: boolean): Promise<void> { keepSynced(bool: boolean): Promise<void> {
return this._database._native.keepSynced(this._getRefKey(), this.path, this._query.getModifiers(), bool); return getNativeModule(this._database).keepSynced(this._getRefKey(), this.path, this._query.getModifiers(), bool);
} }
/** /**
@ -111,7 +113,7 @@ export default class Reference extends ReferenceBase {
*/ */
set(value: any, onComplete?: Function): Promise<void> { set(value: any, onComplete?: Function): Promise<void> {
return promiseOrCallback( return promiseOrCallback(
this._database._native.set(this.path, this._serializeAnyType(value)), getNativeModule(this._database).set(this.path, this._serializeAnyType(value)),
onComplete, onComplete,
); );
} }
@ -128,7 +130,7 @@ export default class Reference extends ReferenceBase {
const _priority = this._serializeAnyType(priority); const _priority = this._serializeAnyType(priority);
return promiseOrCallback( return promiseOrCallback(
this._database._native.setPriority(this.path, _priority), getNativeModule(this._database).setPriority(this.path, _priority),
onComplete, onComplete,
); );
} }
@ -147,7 +149,7 @@ export default class Reference extends ReferenceBase {
const _priority = this._serializeAnyType(priority); const _priority = this._serializeAnyType(priority);
return promiseOrCallback( return promiseOrCallback(
this._database._native.setWithPriority(this.path, _value, _priority), getNativeModule(this._database).setWithPriority(this.path, _value, _priority),
onComplete, onComplete,
); );
} }
@ -164,7 +166,7 @@ export default class Reference extends ReferenceBase {
const value = this._serializeObject(val); const value = this._serializeObject(val);
return promiseOrCallback( return promiseOrCallback(
this._database._native.update(this.path, value), getNativeModule(this._database).update(this.path, value),
onComplete, onComplete,
); );
} }
@ -178,7 +180,7 @@ export default class Reference extends ReferenceBase {
*/ */
remove(onComplete?: Function): Promise<void> { remove(onComplete?: Function): Promise<void> {
return promiseOrCallback( return promiseOrCallback(
this._database._native.remove(this.path), getNativeModule(this._database).remove(this.path),
onComplete, onComplete,
); );
} }
@ -234,7 +236,7 @@ export default class Reference extends ReferenceBase {
cancelOrContext: (error: FirebaseError) => void, cancelOrContext: (error: FirebaseError) => void,
context?: Object, context?: Object,
) { ) {
return this._database._native.once(this._getRefKey(), this.path, this._query.getModifiers(), eventName) return getNativeModule(this._database).once(this._getRefKey(), this.path, this._query.getModifiers(), eventName)
.then(({ snapshot }) => { .then(({ snapshot }) => {
const _snapshot = new Snapshot(this, snapshot); const _snapshot = new Snapshot(this, snapshot);
@ -269,7 +271,9 @@ export default class Reference extends ReferenceBase {
// if callback provided then internally call the set promise with value // if callback provided then internally call the set promise with value
if (isFunction(onComplete)) { if (isFunction(onComplete)) {
return promise return promise
// $FlowBug: Reports that onComplete can change to null despite the null check: https://github.com/facebook/flow/issues/1655
.then(() => onComplete(null, newRef)) .then(() => onComplete(null, newRef))
// $FlowBug: Reports that onComplete can change to null despite the null check: https://github.com/facebook/flow/issues/1655
.catch(error => onComplete(error, null)); .catch(error => onComplete(error, null));
} }
@ -535,7 +539,7 @@ export default class Reference extends ReferenceBase {
* @return {string} * @return {string}
*/ */
_getRegistrationKey(eventType: string): string { _getRegistrationKey(eventType: string): string {
return `$${this._database._appName}$/${this.path}$${this._query.queryIdentifier()}$${listeners}$${eventType}`; return `$${this._database.app.name}$/${this.path}$${this._query.queryIdentifier()}$${listeners}$${eventType}`;
} }
/** /**
@ -546,14 +550,7 @@ export default class Reference extends ReferenceBase {
* @private * @private
*/ */
_getRefKey(): string { _getRefKey(): string {
return `$${this._database._appName}$/${this.path}$${this._query.queryIdentifier()}`; return `$${this._database.app.name}$/${this.path}$${this._query.queryIdentifier()}`;
}
/**
* Return instance of db logger
*/
get log() {
return this._database.log;
} }
/** /**
@ -626,7 +623,7 @@ export default class Reference extends ReferenceBase {
* *
* {@link https://firebase.google.com/docs/reference/js/firebase.database.Reference#on} * {@link https://firebase.google.com/docs/reference/js/firebase.database.Reference#on}
*/ */
on(eventType: string, callback: () => any, cancelCallbackOrContext?: () => any, context?: Object): Function { on(eventType: string, callback: (Snapshot) => any, cancelCallbackOrContext?: (Object) => any | Object, context?: Object): Function {
if (!eventType) { if (!eventType) {
throw new Error('Query.on failed: Function called with 0 arguments. Expects at least 2.'); throw new Error('Query.on failed: Function called with 0 arguments. Expects at least 2.');
} }
@ -659,36 +656,37 @@ export default class Reference extends ReferenceBase {
ref: this, ref: this,
path: this.path, path: this.path,
key: this._getRefKey(), key: this._getRefKey(),
appName: this._database._appName, appName: this._database.app.name,
eventRegistrationKey, eventRegistrationKey,
}; };
this._syncTree.addRegistration(registrationObj, _context ? callback.bind(_context) : callback); SyncTree.addRegistration({
...registrationObj,
listener: _context ? callback.bind(_context) : callback,
});
if (isFunction(cancelCallbackOrContext)) { if (cancelCallbackOrContext && isFunction(cancelCallbackOrContext)) {
// cancellations have their own separate registration // cancellations have their own separate registration
// as these are one off events, and they're not guaranteed // as these are one off events, and they're not guaranteed
// to occur either, only happens on failure to register on native // to occur either, only happens on failure to register on native
this._syncTree.addRegistration( SyncTree.addRegistration({
{ ref: this,
ref: this, once: true,
once: true, path: this.path,
path: this.path, key: this._getRefKey(),
key: this._getRefKey(), appName: this._database.app.name,
appName: this._database._appName, eventType: `${eventType}$cancelled`,
eventType: `${eventType}$cancelled`, eventRegistrationKey: registrationCancellationKey,
eventRegistrationKey: registrationCancellationKey, listener: _context ? cancelCallbackOrContext.bind(_context) : cancelCallbackOrContext,
}, });
_context ? cancelCallbackOrContext.bind(_context) : cancelCallbackOrContext,
);
} }
// initialise the native listener if not already listening // initialise the native listener if not already listening
this._database._native.on({ getNativeModule(this._database).on({
eventType, eventType,
path: this.path, path: this.path,
key: this._getRefKey(), key: this._getRefKey(),
appName: this._database._appName, appName: this._database.app.name,
modifiers: this._query.getModifiers(), modifiers: this._query.getModifiers(),
hasCancellationCallback: isFunction(cancelCallbackOrContext), hasCancellationCallback: isFunction(cancelCallbackOrContext),
registration: { registration: {
@ -726,7 +724,7 @@ export default class Reference extends ReferenceBase {
if (!arguments.length) { if (!arguments.length) {
// Firebase Docs: // Firebase Docs:
// if no eventType or callback is specified, all callbacks for the Reference will be removed. // if no eventType or callback is specified, all callbacks for the Reference will be removed.
return this._syncTree.removeListenersForRegistrations(this._syncTree.getRegistrationsByPath(this.path)); return SyncTree.removeListenersForRegistrations(SyncTree.getRegistrationsByPath(this.path));
} }
/* /*
@ -747,29 +745,25 @@ export default class Reference extends ReferenceBase {
// remove the callback. // remove the callback.
// Remove only a single registration // Remove only a single registration
if (eventType && originalCallback) { if (eventType && originalCallback) {
const registration = this._syncTree.getOneByPathEventListener(this.path, eventType, originalCallback); const registration = SyncTree.getOneByPathEventListener(this.path, eventType, originalCallback);
if (!registration) return []; if (!registration) return [];
// remove the paired cancellation registration if any exist // remove the paired cancellation registration if any exist
this._syncTree.removeListenersForRegistrations([`${registration}$cancelled`]); SyncTree.removeListenersForRegistrations([`${registration}$cancelled`]);
// remove only the first registration to match firebase web sdk // remove only the first registration to match firebase web sdk
// call multiple times to remove multiple registrations // call multiple times to remove multiple registrations
return this._syncTree.removeListenerRegistrations(originalCallback, [registration]); return SyncTree.removeListenerRegistrations(originalCallback, [registration]);
} }
// Firebase Docs: // Firebase Docs:
// If a callback is not specified, all callbacks for the specified eventType will be removed. // If a callback is not specified, all callbacks for the specified eventType will be removed.
const registrations = this._syncTree.getRegistrationsByPathEvent(this.path, eventType); const registrations = SyncTree.getRegistrationsByPathEvent(this.path, eventType);
this._syncTree.removeListenersForRegistrations( SyncTree.removeListenersForRegistrations(
this._syncTree.getRegistrationsByPathEvent(this.path, `${eventType}$cancelled`), SyncTree.getRegistrationsByPathEvent(this.path, `${eventType}$cancelled`),
); );
return this._syncTree.removeListenersForRegistrations(registrations); return SyncTree.removeListenersForRegistrations(registrations);
}
get _syncTree(): SyncTree {
return INTERNALS.SyncTree;
} }
} }

View File

@ -2,24 +2,36 @@
* @flow * @flow
* Database Transaction representation wrapper * Database Transaction representation wrapper
*/ */
import { getAppEventName, SharedEventEmitter } from '../../utils/events';
import { getLogger } from '../../utils/log';
import { getNativeModule } from '../../utils/native';
import type Database from './'; import type Database from './';
let transactionId = 0; let transactionId = 0;
/**
* Uses the push id generator to create a transaction id
* @returns {number}
* @private
*/
const generateTransactionId = (): number => {
return transactionId++;
};
/** /**
* @class TransactionHandler * @class TransactionHandler
*/ */
export default class TransactionHandler { export default class TransactionHandler {
_database: Database; _database: Database;
_transactionListener: Function; _transactionListener: Function;
_transactions: { [string]: Object } _transactions: { [number]: Object }
constructor(database: Database) { constructor(database: Database) {
this._transactions = {}; this._transactions = {};
this._database = database; this._database = database;
this._transactionListener = this._database.addListener( this._transactionListener = SharedEventEmitter.addListener(
this._database._getAppEventName('database_transaction_event'), getAppEventName(this._database, 'database_transaction_event'),
this._handleTransactionEvent.bind(this), this._handleTransactionEvent.bind(this),
); );
} }
@ -32,7 +44,7 @@ export default class TransactionHandler {
* @param applyLocally * @param applyLocally
*/ */
add(reference: Object, transactionUpdater: Function, onComplete?: Function, applyLocally?: boolean = false) { add(reference: Object, transactionUpdater: Function, onComplete?: Function, applyLocally?: boolean = false) {
const id = this._generateTransactionId(); const id = generateTransactionId();
this._transactions[id] = { this._transactions[id] = {
id, id,
@ -44,22 +56,13 @@ export default class TransactionHandler {
started: true, started: true,
}; };
this._database._native.transactionStart(reference.path, id, applyLocally); getNativeModule(this._database).transactionStart(reference.path, id, applyLocally);
} }
/** /**
* INTERNALS * INTERNALS
*/ */
/**
* Uses the push id generator to create a transaction id
* @returns {string}
* @private
*/
_generateTransactionId(): string {
return transactionId++;
}
/** /**
* *
* @param event * @param event
@ -75,7 +78,7 @@ export default class TransactionHandler {
case 'complete': case 'complete':
return this._handleComplete(event); return this._handleComplete(event);
default: default:
this.log.warn(`Unknown transaction event type: '${event.type}'`, event); getLogger(this._database).warn(`Unknown transaction event type: '${event.type}'`, event);
return undefined; return undefined;
} }
} }
@ -101,7 +104,7 @@ export default class TransactionHandler {
abort = true; abort = true;
} }
this._database._native.transactionTryCommit(id, { value: newValue, abort }); getNativeModule(this._database).transactionTryCommit(id, { value: newValue, abort });
} }
} }
@ -115,7 +118,7 @@ export default class TransactionHandler {
if (transaction && !transaction.completed) { if (transaction && !transaction.completed) {
transaction.completed = true; transaction.completed = true;
try { try {
transaction.onComplete(new Error(event.error.message, event.error.code), null); transaction.onComplete(event.error, false, null);
} finally { } finally {
setImmediate(() => { setImmediate(() => {
delete this._transactions[event.id]; delete this._transactions[event.id];

View File

@ -3,22 +3,26 @@
* Crash Reporting representation wrapper * Crash Reporting representation wrapper
*/ */
import ModuleBase from '../../../utils/ModuleBase'; import ModuleBase from '../../../utils/ModuleBase';
import { getNativeModule } from '../../../utils/native';
import type FirebaseApp from '../../core/firebase-app'; import type App from '../../core/firebase-app';
export const MODULE_NAME = 'RNFirebaseCrashlytics';
export const NAMESPACE = 'crashlytics';
export default class Crashlytics extends ModuleBase { export default class Crashlytics extends ModuleBase {
static _NAMESPACE = 'crashlytics'; constructor(app: App) {
static _NATIVE_MODULE = 'RNFirebaseCrashlytics'; super(app, {
moduleName: MODULE_NAME,
constructor(firebaseApp: FirebaseApp, options: Object = {}) { namespace: NAMESPACE,
super(firebaseApp, options); });
} }
/** /**
* Forces a crash. Useful for testing your application is set up correctly. * Forces a crash. Useful for testing your application is set up correctly.
*/ */
crash(): void { crash(): void {
this._native.crash(); getNativeModule(this).crash();
} }
/** /**
@ -26,7 +30,7 @@ export default class Crashlytics extends ModuleBase {
* @param {string} message * @param {string} message
*/ */
log(message: string): void { log(message: string): void {
this._native.log(message); getNativeModule(this).log(message);
} }
/** /**
@ -35,42 +39,42 @@ export default class Crashlytics extends ModuleBase {
* @param {string} message * @param {string} message
*/ */
recordError(code: number, message: string): void { recordError(code: number, message: string): void {
this._native.recordError(code, message); getNativeModule(this).recordError(code, message);
} }
/** /**
* Set a boolean value to show alongside any subsequent crash reports. * Set a boolean value to show alongside any subsequent crash reports.
*/ */
setBoolValue(key: string, value: boolean): void { setBoolValue(key: string, value: boolean): void {
this._native.setBoolValue(key, value); getNativeModule(this).setBoolValue(key, value);
} }
/** /**
* Set a float value to show alongside any subsequent crash reports. * Set a float value to show alongside any subsequent crash reports.
*/ */
setFloatValue(key: string, value: number): void { setFloatValue(key: string, value: number): void {
this._native.setFloatValue(key, value); getNativeModule(this).setFloatValue(key, value);
} }
/** /**
* Set an integer value to show alongside any subsequent crash reports. * Set an integer value to show alongside any subsequent crash reports.
*/ */
setIntValue(key: string, value: number): void { setIntValue(key: string, value: number): void {
this._native.setIntValue(key, value); getNativeModule(this).setIntValue(key, value);
} }
/** /**
* Set a string value to show alongside any subsequent crash reports. * Set a string value to show alongside any subsequent crash reports.
*/ */
setStringValue(key: string, value: string): void { setStringValue(key: string, value: string): void {
this._native.setStringValue(key, value); getNativeModule(this).setStringValue(key, value);
} }
/** /**
* Set the user ID to show alongside any subsequent crash reports. * Set the user ID to show alongside any subsequent crash reports.
*/ */
setUserIdentifier(userId: string): void { setUserIdentifier(userId: string): void {
this._native.setUserIdentifier(userId); getNativeModule(this).setUserIdentifier(userId);
} }
} }

View File

@ -6,11 +6,10 @@ import DocumentReference from './DocumentReference';
import Query from './Query'; import Query from './Query';
import { firestoreAutoId } from '../../utils'; import { firestoreAutoId } from '../../utils';
import type DocumentSnapshot from './DocumentSnapshot';
import type Firestore from './'; import type Firestore from './';
import type { FirestoreQueryDirection, FirestoreQueryOperator } from '../../types'; import type { FirestoreQueryDirection, FirestoreQueryOperator } from '../../types';
import type Path from './Path'; import type Path from './Path';
import type { Observer, QueryListenOptions } from './Query'; import type { Observer, ObserverOnError, ObserverOnNext, QueryListenOptions } from './Query';
import type QuerySnapshot from './QuerySnapshot'; import type QuerySnapshot from './QuerySnapshot';
/** /**
@ -75,9 +74,9 @@ export default class CollectionReference {
} }
onSnapshot( onSnapshot(
optionsOrObserverOrOnNext: QueryListenOptions | Observer | (DocumentSnapshot) => void, optionsOrObserverOrOnNext: QueryListenOptions | Observer | ObserverOnNext,
observerOrOnNextOrOnError?: Observer | (DocumentSnapshot) => void | (Object) => void, observerOrOnNextOrOnError?: Observer | ObserverOnNext | ObserverOnError,
onError?: (Object) => void, onError?: ObserverOnError,
): () => void { ): () => void {
return this._query.onSnapshot(optionsOrObserverOrOnNext, observerOrOnNextOrOnError, onError); return this._query.onSnapshot(optionsOrObserverOrOnNext, observerOrOnNextOrOnError, onError);
} }

View File

@ -5,7 +5,10 @@
import CollectionReference from './CollectionReference'; import CollectionReference from './CollectionReference';
import DocumentSnapshot from './DocumentSnapshot'; import DocumentSnapshot from './DocumentSnapshot';
import { buildNativeMap } from './utils/serialize'; import { buildNativeMap } from './utils/serialize';
import { getAppEventName, SharedEventEmitter } from '../../utils/events';
import { getLogger } from '../../utils/log';
import { firestoreAutoId, isFunction, isObject, isString } from '../../utils'; import { firestoreAutoId, isFunction, isObject, isString } from '../../utils';
import { getNativeModule } from '../../utils/native';
import type Firestore from './'; import type Firestore from './';
import type { FirestoreNativeDocumentSnapshot, FirestoreWriteOptions } from '../../types'; import type { FirestoreNativeDocumentSnapshot, FirestoreWriteOptions } from '../../types';
@ -65,12 +68,12 @@ export default class DocumentReference {
} }
delete(): Promise<void> { delete(): Promise<void> {
return this._firestore._native return getNativeModule(this._firestore)
.documentDelete(this.path); .documentDelete(this.path);
} }
get(): Promise<DocumentSnapshot> { get(): Promise<DocumentSnapshot> {
return this._firestore._native return getNativeModule(this._firestore)
.documentGet(this.path) .documentGet(this.path)
.then(result => new DocumentSnapshot(this._firestore, result)); .then(result => new DocumentSnapshot(this._firestore, result));
} }
@ -80,15 +83,18 @@ export default class DocumentReference {
observerOrOnNextOrOnError?: Observer | ObserverOnNext | ObserverOnError, observerOrOnNextOrOnError?: Observer | ObserverOnNext | ObserverOnError,
onError?: ObserverOnError, onError?: ObserverOnError,
) { ) {
let observer = {}; let observer: Observer;
let docListenOptions = {}; let docListenOptions = {};
// Called with: onNext, ?onError // Called with: onNext, ?onError
if (isFunction(optionsOrObserverOrOnNext)) { if (isFunction(optionsOrObserverOrOnNext)) {
observer.next = optionsOrObserverOrOnNext;
if (observerOrOnNextOrOnError && !isFunction(observerOrOnNextOrOnError)) { if (observerOrOnNextOrOnError && !isFunction(observerOrOnNextOrOnError)) {
throw new Error('DocumentReference.onSnapshot failed: Second argument must be a valid function.'); throw new Error('DocumentReference.onSnapshot failed: Second argument must be a valid function.');
} }
observer.error = observerOrOnNextOrOnError; // $FlowBug: Not coping with the overloaded method signature
observer = {
next: optionsOrObserverOrOnNext,
error: observerOrOnNextOrOnError,
};
} else if (optionsOrObserverOrOnNext && isObject(optionsOrObserverOrOnNext)) { } else if (optionsOrObserverOrOnNext && isObject(optionsOrObserverOrOnNext)) {
// Called with: Observer // Called with: Observer
if (optionsOrObserverOrOnNext.next) { if (optionsOrObserverOrOnNext.next) {
@ -96,7 +102,11 @@ export default class DocumentReference {
if (optionsOrObserverOrOnNext.error && !isFunction(optionsOrObserverOrOnNext.error)) { if (optionsOrObserverOrOnNext.error && !isFunction(optionsOrObserverOrOnNext.error)) {
throw new Error('DocumentReference.onSnapshot failed: Observer.error must be a valid function.'); throw new Error('DocumentReference.onSnapshot failed: Observer.error must be a valid function.');
} }
observer = optionsOrObserverOrOnNext; // $FlowBug: Not coping with the overloaded method signature
observer = {
next: optionsOrObserverOrOnNext.next,
error: optionsOrObserverOrOnNext.error,
};
} else { } else {
throw new Error('DocumentReference.onSnapshot failed: Observer.next must be a valid function.'); throw new Error('DocumentReference.onSnapshot failed: Observer.next must be a valid function.');
} }
@ -104,18 +114,24 @@ export default class DocumentReference {
docListenOptions = optionsOrObserverOrOnNext; docListenOptions = optionsOrObserverOrOnNext;
// Called with: Options, onNext, ?onError // Called with: Options, onNext, ?onError
if (isFunction(observerOrOnNextOrOnError)) { if (isFunction(observerOrOnNextOrOnError)) {
observer.next = observerOrOnNextOrOnError;
if (onError && !isFunction(onError)) { if (onError && !isFunction(onError)) {
throw new Error('DocumentReference.onSnapshot failed: Third argument must be a valid function.'); throw new Error('DocumentReference.onSnapshot failed: Third argument must be a valid function.');
} }
observer.error = onError; // $FlowBug: Not coping with the overloaded method signature
observer = {
next: observerOrOnNextOrOnError,
error: onError,
};
// Called with Options, Observer // Called with Options, Observer
} else if (observerOrOnNextOrOnError && isObject(observerOrOnNextOrOnError) && observerOrOnNextOrOnError.next) { } else if (observerOrOnNextOrOnError && isObject(observerOrOnNextOrOnError) && observerOrOnNextOrOnError.next) {
if (isFunction(observerOrOnNextOrOnError.next)) { if (isFunction(observerOrOnNextOrOnError.next)) {
if (observerOrOnNextOrOnError.error && !isFunction(observerOrOnNextOrOnError.error)) { if (observerOrOnNextOrOnError.error && !isFunction(observerOrOnNextOrOnError.error)) {
throw new Error('DocumentReference.onSnapshot failed: Observer.error must be a valid function.'); throw new Error('DocumentReference.onSnapshot failed: Observer.error must be a valid function.');
} }
observer = observerOrOnNextOrOnError; observer = {
next: observerOrOnNextOrOnError.next,
error: observerOrOnNextOrOnError.error,
};
} else { } else {
throw new Error('DocumentReference.onSnapshot failed: Observer.next must be a valid function.'); throw new Error('DocumentReference.onSnapshot failed: Observer.next must be a valid function.');
} }
@ -136,21 +152,21 @@ export default class DocumentReference {
}; };
// Listen to snapshot events // Listen to snapshot events
this._firestore.on( SharedEventEmitter.addListener(
this._firestore._getAppEventName(`onDocumentSnapshot:${listenerId}`), getAppEventName(this._firestore, `onDocumentSnapshot:${listenerId}`),
listener, listener,
); );
// Listen for snapshot error events // Listen for snapshot error events
if (observer.error) { if (observer.error) {
this._firestore.on( SharedEventEmitter.addListener(
this._firestore._getAppEventName(`onDocumentSnapshotError:${listenerId}`), getAppEventName(this._firestore, `onDocumentSnapshotError:${listenerId}`),
observer.error, observer.error,
); );
} }
// Add the native listener // Add the native listener
this._firestore._native getNativeModule(this._firestore)
.documentOnSnapshot(this.path, listenerId, docListenOptions); .documentOnSnapshot(this.path, listenerId, docListenOptions);
// Return an unsubscribe method // Return an unsubscribe method
@ -159,7 +175,7 @@ export default class DocumentReference {
set(data: Object, writeOptions?: FirestoreWriteOptions): Promise<void> { set(data: Object, writeOptions?: FirestoreWriteOptions): Promise<void> {
const nativeData = buildNativeMap(data); const nativeData = buildNativeMap(data);
return this._firestore._native return getNativeModule(this._firestore)
.documentSet(this.path, nativeData, writeOptions); .documentSet(this.path, nativeData, writeOptions);
} }
@ -183,7 +199,7 @@ export default class DocumentReference {
} }
} }
const nativeData = buildNativeMap(data); const nativeData = buildNativeMap(data);
return this._firestore._native return getNativeModule(this._firestore)
.documentUpdate(this.path, nativeData); .documentUpdate(this.path, nativeData);
} }
@ -196,10 +212,10 @@ export default class DocumentReference {
* @param listener * @param listener
*/ */
_offDocumentSnapshot(listenerId: string, listener: Function) { _offDocumentSnapshot(listenerId: string, listener: Function) {
this._firestore.log.info('Removing onDocumentSnapshot listener'); getLogger(this._firestore).info('Removing onDocumentSnapshot listener');
this._firestore.removeListener(this._firestore._getAppEventName(`onDocumentSnapshot:${listenerId}`), listener); SharedEventEmitter.removeListener(getAppEventName(this._firestore, `onDocumentSnapshot:${listenerId}`), listener);
this._firestore.removeListener(this._firestore._getAppEventName(`onDocumentSnapshotError:${listenerId}`), listener); SharedEventEmitter.removeListener(getAppEventName(this._firestore, `onDocumentSnapshotError:${listenerId}`), listener);
this._firestore._native getNativeModule(this._firestore)
.documentOffSnapshot(this.path, listenerId); .documentOffSnapshot(this.path, listenerId);
} }
} }

View File

@ -5,7 +5,10 @@
import DocumentSnapshot from './DocumentSnapshot'; import DocumentSnapshot from './DocumentSnapshot';
import QuerySnapshot from './QuerySnapshot'; import QuerySnapshot from './QuerySnapshot';
import { buildNativeArray, buildTypeMap } from './utils/serialize'; import { buildNativeArray, buildTypeMap } from './utils/serialize';
import { getAppEventName, SharedEventEmitter } from '../../utils/events';
import { getLogger } from '../../utils/log';
import { firestoreAutoId, isFunction, isObject } from '../../utils'; import { firestoreAutoId, isFunction, isObject } from '../../utils';
import { getNativeModule } from '../../utils/native';
import type Firestore from './'; import type Firestore from './';
import type { FirestoreQueryDirection, FirestoreQueryOperator } from '../../types'; import type { FirestoreQueryDirection, FirestoreQueryOperator } from '../../types';
@ -51,9 +54,12 @@ export type QueryListenOptions = {
includeQueryMetadataChanges: boolean, includeQueryMetadataChanges: boolean,
} }
export type ObserverOnError = (Object) => void;
export type ObserverOnNext = (QuerySnapshot) => void;
export type Observer = { export type Observer = {
next: (DocumentSnapshot) => void, error?: ObserverOnError,
error?: (Object) => void, next: ObserverOnNext,
} }
/** /**
@ -117,7 +123,7 @@ export default class Query {
} }
get(): Promise<QuerySnapshot> { get(): Promise<QuerySnapshot> {
return this._firestore._native return getNativeModule(this._firestore)
.collectionGet( .collectionGet(
this._referencePath.relativeName, this._referencePath.relativeName,
this._fieldFilters, this._fieldFilters,
@ -145,19 +151,22 @@ export default class Query {
} }
onSnapshot( onSnapshot(
optionsOrObserverOrOnNext: QueryListenOptions | Observer | (DocumentSnapshot) => void, optionsOrObserverOrOnNext: QueryListenOptions | Observer | ObserverOnNext,
observerOrOnNextOrOnError?: Observer | (DocumentSnapshot) => void | (Object) => void, observerOrOnNextOrOnError?: Observer | ObserverOnNext | ObserverOnError,
onError?: (Object) => void, onError?: ObserverOnError,
) { ) {
let observer = {}; let observer: Observer;
let queryListenOptions = {}; let queryListenOptions = {};
// Called with: onNext, ?onError // Called with: onNext, ?onError
if (isFunction(optionsOrObserverOrOnNext)) { if (isFunction(optionsOrObserverOrOnNext)) {
observer.next = optionsOrObserverOrOnNext;
if (observerOrOnNextOrOnError && !isFunction(observerOrOnNextOrOnError)) { if (observerOrOnNextOrOnError && !isFunction(observerOrOnNextOrOnError)) {
throw new Error('Query.onSnapshot failed: Second argument must be a valid function.'); throw new Error('Query.onSnapshot failed: Second argument must be a valid function.');
} }
observer.error = observerOrOnNextOrOnError; // $FlowBug: Not coping with the overloaded method signature
observer = {
next: optionsOrObserverOrOnNext,
error: observerOrOnNextOrOnError,
};
} else if (optionsOrObserverOrOnNext && isObject(optionsOrObserverOrOnNext)) { } else if (optionsOrObserverOrOnNext && isObject(optionsOrObserverOrOnNext)) {
// Called with: Observer // Called with: Observer
if (optionsOrObserverOrOnNext.next) { if (optionsOrObserverOrOnNext.next) {
@ -165,7 +174,11 @@ export default class Query {
if (optionsOrObserverOrOnNext.error && !isFunction(optionsOrObserverOrOnNext.error)) { if (optionsOrObserverOrOnNext.error && !isFunction(optionsOrObserverOrOnNext.error)) {
throw new Error('Query.onSnapshot failed: Observer.error must be a valid function.'); throw new Error('Query.onSnapshot failed: Observer.error must be a valid function.');
} }
observer = optionsOrObserverOrOnNext; // $FlowBug: Not coping with the overloaded method signature
observer = {
next: optionsOrObserverOrOnNext.next,
error: optionsOrObserverOrOnNext.error,
};
} else { } else {
throw new Error('Query.onSnapshot failed: Observer.next must be a valid function.'); throw new Error('Query.onSnapshot failed: Observer.next must be a valid function.');
} }
@ -173,18 +186,24 @@ export default class Query {
queryListenOptions = optionsOrObserverOrOnNext; queryListenOptions = optionsOrObserverOrOnNext;
// Called with: Options, onNext, ?onError // Called with: Options, onNext, ?onError
if (isFunction(observerOrOnNextOrOnError)) { if (isFunction(observerOrOnNextOrOnError)) {
observer.next = observerOrOnNextOrOnError;
if (onError && !isFunction(onError)) { if (onError && !isFunction(onError)) {
throw new Error('Query.onSnapshot failed: Third argument must be a valid function.'); throw new Error('Query.onSnapshot failed: Third argument must be a valid function.');
} }
observer.error = onError; // $FlowBug: Not coping with the overloaded method signature
observer = {
next: observerOrOnNextOrOnError,
error: onError,
};
// Called with Options, Observer // Called with Options, Observer
} else if (observerOrOnNextOrOnError && isObject(observerOrOnNextOrOnError) && observerOrOnNextOrOnError.next) { } else if (observerOrOnNextOrOnError && isObject(observerOrOnNextOrOnError) && observerOrOnNextOrOnError.next) {
if (isFunction(observerOrOnNextOrOnError.next)) { if (isFunction(observerOrOnNextOrOnError.next)) {
if (observerOrOnNextOrOnError.error && !isFunction(observerOrOnNextOrOnError.error)) { if (observerOrOnNextOrOnError.error && !isFunction(observerOrOnNextOrOnError.error)) {
throw new Error('Query.onSnapshot failed: Observer.error must be a valid function.'); throw new Error('Query.onSnapshot failed: Observer.error must be a valid function.');
} }
observer = observerOrOnNextOrOnError; observer = {
next: observerOrOnNextOrOnError.next,
error: observerOrOnNextOrOnError.error,
};
} else { } else {
throw new Error('Query.onSnapshot failed: Observer.next must be a valid function.'); throw new Error('Query.onSnapshot failed: Observer.next must be a valid function.');
} }
@ -197,7 +216,6 @@ export default class Query {
} else { } else {
throw new Error('Query.onSnapshot failed: Called with invalid arguments.'); throw new Error('Query.onSnapshot failed: Called with invalid arguments.');
} }
const listenerId = firestoreAutoId(); const listenerId = firestoreAutoId();
const listener = (nativeQuerySnapshot) => { const listener = (nativeQuerySnapshot) => {
@ -206,21 +224,21 @@ export default class Query {
}; };
// Listen to snapshot events // Listen to snapshot events
this._firestore.on( SharedEventEmitter.addListener(
this._firestore._getAppEventName(`onQuerySnapshot:${listenerId}`), getAppEventName(this._firestore, `onQuerySnapshot:${listenerId}`),
listener, listener,
); );
// Listen for snapshot error events // Listen for snapshot error events
if (observer.error) { if (observer.error) {
this._firestore.on( SharedEventEmitter.addListener(
this._firestore._getAppEventName(`onQuerySnapshotError:${listenerId}`), getAppEventName(this._firestore, `onQuerySnapshotError:${listenerId}`),
observer.error, observer.error,
); );
} }
// Add the native listener // Add the native listener
this._firestore._native getNativeModule(this._firestore)
.collectionOnSnapshot( .collectionOnSnapshot(
this._referencePath.relativeName, this._referencePath.relativeName,
this._fieldFilters, this._fieldFilters,
@ -334,10 +352,10 @@ export default class Query {
* @param listener * @param listener
*/ */
_offCollectionSnapshot(listenerId: string, listener: Function) { _offCollectionSnapshot(listenerId: string, listener: Function) {
this._firestore.log.info('Removing onQuerySnapshot listener'); getLogger(this._firestore).info('Removing onQuerySnapshot listener');
this._firestore.removeListener(this._firestore._getAppEventName(`onQuerySnapshot:${listenerId}`), listener); SharedEventEmitter.removeListener(getAppEventName(this._firestore, `onQuerySnapshot:${listenerId}`), listener);
this._firestore.removeListener(this._firestore._getAppEventName(`onQuerySnapshotError:${listenerId}`), listener); SharedEventEmitter.removeListener(getAppEventName(this._firestore, `onQuerySnapshotError:${listenerId}`), listener);
this._firestore._native getNativeModule(this._firestore)
.collectionOffSnapshot( .collectionOffSnapshot(
this._referencePath.relativeName, this._referencePath.relativeName,
this._fieldFilters, this._fieldFilters,

View File

@ -4,6 +4,7 @@
*/ */
import { buildNativeMap } from './utils/serialize'; import { buildNativeMap } from './utils/serialize';
import { isObject, isString } from '../../utils'; import { isObject, isString } from '../../utils';
import { getNativeModule } from '../../utils/native';
import type DocumentReference from './DocumentReference'; import type DocumentReference from './DocumentReference';
import type Firestore from './'; import type Firestore from './';
@ -29,8 +30,7 @@ export default class WriteBatch {
} }
commit(): Promise<void> { commit(): Promise<void> {
return this._firestore._native return getNativeModule(this._firestore).documentBatch(this._writes);
.documentBatch(this._writes);
} }
delete(docRef: DocumentReference): WriteBatch { delete(docRef: DocumentReference): WriteBatch {

View File

@ -4,7 +4,8 @@
*/ */
import { NativeModules } from 'react-native'; import { NativeModules } from 'react-native';
import ModuleBase from './../../utils/ModuleBase'; import { getAppEventName, SharedEventEmitter } from '../../utils/events';
import ModuleBase from '../../utils/ModuleBase';
import CollectionReference from './CollectionReference'; import CollectionReference from './CollectionReference';
import DocumentReference from './DocumentReference'; import DocumentReference from './DocumentReference';
import FieldValue from './FieldValue'; import FieldValue from './FieldValue';
@ -14,7 +15,7 @@ import WriteBatch from './WriteBatch';
import INTERNALS from '../../utils/internals'; import INTERNALS from '../../utils/internals';
import type DocumentSnapshot from './DocumentSnapshot'; import type DocumentSnapshot from './DocumentSnapshot';
import type FirebaseApp from '../core/firebase-app'; import type App from '../core/firebase-app';
import type QuerySnapshot from './QuerySnapshot'; import type QuerySnapshot from './QuerySnapshot';
type CollectionSyncEvent = { type CollectionSyncEvent = {
@ -33,64 +34,41 @@ type DocumentSyncEvent = {
path: string, path: string,
} }
class FirestoreInternalModule extends ModuleBase { const NATIVE_EVENTS = [
static _NAMESPACE = 'firestore'; 'firestore_collection_sync_event',
static _NATIVE_MODULE = 'RNFirebaseFirestore'; 'firestore_document_sync_event',
];
_referencePath: Path; export const MODULE_NAME = 'RNFirebaseFirestore';
export const NAMESPACE = 'firestore';
constructor(firebaseApp: FirebaseApp, options: Object = {}) {
super(firebaseApp, options, true);
this._referencePath = new Path([]);
super.addListener(
// sub to internal native event - this fans out to
// public event name: onCollectionSnapshot
super._getAppEventName('firestore_collection_sync_event'),
this._onCollectionSyncEvent.bind(this),
);
super.addListener(
// sub to internal native event - this fans out to
// public event name: onDocumentSnapshot
super._getAppEventName('firestore_document_sync_event'),
this._onDocumentSyncEvent.bind(this),
);
}
/**
* Internal collection sync listener
* @param event
* @private
*/
_onCollectionSyncEvent(event: CollectionSyncEvent) {
if (event.error) {
this.emit(super._getAppEventName(`onQuerySnapshotError:${event.listenerId}`), event.error);
} else {
this.emit(super._getAppEventName(`onQuerySnapshot:${event.listenerId}`), event.querySnapshot);
}
}
/**
* Internal document sync listener
* @param event
* @private
*/
_onDocumentSyncEvent(event: DocumentSyncEvent) {
if (event.error) {
this.emit(super._getAppEventName(`onDocumentSnapshotError:${event.listenerId}`), event.error);
} else {
this.emit(super._getAppEventName(`onDocumentSnapshot:${event.listenerId}`), event.documentSnapshot);
}
}
}
/** /**
* @class Firestore * @class Firestore
*/ */
export default class Firestore extends FirestoreInternalModule { export default class Firestore extends ModuleBase {
constructor(firebaseApp: FirebaseApp, options: Object = {}) { _referencePath: Path;
super(firebaseApp, options);
constructor(app: App) {
super(app, {
events: NATIVE_EVENTS,
moduleName: MODULE_NAME,
namespace: NAMESPACE,
});
this._referencePath = new Path([]);
SharedEventEmitter.addListener(
// sub to internal native event - this fans out to
// public event name: onCollectionSnapshot
getAppEventName(this, 'firestore_collection_sync_event'),
this._onCollectionSyncEvent.bind(this),
);
SharedEventEmitter.addListener(
// sub to internal native event - this fans out to
// public event name: onDocumentSnapshot
getAppEventName(this, 'firestore_document_sync_event'),
this._onDocumentSyncEvent.bind(this),
);
} }
batch(): WriteBatch { batch(): WriteBatch {
@ -134,20 +112,46 @@ export default class Firestore extends FirestoreInternalModule {
} }
setLogLevel(): void { setLogLevel(): void {
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD(Firestore, 'setLogLevel')); throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD('firestore', 'setLogLevel'));
} }
settings(): void { settings(): void {
throw new Error('firebase.firestore().settings() coming soon'); throw new Error('firebase.firestore().settings() coming soon');
} }
/**
* Internal collection sync listener
* @param event
* @private
*/
_onCollectionSyncEvent(event: CollectionSyncEvent) {
if (event.error) {
SharedEventEmitter.emit(getAppEventName(this, `onQuerySnapshotError:${event.listenerId}`), event.error);
} else {
SharedEventEmitter.emit(getAppEventName(this, `onQuerySnapshot:${event.listenerId}`), event.querySnapshot);
}
}
/**
* Internal document sync listener
* @param event
* @private
*/
_onDocumentSyncEvent(event: DocumentSyncEvent) {
if (event.error) {
SharedEventEmitter.emit(getAppEventName(this, `onDocumentSnapshotError:${event.listenerId}`), event.error);
} else {
SharedEventEmitter.emit(getAppEventName(this, `onDocumentSnapshot:${event.listenerId}`), event.documentSnapshot);
}
}
} }
export const statics = { export const statics = {
FieldValue, FieldValue,
GeoPoint, GeoPoint,
enableLogging(bool) { enableLogging(enabled: boolean) {
if (NativeModules[Firestore._NATIVE_MODULE]) { if (NativeModules[MODULE_NAME]) {
NativeModules[Firestore._NATIVE_MODULE].enableLogging(bool); NativeModules[MODULE_NAME].enableLogging(enabled);
} }
}, },
}; };

View File

@ -2,15 +2,24 @@
* @flow * @flow
* Dynamic Links representation wrapper * Dynamic Links representation wrapper
*/ */
import ModuleBase from './../../utils/ModuleBase'; import { SharedEventEmitter } from '../../utils/events';
import { areObjectKeysContainedInOther, isObject, isString } from './../../utils'; import ModuleBase from '../../utils/ModuleBase';
import { areObjectKeysContainedInOther, isObject, isString } from '../../utils';
import { getNativeModule } from '../../utils/native';
import type FirebaseApp from '../core/firebase-app'; import type App from '../core/firebase-app';
const EVENT_TYPE = { const EVENT_TYPE = {
Link: 'dynamic_link_received', Link: 'dynamic_link_received',
}; };
const NATIVE_EVENTS = [
EVENT_TYPE.Link,
];
export const MODULE_NAME = 'RNFirebaseLinks';
export const NAMESPACE = 'links';
function validateParameters(parameters: Object): void { function validateParameters(parameters: Object): void {
const suportedParametersObject = { const suportedParametersObject = {
dynamicLinkDomain: 'string', dynamicLinkDomain: 'string',
@ -62,11 +71,12 @@ function checkForMandatoryParameters(parameters: Object): void {
* @class Links * @class Links
*/ */
export default class Links extends ModuleBase { export default class Links extends ModuleBase {
static _NAMESPACE = 'links'; constructor(app: App) {
static _NATIVE_MODULE = 'RNFirebaseLinks'; super(app, {
events: NATIVE_EVENTS,
constructor(firebaseApp: FirebaseApp, options: Object = {}) { moduleName: MODULE_NAME,
super(firebaseApp, options, true); namespace: NAMESPACE,
});
} }
get EVENT_TYPE(): Object { get EVENT_TYPE(): Object {
@ -78,7 +88,7 @@ export default class Links extends ModuleBase {
* @returns {Promise.<String>} * @returns {Promise.<String>}
*/ */
getInitialLink(): Promise<string> { getInitialLink(): Promise<string> {
return this._native.getInitialLink(); return getNativeModule(this).getInitialLink();
} }
/** /**
@ -87,7 +97,7 @@ export default class Links extends ModuleBase {
* @returns {Function} * @returns {Function}
*/ */
onLink(listener: Function): () => any { onLink(listener: Function): () => any {
const rnListener = this._eventEmitter.addListener(EVENT_TYPE.Link, listener); const rnListener = SharedEventEmitter.addListener(EVENT_TYPE.Link, listener);
return () => rnListener.remove(); return () => rnListener.remove();
} }
@ -100,7 +110,7 @@ export default class Links extends ModuleBase {
try { try {
checkForMandatoryParameters(parameters); checkForMandatoryParameters(parameters);
validateParameters(parameters); validateParameters(parameters);
return this._native.createDynamicLink(parameters); return getNativeModule(this).createDynamicLink(parameters);
} catch (error) { } catch (error) {
return Promise.reject(error); return Promise.reject(error);
} }
@ -115,7 +125,7 @@ export default class Links extends ModuleBase {
try { try {
checkForMandatoryParameters(parameters); checkForMandatoryParameters(parameters);
validateParameters(parameters); validateParameters(parameters);
return this._native.createShortDynamicLink(parameters); return getNativeModule(this).createShortDynamicLink(parameters);
} catch (error) { } catch (error) {
return Promise.reject(error); return Promise.reject(error);
} }

View File

@ -3,10 +3,12 @@
* Messaging representation wrapper * Messaging representation wrapper
*/ */
import { Platform, NativeModules } from 'react-native'; import { Platform, NativeModules } from 'react-native';
import ModuleBase from './../../utils/ModuleBase'; import { SharedEventEmitter } from '../../utils/events';
import ModuleBase from '../../utils/ModuleBase';
import RemoteMessage from './RemoteMessage'; import RemoteMessage from './RemoteMessage';
import { getNativeModule } from '../../utils/native';
import type FirebaseApp from '../core/firebase-app'; import type App from '../core/firebase-app';
const EVENT_TYPE = { const EVENT_TYPE = {
RefreshToken: 'messaging_token_refreshed', RefreshToken: 'messaging_token_refreshed',
@ -31,6 +33,11 @@ const WILL_PRESENT_RESULT = {
None: 'UNNotificationPresentationOptionNone', None: 'UNNotificationPresentationOptionNone',
}; };
const NATIVE_EVENTS = [
EVENT_TYPE.RefreshToken,
EVENT_TYPE.Notification,
];
const FirebaseMessaging = NativeModules.RNFirebaseMessaging; const FirebaseMessaging = NativeModules.RNFirebaseMessaging;
/** /**
@ -73,16 +80,19 @@ function finish(data) {
} }
} }
export const MODULE_NAME = 'RNFirebaseMessaging';
export const NAMESPACE = 'messaging';
/** /**
* @class Messaging * @class Messaging
*/ */
export default class Messaging extends ModuleBase { export default class Messaging extends ModuleBase {
static _NAMESPACE = 'messaging'; constructor(app: App) {
static _NATIVE_MODULE = 'RNFirebaseMessaging'; super(app, {
events: NATIVE_EVENTS,
constructor(firebaseApp: FirebaseApp, options: Object = {}) { moduleName: MODULE_NAME,
super(firebaseApp, options, true); namespace: NAMESPACE,
});
} }
get EVENT_TYPE(): Object { get EVENT_TYPE(): Object {
@ -106,7 +116,7 @@ export default class Messaging extends ModuleBase {
* @returns {*} * @returns {*}
*/ */
getInitialNotification(): Promise<Object> { getInitialNotification(): Promise<Object> {
return this._native.getInitialNotification(); return getNativeModule(this).getInitialNotification();
} }
/** /**
@ -114,7 +124,7 @@ export default class Messaging extends ModuleBase {
* @returns {*|Promise.<String>} * @returns {*|Promise.<String>}
*/ */
getToken(): Promise<string> { getToken(): Promise<string> {
return this._native.getToken(); return getNativeModule(this).getToken();
} }
/** /**
@ -122,7 +132,7 @@ export default class Messaging extends ModuleBase {
* @returns {*|Promise.<*>} * @returns {*|Promise.<*>}
*/ */
deleteInstanceId(): Promise<void> { deleteInstanceId(): Promise<void> {
return this._native.deleteInstanceId(); return getNativeModule(this).deleteInstanceId();
} }
/** /**
@ -134,7 +144,7 @@ export default class Messaging extends ModuleBase {
const _notification = Object.assign({}, notification); const _notification = Object.assign({}, notification);
_notification.id = _notification.id || new Date().getTime().toString(); _notification.id = _notification.id || new Date().getTime().toString();
_notification.local_notification = true; _notification.local_notification = true;
return this._native.createLocalNotification(_notification); return getNativeModule(this).createLocalNotification(_notification);
} }
/** /**
@ -146,7 +156,7 @@ export default class Messaging extends ModuleBase {
const _notification = Object.assign({}, notification); const _notification = Object.assign({}, notification);
if (!notification.id) return Promise.reject(new Error('An id is required to schedule a local notification.')); if (!notification.id) return Promise.reject(new Error('An id is required to schedule a local notification.'));
_notification.local_notification = true; _notification.local_notification = true;
return this._native.scheduleLocalNotification(_notification); return getNativeModule(this).scheduleLocalNotification(_notification);
} }
/** /**
@ -154,7 +164,7 @@ export default class Messaging extends ModuleBase {
* @returns {Promise.<Array>} * @returns {Promise.<Array>}
*/ */
getScheduledLocalNotifications(): Promise<Object[]> { getScheduledLocalNotifications(): Promise<Object[]> {
return this._native.getScheduledLocalNotifications(); return getNativeModule(this).getScheduledLocalNotifications();
} }
/** /**
@ -165,8 +175,8 @@ export default class Messaging extends ModuleBase {
*/ */
cancelLocalNotification(id: string): Promise<void> { cancelLocalNotification(id: string): Promise<void> {
if (!id) return Promise.reject(new Error('Missing notification id')); if (!id) return Promise.reject(new Error('Missing notification id'));
if (id === '*') return this._native.cancelAllLocalNotifications(); if (id === '*') return getNativeModule(this).cancelAllLocalNotifications();
return this._native.cancelLocalNotification(id); return getNativeModule(this).cancelLocalNotification(id);
} }
/** /**
@ -177,8 +187,8 @@ export default class Messaging extends ModuleBase {
*/ */
removeDeliveredNotification(id: string): Promise<void> { removeDeliveredNotification(id: string): Promise<void> {
if (!id) return Promise.reject(new Error('Missing notification id')); if (!id) return Promise.reject(new Error('Missing notification id'));
if (id === '*') return this._native.removeAllDeliveredNotifications(); if (id === '*') return getNativeModule(this).removeAllDeliveredNotifications();
return this._native.removeDeliveredNotification(id); return getNativeModule(this).removeDeliveredNotification(id);
} }
/** /**
@ -187,7 +197,7 @@ export default class Messaging extends ModuleBase {
* @returns {*|Promise.<*>} * @returns {*|Promise.<*>}
*/ */
requestPermissions(): Promise<void> { requestPermissions(): Promise<void> {
return this._native.requestPermissions(); return getNativeModule(this).requestPermissions();
} }
@ -196,7 +206,7 @@ export default class Messaging extends ModuleBase {
* @param n * @param n
*/ */
setBadgeNumber(n: number): void { setBadgeNumber(n: number): void {
this._native.setBadgeNumber(n); getNativeModule(this).setBadgeNumber(n);
} }
/** /**
@ -204,7 +214,7 @@ export default class Messaging extends ModuleBase {
* @returns {Promise.<Number>} * @returns {Promise.<Number>}
*/ */
getBadgeNumber(): Promise<number> { getBadgeNumber(): Promise<number> {
return this._native.getBadgeNumber(); return getNativeModule(this).getBadgeNumber();
} }
/** /**
@ -213,7 +223,7 @@ export default class Messaging extends ModuleBase {
* @returns {*} * @returns {*}
*/ */
onMessage(listener: (Object) => any): () => any { onMessage(listener: (Object) => any): () => any {
const rnListener = this._eventEmitter.addListener( const rnListener = SharedEventEmitter.addListener(
EVENT_TYPE.Notification, EVENT_TYPE.Notification,
async (event) => { async (event) => {
const data = { const data = {
@ -236,7 +246,7 @@ export default class Messaging extends ModuleBase {
* @returns {*} * @returns {*}
*/ */
onTokenRefresh(listener: (string) => any): () => any { onTokenRefresh(listener: (string) => any): () => any {
const rnListener = this._eventEmitter.addListener(EVENT_TYPE.RefreshToken, listener); const rnListener = SharedEventEmitter.addListener(EVENT_TYPE.RefreshToken, listener);
return () => rnListener.remove(); return () => rnListener.remove();
} }
@ -245,7 +255,7 @@ export default class Messaging extends ModuleBase {
* @param topic * @param topic
*/ */
subscribeToTopic(topic: string): void { subscribeToTopic(topic: string): void {
this._native.subscribeToTopic(topic); getNativeModule(this).subscribeToTopic(topic);
} }
/** /**
@ -253,7 +263,7 @@ export default class Messaging extends ModuleBase {
* @param topic * @param topic
*/ */
unsubscribeFromTopic(topic: string): void { unsubscribeFromTopic(topic: string): void {
this._native.unsubscribeFromTopic(topic); getNativeModule(this).unsubscribeFromTopic(topic);
} }
/** /**
@ -265,7 +275,7 @@ export default class Messaging extends ModuleBase {
throw new Error('messaging().send requires an instance of RemoteMessage as the first argument.'); throw new Error('messaging().send requires an instance of RemoteMessage as the first argument.');
} }
return this._native.send(remoteMessage.toJSON()); return getNativeModule(this).send(remoteMessage.toJSON());
} }
} }

View File

@ -2,26 +2,27 @@
* @flow * @flow
* Trace representation wrapper * Trace representation wrapper
*/ */
import { getNativeModule } from '../../utils/native';
import type PerformanceMonitoring from './'; import type PerformanceMonitoring from './';
export default class Trace { export default class Trace {
identifier: string; identifier: string;
perf: PerformanceMonitoring; _perf: PerformanceMonitoring;
constructor(perf: PerformanceMonitoring, identifier: string) { constructor(perf: PerformanceMonitoring, identifier: string) {
this.perf = perf; this._perf = perf;
this.identifier = identifier; this.identifier = identifier;
} }
start(): void { start(): void {
this.perf._native.start(this.identifier); getNativeModule(this._perf).start(this.identifier);
} }
stop(): void { stop(): void {
this.perf._native.stop(this.identifier); getNativeModule(this._perf).stop(this.identifier);
} }
incrementCounter(event: string): void { incrementCounter(event: string): void {
this.perf._native.incrementCounter(this.identifier, event); getNativeModule(this._perf).incrementCounter(this.identifier, event);
} }
} }

View File

@ -4,15 +4,19 @@
*/ */
import Trace from './Trace'; import Trace from './Trace';
import ModuleBase from '../../utils/ModuleBase'; import ModuleBase from '../../utils/ModuleBase';
import { getNativeModule } from '../../utils/native';
import type FirebaseApp from '../core/firebase-app'; import type App from '../core/firebase-app';
export const MODULE_NAME = 'RNFirebasePerformance';
export const NAMESPACE = 'perf';
export default class PerformanceMonitoring extends ModuleBase { export default class PerformanceMonitoring extends ModuleBase {
static _NAMESPACE = 'perf'; constructor(app: App) {
static _NATIVE_MODULE = 'RNFirebasePerformance'; super(app, {
moduleName: MODULE_NAME,
constructor(firebaseApp: FirebaseApp, options: Object = {}) { namespace: NAMESPACE,
super(firebaseApp, options); });
} }
/** /**
@ -21,7 +25,7 @@ export default class PerformanceMonitoring extends ModuleBase {
* @returns {*} * @returns {*}
*/ */
setPerformanceCollectionEnabled(enabled: boolean): void { setPerformanceCollectionEnabled(enabled: boolean): void {
this._native.setPerformanceCollectionEnabled(enabled); getNativeModule(this).setPerformanceCollectionEnabled(enabled);
} }
/** /**

View File

@ -5,31 +5,43 @@
import { NativeModules } from 'react-native'; import { NativeModules } from 'react-native';
import StorageRef from './reference'; import StorageRef from './reference';
import ModuleBase from './../../utils/ModuleBase'; import { getAppEventName, SharedEventEmitter } from '../../utils/events';
import { getLogger } from '../../utils/log';
import ModuleBase from '../../utils/ModuleBase';
import { getNativeModule } from '../../utils/native';
import type FirebaseApp from '../core/firebase-app'; import type App from '../core/firebase-app';
const FirebaseStorage = NativeModules.RNFirebaseStorage; const FirebaseStorage = NativeModules.RNFirebaseStorage;
export default class Storage extends ModuleBase { const NATIVE_EVENTS = [
static _NAMESPACE = 'storage'; 'storage_event',
static _NATIVE_MODULE = 'RNFirebaseStorage'; 'storage_error',
];
export const MODULE_NAME = 'RNFirebaseStorage';
export const NAMESPACE = 'storage';
export default class Storage extends ModuleBase {
/** /**
* *
* @param firebaseApp * @param app
* @param options * @param options
*/ */
constructor(firebaseApp: FirebaseApp, options: Object = {}) { constructor(app: App) {
super(firebaseApp, options, true); super(app, {
events: NATIVE_EVENTS,
moduleName: MODULE_NAME,
namespace: NAMESPACE,
});
this.addListener( SharedEventEmitter.addListener(
this._getAppEventName('storage_event'), getAppEventName(this, 'storage_event'),
this._handleStorageEvent.bind(this), this._handleStorageEvent.bind(this),
); );
this.addListener( SharedEventEmitter.addListener(
this._getAppEventName('storage_error'), getAppEventName(this, 'storage_error'),
this._handleStorageEvent.bind(this), this._handleStorageEvent.bind(this),
); );
} }
@ -50,7 +62,7 @@ export default class Storage extends ModuleBase {
* @param url * @param url
* @returns {StorageReference} * @returns {StorageReference}
*/ */
refFromURL(url: string): Promise<StorageRef> { refFromURL(url: string): StorageRef {
// TODO don't think this is correct? // TODO don't think this is correct?
return new StorageRef(this, `url::${url}`); return new StorageRef(this, `url::${url}`);
} }
@ -61,7 +73,7 @@ export default class Storage extends ModuleBase {
* @param time The new maximum operation retry time in milliseconds. * @param time The new maximum operation retry time in milliseconds.
*/ */
setMaxOperationRetryTime(time: number): void { setMaxOperationRetryTime(time: number): void {
this._native.setMaxOperationRetryTime(time); getNativeModule(this).setMaxOperationRetryTime(time);
} }
/** /**
@ -70,7 +82,7 @@ export default class Storage extends ModuleBase {
* @param time The new maximum upload retry time in milliseconds. * @param time The new maximum upload retry time in milliseconds.
*/ */
setMaxUploadRetryTime(time: number): void { setMaxUploadRetryTime(time: number): void {
this._native.setMaxUploadRetryTime(time); getNativeModule(this).setMaxUploadRetryTime(time);
} }
/** /**
@ -79,38 +91,38 @@ export default class Storage extends ModuleBase {
* @param time The new maximum download retry time in milliseconds. * @param time The new maximum download retry time in milliseconds.
*/ */
setMaxDownloadRetryTime(time: number): void { setMaxDownloadRetryTime(time: number): void {
this._native.setMaxDownloadRetryTime(time); getNativeModule(this).setMaxDownloadRetryTime(time);
} }
/** /**
* INTERNALS * INTERNALS
*/ */
_getSubEventName(path: string, eventName: string) { _getSubEventName(path: string, eventName: string) {
return this._getAppEventName(`${path}-${eventName}`); return getAppEventName(this, `${path}-${eventName}`);
} }
_handleStorageEvent(event: Object) { _handleStorageEvent(event: Object) {
const { path, eventName } = event; const { path, eventName } = event;
const body = event.body || {}; const body = event.body || {};
this.log.debug('_handleStorageEvent: ', path, eventName, body); getLogger(this).debug('_handleStorageEvent: ', path, eventName, body);
this.emit(this._getSubEventName(path, eventName), body); SharedEventEmitter.emit(this._getSubEventName(path, eventName), body);
} }
_handleStorageError(err: Object) { _handleStorageError(err: Object) {
const { path, eventName } = err; const { path, eventName } = err;
const body = err.body || {}; const body = err.body || {};
this.log.debug('_handleStorageError ->', err); getLogger(this).debug('_handleStorageError ->', err);
this.emit(this._getSubEventName(path, eventName), body); SharedEventEmitter.emit(this._getSubEventName(path, eventName), body);
} }
_addListener(path: string, eventName: string, cb: (evt: Object) => Object): void { _addListener(path: string, eventName: string, cb: (evt: Object) => Object): void {
this.on(this._getSubEventName(path, eventName), cb); SharedEventEmitter.addListener(this._getSubEventName(path, eventName), cb);
} }
_removeListener(path: string, eventName: string, origCB: (evt: Object) => Object): void { _removeListener(path: string, eventName: string, origCB: (evt: Object) => Object): void {
this.removeListener(this._getSubEventName(path, eventName), origCB); SharedEventEmitter.removeListener(this._getSubEventName(path, eventName), origCB);
} }
} }

View File

@ -4,6 +4,7 @@
*/ */
import ReferenceBase from '../../utils/ReferenceBase'; import ReferenceBase from '../../utils/ReferenceBase';
import StorageTask, { UPLOAD_TASK, DOWNLOAD_TASK } from './task'; import StorageTask, { UPLOAD_TASK, DOWNLOAD_TASK } from './task';
import { getNativeModule } from '../../utils/native';
import type Storage from './'; import type Storage from './';
@ -14,7 +15,7 @@ export default class StorageReference extends ReferenceBase {
_storage: Storage; _storage: Storage;
constructor(storage: Storage, path: string) { constructor(storage: Storage, path: string) {
super(path, storage); super(path);
this._storage = storage; this._storage = storage;
} }
@ -40,7 +41,7 @@ export default class StorageReference extends ReferenceBase {
* @returns {Promise.<T>|*} * @returns {Promise.<T>|*}
*/ */
delete(): Promise<void> { delete(): Promise<void> {
return this._storage._native.delete(this.path); return getNativeModule(this._storage).delete(this.path);
} }
/** /**
@ -48,7 +49,7 @@ export default class StorageReference extends ReferenceBase {
* @returns {Promise.<T>|*} * @returns {Promise.<T>|*}
*/ */
getDownloadURL(): Promise<string> { getDownloadURL(): Promise<string> {
return this._storage._native.getDownloadURL(this.path); return getNativeModule(this._storage).getDownloadURL(this.path);
} }
/** /**
@ -56,7 +57,7 @@ export default class StorageReference extends ReferenceBase {
* @returns {Promise.<T>|*} * @returns {Promise.<T>|*}
*/ */
getMetadata(): Promise<Object> { getMetadata(): Promise<Object> {
return this._storage._native.getMetadata(this.path); return getNativeModule(this._storage).getMetadata(this.path);
} }
/** /**
@ -65,7 +66,7 @@ export default class StorageReference extends ReferenceBase {
* @returns {Promise.<T>|*} * @returns {Promise.<T>|*}
*/ */
updateMetadata(metadata: Object = {}): Promise<Object> { updateMetadata(metadata: Object = {}): Promise<Object> {
return this._storage._native.updateMetadata(this.path, metadata); return getNativeModule(this._storage).updateMetadata(this.path, metadata);
} }
/** /**
@ -74,7 +75,7 @@ export default class StorageReference extends ReferenceBase {
* @return {Promise} * @return {Promise}
*/ */
downloadFile(filePath: string): Promise<Object> { downloadFile(filePath: string): Promise<Object> {
return new StorageTask(DOWNLOAD_TASK, this._storage._native.downloadFile(this.path, filePath), this); return new StorageTask(DOWNLOAD_TASK, getNativeModule(this._storage).downloadFile(this.path, filePath), this);
} }
/** /**
@ -93,6 +94,6 @@ export default class StorageReference extends ReferenceBase {
*/ */
putFile(filePath: Object, metadata: Object = {}): Promise<Object> { putFile(filePath: Object, metadata: Object = {}): Promise<Object> {
const _filePath = filePath.replace('file://', ''); const _filePath = filePath.replace('file://', '');
return new StorageTask(UPLOAD_TASK, this._module._native.putFile(this.path, _filePath, metadata), this); return new StorageTask(UPLOAD_TASK, getNativeModule(this._storage).putFile(this.path, _filePath, metadata), this);
} }
} }

View File

@ -2,7 +2,6 @@
import { NativeModules } from 'react-native'; import { NativeModules } from 'react-native';
// import { version as ReactVersion } from 'react'; // import { version as ReactVersion } from 'react';
// import ReactNativeVersion from 'react-native/Libraries/Core/ReactNativeVersion'; // import ReactNativeVersion from 'react-native/Libraries/Core/ReactNativeVersion';
import INTERNALS from '../../utils/internals'; import INTERNALS from '../../utils/internals';
import { isIOS } from '../../utils'; import { isIOS } from '../../utils';
import ModuleBase from '../../utils/ModuleBase'; import ModuleBase from '../../utils/ModuleBase';
@ -18,34 +17,31 @@ type GoogleApiAvailabilityType = {
error?: string error?: string
} }
export default class RNFirebaseUtils extends ModuleBase { export const MODULE_NAME = 'RNFirebaseUtils';
static _NAMESPACE = 'utils'; export const NAMESPACE = 'utils';
static _NATIVE_DISABLED = true;
static _NATIVE_MODULE = 'RNFirebaseUtils';
export default class RNFirebaseUtils extends ModuleBase {
/** /**
* *
*/ */
checkPlayServicesAvailability() { checkPlayServicesAvailability() {
if (isIOS) return null; if (isIOS) return;
const code = this.playServicesAvailability.code; const { status } = this.playServicesAvailability;
if (!this.playServicesAvailability.isAvailable) { if (!this.playServicesAvailability.isAvailable) {
if (INTERNALS.OPTIONS.promptOnMissingPlayServices && this.playServicesAvailability.isUserResolvableError) { if (INTERNALS.OPTIONS.promptOnMissingPlayServices && this.playServicesAvailability.isUserResolvableError) {
this.promptForPlayServices(); this.promptForPlayServices();
} else { } else {
const error = INTERNALS.STRINGS.ERROR_PLAY_SERVICES(code); const error = INTERNALS.STRINGS.ERROR_PLAY_SERVICES(status);
if (INTERNALS.OPTIONS.errorOnMissingPlayServices) { if (INTERNALS.OPTIONS.errorOnMissingPlayServices) {
if (code === 2) console.warn(error); // only warn if it exists but may need an update if (status === 2) console.warn(error); // only warn if it exists but may need an update
else throw new Error(error); else throw new Error(error);
} else { } else {
console.warn(error); console.warn(error);
} }
} }
} }
return null;
} }
promptForPlayServices() { promptForPlayServices() {
@ -63,41 +59,13 @@ export default class RNFirebaseUtils extends ModuleBase {
return FirebaseCoreModule.makePlayServicesAvailable(); return FirebaseCoreModule.makePlayServicesAvailable();
} }
get sharedEventEmitter(): Object {
return INTERNALS.SharedEventEmitter;
}
/** /**
* Set the global logging level for all logs. * Set the global logging level for all logs.
* *
* @param booleanOrDebugString * @param logLevel
*/ */
set logLevel(booleanOrDebugString) { set logLevel(logLevel: string) {
INTERNALS.OPTIONS.logLevel = booleanOrDebugString; INTERNALS.OPTIONS.logLevel = logLevel;
}
/**
* Returns an array of all current database registrations id strings
*/
get databaseRegistrations(): Array<string> {
return Object.keys(INTERNALS.SyncTree._reverseLookup);
}
/**
* Call with a registration id string to get the details off this reg
*/
get getDatabaseRegistrationDetails(): Function {
return INTERNALS.SyncTree.getRegistration.bind(INTERNALS.SyncTree);
}
/**
* Accepts an array or a single string of registration ids.
* This will remove the refs on both the js and native sides and their listeners.
* @return {function(this:T)}
*/
get removeDatabaseRegistration(): Function {
return INTERNALS.SyncTree.removeListenersForRegistrations.bind(INTERNALS.SyncTree);
} }
/** /**
@ -130,7 +98,6 @@ export default class RNFirebaseUtils extends ModuleBase {
export const statics = { export const statics = {
DEFAULT_APP_NAME: INTERNALS.STRINGS.DEFAULT_APP_NAME,
// VERSIONS: { // VERSIONS: {
// react: ReactVersion, // react: ReactVersion,
// 'react-native': Object.values(ReactNativeVersion.version).slice(0, 3).join('.'), // 'react-native': Object.values(ReactNativeVersion.version).slice(0, 3).join('.'),

View File

@ -40,7 +40,18 @@ export type FirebaseError = {
export type FirebaseModule = $Subtype<ModuleBase>; export type FirebaseModule = $Subtype<ModuleBase>;
export type FirebaseModuleName = 'admob' | 'analytics' | 'auth' | 'config' | 'crash' export type FirebaseModuleConfig = {
events?: string[],
moduleName: FirebaseModuleName,
namespace: FirebaseNamespace,
}
export type FirebaseModuleName = 'RNFirebaseAdmob' | 'RNFirebaseAnalytics' | 'RNFirebaseAuth'
| 'RNFirebaseRemoteConfig' | 'RNFirebaseCrash' | 'RNFirebaseCrashlytics' | 'RNFirebaseDatabase'
| 'RNFirebaseFirestore' | 'RNFirebaseLinks' | 'RNFirebaseMessaging' | 'RNFirebasePerformance'
| 'RNFirebaseStorage' | 'RNFirebaseUtils';
export type FirebaseNamespace = 'admob' | 'analytics' | 'auth' | 'config' | 'crash'
| 'crashlytics' | 'database' | 'firestore' | 'links' | 'messaging' | 'perf' | 'storage' | 'crashlytics' | 'database' | 'firestore' | 'links' | 'messaging' | 'perf' | 'storage'
| 'utils'; | 'utils';

View File

@ -1,174 +1,42 @@
/** /**
* @flow * @flow
*/ */
import { NativeModules } from 'react-native'; import { initialiseLogger } from './log';
import { initialiseNativeModule } from './native';
import Log from './log'; import type App from '../modules/core/firebase-app';
import INTERNALS from './internals'; import type { FirebaseModuleConfig, FirebaseNamespace } from '../types';
import FirebaseCore from '../modules/core/firebase';
import { nativeWithApp } from '../utils';
import type FirebaseApp from '../modules/core/firebase-app';
import type { FirebaseModuleName } from '../types';
const logs = {};
// Firebase Native SDKs that support multiple app instances
const MULTI_APP_MODULES = [
'auth',
'database',
'firestore',
'storage',
];
const NATIVE_MODULE_EVENTS = {
Storage: [
'storage_event',
'storage_error',
],
Auth: [
'auth_state_changed',
'phone_auth_state_changed',
],
Database: [
'database_transaction_event',
// 'database_server_offset', // TODO
],
Firestore: [
'firestore_collection_sync_event',
'firestore_document_sync_event',
],
};
const DEFAULTS = {
Database: {
persistence: false,
},
};
export default class ModuleBase { export default class ModuleBase {
_native: Object; _app: App;
_module: string; namespace: FirebaseNamespace;
_options: Object;
_appName: string;
_namespace: string;
_firebaseApp: FirebaseApp;
_eventEmitter: Object;
static _NAMESPACE: FirebaseModuleName;
static _NATIVE_MODULE: string;
/** /**
* *
* @param firebaseApp * @param app
* @param options * @param config
* @param withEventEmitter
*/ */
constructor(firebaseApp: FirebaseApp, options: Object, withEventEmitter: boolean = false) { constructor(app: App, config: FirebaseModuleConfig) {
this._module = this.constructor._NATIVE_MODULE.replace('RNFirebase', ''); if (!config.moduleName) {
this._firebaseApp = firebaseApp; throw new Error('Missing module name');
this._appName = firebaseApp._name; }
this._namespace = `${this._appName}:${this._module}`; if (!config.namespace) {
this._options = Object.assign({}, DEFAULTS[this._module] || {}, options); throw new Error('Missing namespace');
}
const { moduleName } = config;
this._app = app;
this.namespace = config.namespace;
// check if native module exists as all native // check if native module exists as all native
// modules are now optionally part of build initialiseNativeModule(this, config);
const nativeModule = NativeModules[this.constructor._NATIVE_MODULE]; initialiseLogger(this, `${app.name}:${moduleName.replace('RNFirebase', '')}`);
if (!nativeModule && !this.constructor._NATIVE_DISABLED) {
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_MODULE(this.constructor._NAMESPACE, this.constructor._NATIVE_MODULE));
}
// used by the modules that extend ModuleBase
// to access their native module counterpart
if (!MULTI_APP_MODULES.includes(this._module.toLowerCase())) {
this._native = nativeModule;
} else {
this._native = nativeWithApp(this._appName, nativeModule);
}
if (withEventEmitter) {
this._setupEventEmitter(nativeModule, this._module);
}
} }
/** /**
* * Returns the App instance for current module
* @param nativeModule
* @param moduleName
* @private
*/
_setupEventEmitter(nativeModule: Object, moduleName: string) {
this._eventEmitter = FirebaseCore._getOrSetNativeEmitter(`${this._appName}-${this._module}`, nativeModule);
const events = NATIVE_MODULE_EVENTS[moduleName];
if (events && events.length) {
for (let i = 0, len = events.length; i < len; i++) {
FirebaseCore._subscribeForDistribution(events[i], this._eventEmitter);
}
}
}
/**
*
* @param eventName
* @return {string}
* @private
*/
_getAppEventName(eventName: string) {
return `${this._appName}-${eventName}`;
}
/**
* Returns the FirebaseApp instance for current module
* @return {*} * @return {*}
*/ */
get app(): FirebaseApp { get app(): App {
return this._firebaseApp; return this._app;
}
get log(): Log {
if (logs[this._namespace]) return logs[this._namespace];
return logs[this._namespace] = Log.createLogger(`🔥 ${this._namespace.toUpperCase()}`);
}
/*
* Proxy functions to shared event emitter instance
* https://github.com/facebook/react-native/blob/master/Libraries/EventEmitter/EventEmitter.js
*/
get sharedEventEmitter(): Object {
return INTERNALS.SharedEventEmitter;
}
get addListener(): Function {
return INTERNALS.SharedEventEmitter.addListener.bind(INTERNALS.SharedEventEmitter);
}
get once(): Function {
return INTERNALS.SharedEventEmitter.once.bind(INTERNALS.SharedEventEmitter);
}
get on(): Function {
return INTERNALS.SharedEventEmitter.addListener.bind(INTERNALS.SharedEventEmitter);
}
get emit(): Function {
return INTERNALS.SharedEventEmitter.emit.bind(INTERNALS.SharedEventEmitter);
}
get listeners(): Function {
return INTERNALS.SharedEventEmitter.listeners.bind(INTERNALS.SharedEventEmitter);
}
hasListeners(eventType: string): Boolean {
const subscriptions = INTERNALS.SharedEventEmitter._subscriber.getSubscriptionsForType(eventType);
return subscriptions && subscriptions.length;
}
get removeListener(): Function {
return INTERNALS.SharedEventEmitter.removeListener.bind(INTERNALS.SharedEventEmitter);
}
get removeAllListeners(): Function {
return INTERNALS.SharedEventEmitter.removeAllListeners.bind(INTERNALS.SharedEventEmitter);
} }
} }

View File

@ -1,17 +1,10 @@
/** /**
* @flow * @flow
*/ */
import Log from './log';
import type Database from '../modules/database';
import type Storage from '../modules/storage';
export default class ReferenceBase { export default class ReferenceBase {
_module: Database | Storage;
path: string; path: string;
constructor(path: string, module: Database | Storage) { constructor(path: string) {
this._module = module;
this.path = path || '/'; this.path = path || '/';
} }
@ -24,8 +17,4 @@ export default class ReferenceBase {
get key(): string | null { get key(): string | null {
return this.path === '/' ? null : this.path.substring(this.path.lastIndexOf('/') + 1); return this.path === '/' ? null : this.path.substring(this.path.lastIndexOf('/') + 1);
} }
get log(): Log {
return this._module.log;
}
} }

View File

@ -1,20 +1,22 @@
/** /**
* @flow * @flow
*/ */
import { NativeEventEmitter } from 'react-native'; import { NativeEventEmitter, NativeModules } from 'react-native';
import INTERNALS from './internals'; import { SharedEventEmitter } from './events';
import DatabaseSnapshot from '../modules/database/snapshot'; import DatabaseSnapshot from '../modules/database/snapshot';
import DatabaseReference from '../modules/database/reference'; import DatabaseReference from '../modules/database/reference';
import { isString, nativeToJSError } from '../utils'; import { isString, nativeToJSError } from '../utils';
type Listener = (DatabaseSnapshot) => any;
type Registration = { type Registration = {
key: string, key: string,
path: string, path: string,
once?: boolean, once?: boolean,
appName: string, appName: string,
eventType: string, eventType: string,
listener: Function, listener: Listener,
eventRegistrationKey: string, eventRegistrationKey: string,
ref: DatabaseReference, ref: DatabaseReference,
} }
@ -23,21 +25,21 @@ type Registration = {
* Internally used to manage firebase database realtime event * Internally used to manage firebase database realtime event
* subscriptions and keep the listeners in sync in js vs native. * subscriptions and keep the listeners in sync in js vs native.
*/ */
export default class SyncTree { class SyncTree {
_databaseNative: Object;
_nativeEmitter: NativeEventEmitter; _nativeEmitter: NativeEventEmitter;
_reverseLookup: { [string]: Registration }; _reverseLookup: { [string]: Registration };
_tree: { [string]: { [string]: Array }}; _tree: { [string]: { [string]: { [string]: Listener }}};
constructor(databaseNative: Object) { constructor() {
this._tree = {}; this._tree = {};
this._reverseLookup = {}; this._reverseLookup = {};
this._databaseNative = databaseNative; if (NativeModules.RNFirebaseDatabase) {
this._nativeEmitter = new NativeEventEmitter(databaseNative); this._nativeEmitter = new NativeEventEmitter(NativeModules.RNFirebaseDatabase);
this._nativeEmitter.addListener( this._nativeEmitter.addListener(
'database_sync_event', 'database_sync_event',
this._handleSyncEvent.bind(this), this._handleSyncEvent.bind(this),
); );
}
} }
/** /**
@ -71,13 +73,13 @@ export default class SyncTree {
// notify native that the registration // notify native that the registration
// no longer exists so it can remove // no longer exists so it can remove
// the native listeners // the native listeners
return this._databaseNative.off(key, eventRegistrationKey); return NativeModules.RNFirebaseDatabase.off(key, eventRegistrationKey);
} }
const { snapshot, previousChildName } = event.data; const { snapshot, previousChildName } = event.data;
// forward on to users .on(successCallback <-- listener // forward on to users .on(successCallback <-- listener
return INTERNALS.SharedEventEmitter.emit( return SharedEventEmitter.emit(
eventRegistrationKey, eventRegistrationKey,
new DatabaseSnapshot(registration.ref, snapshot), new DatabaseSnapshot(registration.ref, snapshot),
previousChildName, previousChildName,
@ -104,7 +106,7 @@ export default class SyncTree {
const error = nativeToJSError(code, message, { ref: registration.ref }); const error = nativeToJSError(code, message, { ref: registration.ref });
// forward on to users .on(successCallback, cancellationCallback <-- listener // forward on to users .on(successCallback, cancellationCallback <-- listener
INTERNALS.SharedEventEmitter.emit(registrationCancellationKey, error); SharedEventEmitter.emit(registrationCancellationKey, error);
// remove the paired event registration - if we received a cancellation // remove the paired event registration - if we received a cancellation
// event then it's guaranteed that they'll be no further value events // event then it's guaranteed that they'll be no further value events
@ -128,17 +130,17 @@ export default class SyncTree {
* @param registrations * @param registrations
* @return {number} * @return {number}
*/ */
removeListenersForRegistrations(registrations: string | string[]) { removeListenersForRegistrations(registrations: string | string[]): number {
if (isString(registrations)) { if (isString(registrations)) {
this.removeRegistration(registrations); this.removeRegistration(registrations);
INTERNALS.SharedEventEmitter.removeAllListeners(registrations); SharedEventEmitter.removeAllListeners(registrations);
return 1; return 1;
} }
if (!Array.isArray(registrations)) return 0; if (!Array.isArray(registrations)) return 0;
for (let i = 0, len = registrations.length; i < len; i++) { for (let i = 0, len = registrations.length; i < len; i++) {
this.removeRegistration(registrations[i]); this.removeRegistration(registrations[i]);
INTERNALS.SharedEventEmitter.removeAllListeners(registrations[i]); SharedEventEmitter.removeAllListeners(registrations[i]);
} }
return registrations.length; return registrations.length;
@ -151,13 +153,13 @@ export default class SyncTree {
* @param registrations * @param registrations
* @return {Array} array of registrations removed * @return {Array} array of registrations removed
*/ */
removeListenerRegistrations(listener, registrations: string[]) { removeListenerRegistrations(listener: () => any, registrations: string[]) {
if (!Array.isArray(registrations)) return []; if (!Array.isArray(registrations)) return [];
const removed = []; const removed = [];
for (let i = 0, len = registrations.length; i < len; i++) { for (let i = 0, len = registrations.length; i < len; i++) {
const registration = registrations[i]; const registration = registrations[i];
const subscriptions = INTERNALS.SharedEventEmitter._subscriber.getSubscriptionsForType(registration); const subscriptions = SharedEventEmitter._subscriber.getSubscriptionsForType(registration);
if (subscriptions) { if (subscriptions) {
for (let j = 0, l = subscriptions.length; j < l; j++) { for (let j = 0, l = subscriptions.length; j < l; j++) {
const subscription = subscriptions[j]; const subscription = subscriptions[j];
@ -181,7 +183,7 @@ export default class SyncTree {
* @param path * @param path
* @return {Array} * @return {Array}
*/ */
getRegistrationsByPath(path: string): Array { getRegistrationsByPath(path: string): string[] {
const out = []; const out = [];
const eventKeys = Object.keys(this._tree[path] || {}); const eventKeys = Object.keys(this._tree[path] || {});
@ -199,7 +201,7 @@ export default class SyncTree {
* @param eventType * @param eventType
* @return {Array} * @return {Array}
*/ */
getRegistrationsByPathEvent(path: string, eventType: string): Array { getRegistrationsByPathEvent(path: string, eventType: string): string[] {
if (!this._tree[path]) return []; if (!this._tree[path]) return [];
if (!this._tree[path][eventType]) return []; if (!this._tree[path][eventType]) return [];
@ -214,9 +216,9 @@ export default class SyncTree {
* @param listener * @param listener
* @return {Array} * @return {Array}
*/ */
getOneByPathEventListener(path: string, eventType: string, listener: Function): Array { getOneByPathEventListener(path: string, eventType: string, listener: Function): ?string {
if (!this._tree[path]) return []; if (!this._tree[path]) return null;
if (!this._tree[path][eventType]) return []; if (!this._tree[path][eventType]) return null;
const registrationsForPathEvent = Object.entries(this._tree[path][eventType]); const registrationsForPathEvent = Object.entries(this._tree[path][eventType]);
@ -236,27 +238,28 @@ export default class SyncTree {
* @param listener * @param listener
* @return {String} * @return {String}
*/ */
addRegistration(parameters: Registration, listener: Function): string { addRegistration(registration: Registration): string {
const { const {
path,
eventType,
eventRegistrationKey, eventRegistrationKey,
eventType,
listener,
once, once,
} = parameters; path,
} = registration;
if (!this._tree[path]) this._tree[path] = {}; if (!this._tree[path]) this._tree[path] = {};
if (!this._tree[path][eventType]) this._tree[path][eventType] = {}; if (!this._tree[path][eventType]) this._tree[path][eventType] = {};
this._tree[path][eventType][eventRegistrationKey] = listener; this._tree[path][eventType][eventRegistrationKey] = listener;
this._reverseLookup[eventRegistrationKey] = Object.assign({ listener }, parameters); this._reverseLookup[eventRegistrationKey] = registration;
if (once) { if (once) {
INTERNALS.SharedEventEmitter.once( SharedEventEmitter.once(
eventRegistrationKey, eventRegistrationKey,
this._onOnceRemoveRegistration(eventRegistrationKey, listener), this._onOnceRemoveRegistration(eventRegistrationKey, listener),
); );
} else { } else {
INTERNALS.SharedEventEmitter.addListener(eventRegistrationKey, listener); SharedEventEmitter.addListener(eventRegistrationKey, listener);
} }
return eventRegistrationKey; return eventRegistrationKey;
@ -287,7 +290,7 @@ export default class SyncTree {
// automatically unsubscribed on native when the first event is sent // automatically unsubscribed on native when the first event is sent
const registrationObj = this._reverseLookup[registration]; const registrationObj = this._reverseLookup[registration];
if (registrationObj && !once) { if (registrationObj && !once) {
this._databaseNative.off(registrationObj.key, registration); NativeModules.RNFirebaseDatabase.off(registrationObj.key, registration);
} }
delete this._tree[path][eventType][registration]; delete this._tree[path][eventType][registration];
@ -305,9 +308,11 @@ export default class SyncTree {
* @private * @private
*/ */
_onOnceRemoveRegistration(registration, listener) { _onOnceRemoveRegistration(registration, listener) {
return (...args) => { return (...args: any[]) => {
this.removeRegistration(registration); this.removeRegistration(registration);
listener(...args); listener(...args);
}; };
} }
} }
export default new SyncTree();

173
lib/utils/apps.js Normal file
View File

@ -0,0 +1,173 @@
/**
* @flow
*/
import { NativeModules } from 'react-native';
import App from '../modules/core/firebase-app';
import INTERNALS from './internals';
import { isAndroid, isObject, isString } from './';
import type {
FirebaseModule,
FirebaseModuleAndStatics,
FirebaseModuleName,
FirebaseNamespace,
FirebaseOptions,
FirebaseStatics,
} from '../types';
const FirebaseCoreModule = NativeModules.RNFirebase;
const APPS: { [string]: App } = {};
const APP_MODULES: { [App]: { [string]: FirebaseModule }} = {};
const DEFAULT_APP_NAME = '[DEFAULT]';
export default {
DEFAULT_APP_NAME,
app(name?: string): App {
const _name = name ? name.toUpperCase() : DEFAULT_APP_NAME;
const app = APPS[_name];
if (!app) throw new Error(INTERNALS.STRINGS.ERROR_APP_NOT_INIT(_name));
return app;
},
apps(): Array<App> {
// $FlowBug: Object.values always returns mixed type: https://github.com/facebook/flow/issues/2221
return Object.values(APPS);
},
/**
*
* @param statics
* @param InstanceClass
* @return {function()}
* @private
*/
appModule<M: FirebaseModule>(app: App, namespace: FirebaseNamespace, InstanceClass: Class<M>): () => FirebaseModule {
return (): M => {
if (!APP_MODULES[app]) {
APP_MODULES[app] = {};
}
if (isAndroid && namespace !== 'utils' && !INTERNALS.FLAGS.checkedPlayServices) {
INTERNALS.FLAGS.checkedPlayServices = true;
this.utils().checkPlayServicesAvailability();
}
if (!APP_MODULES[app][namespace]) {
APP_MODULES[app][namespace] = new InstanceClass(app, app.options);
}
return APP_MODULES[app][namespace];
};
},
deleteApp(name: string): Promise<boolean> {
const app = APPS[name];
if (!app) return Promise.resolve(true);
// https://firebase.google.com/docs/reference/js/firebase.app.App#delete
return app.delete().then(() => {
delete APPS[name];
return true;
});
},
/**
* Web SDK initializeApp
*
* @param options
* @param name
* @return {*}
*/
initializeApp(options: FirebaseOptions, name: string): App {
if (name && !isString(name)) {
throw new Error(INTERNALS.STRINGS.ERROR_INIT_STRING_NAME);
}
const _name = (name || DEFAULT_APP_NAME).toUpperCase();
// return an existing app if found
// todo in v4 remove deprecation and throw an error
if (APPS[_name]) {
console.warn(INTERNALS.STRINGS.WARN_INITIALIZE_DEPRECATION);
return APPS[_name];
}
// only validate if app doesn't already exist
// to allow apps already initialized natively
// to still go through init without erroring (backwards compatibility)
if (!isObject(options)) {
throw new Error(INTERNALS.STRINGS.ERROR_INIT_OBJECT);
}
if (!options.apiKey) {
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_OPT('apiKey'));
}
if (!options.appId) {
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_OPT('appId'));
}
if (!options.databaseURL) {
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_OPT('databaseURL'));
}
if (!options.messagingSenderId) {
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_OPT('messagingSenderId'));
}
if (!options.projectId) {
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_OPT('projectId'));
}
if (!options.storageBucket) {
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_OPT('storageBucket'));
}
APPS[_name] = new App(_name, options);
return APPS[_name];
},
/**
* Bootstraps all native app instances that were discovered on boot
*/
initializeNativeApps() {
for (let i = 0, len = FirebaseCoreModule.apps.length; i < len; i++) {
const app = FirebaseCoreModule.apps[i];
const options = Object.assign({}, app);
delete options.name;
APPS[app.name] = new App(app.name, options, true);
}
},
/**
*
* @param statics
* @param InstanceClass
* @return {function(App=)}
*/
moduleAndStatics<M: FirebaseModule, S: FirebaseStatics>(namespace: FirebaseNamespace, statics: S, moduleName: FirebaseModuleName): FirebaseModuleAndStatics<M, S> {
const getModule = (app?: App): FirebaseModule => {
let _app = app;
// throw an error if it's not a valid app instance
if (_app && !(_app instanceof App)) throw new Error(INTERNALS.STRINGS.ERROR_NOT_APP(namespace));
// default to the 'DEFAULT' app if no arg provided - will throw an error
// if default app not initialized
else if (!_app) _app = this.app(DEFAULT_APP_NAME);
if (namespace === 'crashlytics') {
return _app.fabric[namespace]();
}
// $FlowBug: Flow doesn't support indexable signatures on classes: https://github.com/facebook/flow/issues/1323
const module = _app[namespace];
return module();
};
return Object.assign(getModule, statics, {
nativeModuleExists: !!NativeModules[moduleName],
});
},
};

62
lib/utils/events.js Normal file
View File

@ -0,0 +1,62 @@
/**
* @flow
*/
import { NativeEventEmitter, NativeModules } from 'react-native';
import EventEmitter from './emitter/EventEmitter';
import type ModuleBase from './ModuleBase';
import type { FirebaseModuleConfig, FirebaseModuleName } from '../types';
const NATIVE_EMITTERS: { [string]: NativeEventEmitter } = {};
const NATIVE_SUBSCRIPTIONS: { [string]: boolean } = {};
export const SharedEventEmitter = new EventEmitter();
export const getAppEventName = (module: ModuleBase, eventName: string): string => {
return `${module.app.name}-${eventName}`;
};
const getNativeEmitter = (moduleName: FirebaseModuleName, module: ModuleBase): NativeEventEmitter => {
const name = `${module.app.name}-${moduleName}`;
const nativeModule = NativeModules[moduleName];
if (!NATIVE_EMITTERS[name]) {
NATIVE_EMITTERS[name] = new NativeEventEmitter(nativeModule);
}
return NATIVE_EMITTERS[name];
};
/**
* Subscribe to a native event for js side distribution by appName
* React Native events are hard set at compile - cant do dynamic event names
* so we use a single event send it to js and js then internally can prefix it
* and distribute dynamically.
*
* @param module
* @param eventName
* @private
*/
const subscribeToNativeModuleEvents = (moduleName: FirebaseModuleName, module: ModuleBase, eventName: string): void => {
if (!NATIVE_SUBSCRIPTIONS[eventName]) {
const nativeEmitter = getNativeEmitter(moduleName, module);
nativeEmitter.addListener(eventName, (event) => {
if (event.appName) {
// native event has an appName property - auto prefix and internally emit
SharedEventEmitter.emit(`${event.appName}-${eventName}`, event);
} else {
// standard event - no need to prefix
SharedEventEmitter.emit(eventName, event);
}
});
NATIVE_SUBSCRIPTIONS[eventName] = true;
}
};
export const initialiseNativeModuleEventEmitter = (module: ModuleBase, config: FirebaseModuleConfig): void => {
const { events, moduleName } = config;
if (events && events.length) {
for (let i = 0, len = events.length; i < len; i++) {
subscribeToNativeModuleEvents(moduleName, module, events[i]);
}
}
};

View File

@ -340,25 +340,6 @@ export function nativeToJSError(code: string, message: string, additionalProps?:
return error; return error;
} }
/**
* Prepends appName arg to all native method calls
* @param appName
* @param NativeModule
*/
export function nativeWithApp(appName: string, NativeModule: Object) {
const native = {};
const methods = Object.keys(NativeModule);
for (let i = 0, len = methods.length; i < len; i++) {
const method = methods[i];
native[method] = (...args) => {
return NativeModule[method](...[appName, ...args]);
};
}
return native;
}
/** /**
* *
* @param object * @param object
@ -390,21 +371,21 @@ export function objectToUniqueId(object: Object): string {
* @param optionalCallback * @param optionalCallback
* @return {Promise} * @return {Promise}
*/ */
export function promiseOrCallback(promise: Promise<*>, optionalCallback?: Function) { export function promiseOrCallback(promise: Promise<*>, optionalCallback?: Function): Promise<*> {
if (!isFunction(optionalCallback)) return promise; if (!isFunction(optionalCallback)) return promise;
return promise.then((result) => { return promise.then((result) => {
// some of firebase internal tests & methods only check/return one arg // some of firebase internal tests & methods only check/return one arg
// see https://github.com/firebase/firebase-js-sdk/blob/master/src/utils/promise.ts#L62 // see https://github.com/firebase/firebase-js-sdk/blob/master/src/utils/promise.ts#L62
if (optionalCallback.length === 1) { if (optionalCallback && optionalCallback.length === 1) {
optionalCallback(null); optionalCallback(null);
} else { } else if (optionalCallback) {
optionalCallback(null, result); optionalCallback(null, result);
} }
return Promise.resolve(result); return Promise.resolve(result);
}).catch((error) => { }).catch((error) => {
optionalCallback(error); if (optionalCallback) optionalCallback(error);
return Promise.reject(error); return Promise.reject(error);
}); });
} }

View File

@ -1,15 +1,7 @@
/** /**
* @flow * @flow
*/ */
import { Platform, NativeModules } from 'react-native'; import { Platform } from 'react-native';
import EventEmitter from './emitter/EventEmitter';
import ModuleBase from './ModuleBase';
import SyncTree from './SyncTree';
import type FirebaseApp from '../modules/core/firebase-app';
const DEFAULT_APP_NAME = Platform.OS === 'ios' ? '__FIRAPP_DEFAULT' : '[DEFAULT]';
const NAMESPACE_PODS = { const NAMESPACE_PODS = {
admob: 'Firebase/AdMob', admob: 'Firebase/AdMob',
@ -29,34 +21,38 @@ const GRADLE_DEPS = {
}; };
const PLAY_SERVICES_CODES = { const PLAY_SERVICES_CODES = {
// $FlowBug: Doesn't like numerical object keys: https://github.com/facebook/flow/issues/380
1: { 1: {
code: 'SERVICE_MISSING', code: 'SERVICE_MISSING',
message: 'Google Play services is missing on this device.', message: 'Google Play services is missing on this device.',
}, },
// $FlowBug: Doesn't like numerical object keys: https://github.com/facebook/flow/issues/380
2: { 2: {
code: 'SERVICE_VERSION_UPDATE_REQUIRED', code: 'SERVICE_VERSION_UPDATE_REQUIRED',
message: 'The installed version of Google Play services on this device is out of date.', message: 'The installed version of Google Play services on this device is out of date.',
}, },
// $FlowBug: Doesn't like numerical object keys: https://github.com/facebook/flow/issues/380
3: { 3: {
code: 'SERVICE_DISABLED', code: 'SERVICE_DISABLED',
message: 'The installed version of Google Play services has been disabled on this device.', message: 'The installed version of Google Play services has been disabled on this device.',
}, },
// $FlowBug: Doesn't like numerical object keys: https://github.com/facebook/flow/issues/380
9: { 9: {
code: 'SERVICE_INVALID', code: 'SERVICE_INVALID',
message: 'The version of the Google Play services installed on this device is not authentic.', message: 'The version of the Google Play services installed on this device is not authentic.',
}, },
// $FlowBug: Doesn't like numerical object keys: https://github.com/facebook/flow/issues/380
18: { 18: {
code: 'SERVICE_UPDATING', code: 'SERVICE_UPDATING',
message: 'Google Play services is currently being updated on this device.', message: 'Google Play services is currently being updated on this device.',
}, },
// $FlowBug: Doesn't like numerical object keys: https://github.com/facebook/flow/issues/380
19: { 19: {
code: 'SERVICE_MISSING_PERMISSION', code: 'SERVICE_MISSING_PERMISSION',
message: 'Google Play service doesn\'t have one or more required permissions.', message: 'Google Play service doesn\'t have one or more required permissions.',
}, },
}; };
const APPS: { [string]: FirebaseApp } = {};
export default { export default {
// default options // default options
OPTIONS: { OPTIONS: {
@ -69,9 +65,6 @@ export default {
checkedPlayServices: false, checkedPlayServices: false,
}, },
// track all initialized firebase apps
APPS,
STRINGS: { STRINGS: {
WARN_INITIALIZE_DEPRECATION: 'Deprecation: Calling \'initializeApp()\' for apps that are already initialised natively ' + WARN_INITIALIZE_DEPRECATION: 'Deprecation: Calling \'initializeApp()\' for apps that are already initialised natively ' +
'is unnecessary, use \'firebase.app()\' instead to access the already initialized default app instance.', 'is unnecessary, use \'firebase.app()\' instead to access the already initialized default app instance.',
@ -174,7 +167,7 @@ export default {
* @return {string} * @return {string}
*/ */
ERROR_NOT_APP(namespace: string) { ERROR_NOT_APP(namespace: string) {
return `Invalid FirebaseApp instance passed to firebase.${namespace}(app <--).`; return `Invalid App instance passed to firebase.${namespace}(app <--).`;
}, },
/** /**
@ -194,8 +187,8 @@ export default {
/** /**
* @return {string} * @return {string}
*/ */
ERROR_UNSUPPORTED_MODULE_METHOD(module: Class<ModuleBase>, method: string) { ERROR_UNSUPPORTED_MODULE_METHOD(namespace: string, method: string) {
return `firebase.${module._NAMESPACE}().${method}() is unsupported by the native Firebase SDKs.`; return `firebase.${namespace}().${method}() is unsupported by the native Firebase SDKs.`;
}, },
@ -222,24 +215,5 @@ export default {
'For more information on how to resolve this issue, configure Play Services checks or for guides on how to validate Play Services on your users devices see the link below:' + 'For more information on how to resolve this issue, configure Play Services checks or for guides on how to validate Play Services on your users devices see the link below:' +
'\r\n\r\nhttp://invertase.link/play-services'; '\r\n\r\nhttp://invertase.link/play-services';
}, },
DEFAULT_APP_NAME,
},
SharedEventEmitter: new EventEmitter(),
SyncTree: NativeModules.RNFirebaseDatabase ? new SyncTree(NativeModules.RNFirebaseDatabase) : null,
// internal utils
deleteApp(name: String): Promise<boolean> {
const app = this.APPS[name];
if (!app) return Promise.resolve(true);
// https://firebase.google.com/docs/reference/js/firebase.app.App#delete
return app.delete().then(() => {
delete this.APPS[name];
return true;
});
}, },
}; };

View File

@ -1,12 +1,34 @@
/*
* @flow
*/
import { windowOrGlobal } from './'; import { windowOrGlobal } from './';
import type ModuleBase from './ModuleBase';
((base) => { ((base) => {
window = base || window; window = base || window;
// $FlowFixMe: Why are we using localStorage at all?
if (!window.localStorage) window.localStorage = {}; if (!window.localStorage) window.localStorage = {};
})(windowOrGlobal); })(windowOrGlobal);
// clean up time // clean up time
const NATIVE_LOGGERS: { [string]: Object } = {};
const getModuleKey = (module: ModuleBase): string => `${module.app.name}:${module.namespace}`;
export const getLogger = (module: ModuleBase) => {
const key = getModuleKey(module);
return NATIVE_LOGGERS[key];
};
export const initialiseLogger = (module: ModuleBase, logNamespace: string) => {
const key = getModuleKey(module);
if (!NATIVE_LOGGERS[key]) {
NATIVE_LOGGERS[key] = require('bows')(`🔥 ${logNamespace.toUpperCase()}`);
}
};
export default class Log { export default class Log {
static createLogger(namespace) { static createLogger(namespace) {
return require('bows')(namespace); return require('bows')(namespace);

67
lib/utils/native.js Normal file
View File

@ -0,0 +1,67 @@
/*
* @flow
*/
import { NativeModules } from 'react-native';
import { initialiseNativeModuleEventEmitter } from './events';
import INTERNALS from './internals';
import type ModuleBase from './ModuleBase';
import type { FirebaseModuleConfig } from '../types';
// Firebase Native SDKs that support multiple app instances
const MULTI_APP_MODULES = [
'RNFirebaseAuth',
'RNFirebaseDatabase',
'RNFirebaseFirestore',
'RNFirebaseStorage',
];
const NATIVE_MODULES: { [string]: Object } = {};
/**
* Prepends appName arg to all native method calls
* @param appName
* @param NativeModule
*/
const nativeWithApp = (appName: string, NativeModule: Object): Object => {
const native = {};
const methods = Object.keys(NativeModule);
for (let i = 0, len = methods.length; i < len; i++) {
const method = methods[i];
native[method] = (...args) => {
return NativeModule[method](...[appName, ...args]);
};
}
return native;
};
const getModuleKey = (module: ModuleBase): string => `${module.app.name}:${module.namespace}`;
export const getNativeModule = (module: ModuleBase): Object => {
const key = getModuleKey(module);
return NATIVE_MODULES[key];
};
export const initialiseNativeModule = (module: ModuleBase, config: FirebaseModuleConfig): Object => {
const { moduleName, namespace } = config;
const nativeModule = NativeModules[moduleName];
const key = getModuleKey(module);
if (!nativeModule && namespace !== 'utils') {
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_MODULE(namespace, moduleName));
}
// used by the modules that extend ModuleBase
// to access their native module counterpart
if (!MULTI_APP_MODULES.includes(moduleName)) {
NATIVE_MODULES[key] = nativeModule;
} else {
NATIVE_MODULES[key] = nativeWithApp(module.app.name, nativeModule);
}
initialiseNativeModuleEventEmitter(module, config);
return NATIVE_MODULES[key];
};

View File

@ -153,7 +153,7 @@ PODS:
- React/Core - React/Core
- React/fishhook - React/fishhook
- React/RCTBlob - React/RCTBlob
- RNFirebase (3.1.1): - RNFirebase (3.2.0):
- React - React
- yoga (0.49.1.React) - yoga (0.49.1.React)
@ -215,7 +215,7 @@ SPEC CHECKSUMS:
nanopb: 5601e6bca2dbf1ed831b519092ec110f66982ca3 nanopb: 5601e6bca2dbf1ed831b519092ec110f66982ca3
Protobuf: 03eef2ee0b674770735cf79d9c4d3659cf6908e8 Protobuf: 03eef2ee0b674770735cf79d9c4d3659cf6908e8
React: cf892fb84b7d06bf5fea7f328e554c6dcabe85ee React: cf892fb84b7d06bf5fea7f328e554c6dcabe85ee
RNFirebase: 976f3b35d112017c69da5ada20cf1f15fc2c327e RNFirebase: 22b1917fec663706907bc901ed665ac4f8b9bfd6
yoga: 3abf02d6d9aeeb139b4c930eb1367feae690a35a yoga: 3abf02d6d9aeeb139b4c930eb1367feae690a35a
PODFILE CHECKSUM: f17a538903249834df5049668d10174810db4c4c PODFILE CHECKSUM: f17a538903249834df5049668d10174810db4c4c

View File

@ -40,7 +40,7 @@ const ios = {
const instances = { const instances = {
web: firebase.initializeApp(config), web: firebase.initializeApp(config),
native: RNfirebase.app(), native: RNfirebase,
another: RNfirebase.initializeApp(Platform.OS === 'ios' ? ios : android, 'anotherApp'), another: RNfirebase.initializeApp(Platform.OS === 'ios' ? ios : android, 'anotherApp'),
}; };

View File

@ -53,8 +53,7 @@ function coreTests({ describe, it }) {
it('it should provide an array of apps', () => { it('it should provide an array of apps', () => {
should.equal(!!RNFirebase.apps.length, true); should.equal(!!RNFirebase.apps.length, true);
should.equal(RNFirebase.apps[0]._name, RNFirebase.utils.DEFAULT_APP_NAME); should.equal(RNFirebase.apps.includes(RNFirebase.app('[DEFAULT]')), true);
should.equal(RNFirebase.apps[0].name, '[DEFAULT]');
return Promise.resolve(); return Promise.resolve();
}); });