mirror of
https://github.com/zhigang1992/react-native-firebase.git
synced 2026-06-19 18:23:17 +08:00
started work on multiple app initialization
This commit is contained in:
@@ -7,6 +7,7 @@ import java.util.HashMap;
|
||||
|
||||
// react
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.bridge.LifecycleEventListener;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
@@ -43,6 +44,12 @@ public class RNFirebaseModule extends ReactContextBaseJavaModule implements Life
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void initializeApp(String name, ReadableMap options) {
|
||||
// todo https://firebase.google.com/docs/reference/android/com/google/firebase/FirebaseOptions
|
||||
|
||||
}
|
||||
|
||||
private WritableMap getPlayServicesStatus() {
|
||||
GoogleApiAvailability gapi = GoogleApiAvailability.getInstance();
|
||||
final int status = gapi.isGooglePlayServicesAvailable(getReactApplicationContext());
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.net.Uri;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -42,14 +43,14 @@ import com.google.firebase.auth.EmailAuthProvider;
|
||||
import io.invertase.firebase.Utils;
|
||||
|
||||
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
|
||||
public class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
||||
class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
||||
private static final String TAG = "RNFirebaseAuth";
|
||||
|
||||
private ReactContext mReactContext;
|
||||
private FirebaseAuth mAuth;
|
||||
private FirebaseAuth.AuthStateListener mAuthListener;
|
||||
private Map<String, FirebaseAuth.AuthStateListener> mAuthListeners;
|
||||
|
||||
public RNFirebaseAuth(ReactApplicationContext reactContext) {
|
||||
RNFirebaseAuth(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
mReactContext = reactContext;
|
||||
mAuth = FirebaseAuth.getInstance();
|
||||
@@ -65,16 +66,18 @@ public class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
||||
* Add a new auth state listener - if one doesn't exist already
|
||||
*/
|
||||
@ReactMethod
|
||||
public void addAuthStateListener() {
|
||||
public void addAuthStateListener(final String appName) {
|
||||
Log.d(TAG, "addAuthStateListener");
|
||||
FirebaseAuth.AuthStateListener mAuthListener = mAuthListeners.get(appName);
|
||||
if (mAuthListener == null) {
|
||||
mAuthListener = new FirebaseAuth.AuthStateListener() {
|
||||
FirebaseAuth.AuthStateListener newAuthListener = new FirebaseAuth.AuthStateListener() {
|
||||
@Override
|
||||
public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
|
||||
FirebaseUser user = firebaseAuth.getCurrentUser();
|
||||
WritableMap msgMap = Arguments.createMap();
|
||||
if (user != null) {
|
||||
msgMap.putBoolean("authenticated", true);
|
||||
msgMap.putString("appName", appName); // for js side distribution
|
||||
msgMap.putMap("user", firebaseUserToMap(user));
|
||||
Utils.sendEvent(mReactContext, "onAuthStateChanged", msgMap);
|
||||
} else {
|
||||
@@ -83,7 +86,9 @@ public class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
||||
}
|
||||
}
|
||||
};
|
||||
mAuth.addAuthStateListener(mAuthListener);
|
||||
|
||||
mAuth.addAuthStateListener(newAuthListener);
|
||||
mAuthListeners.put(appName, newAuthListener);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,8 +96,10 @@ public class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
||||
* Removes the current auth state listener
|
||||
*/
|
||||
@ReactMethod
|
||||
public void removeAuthStateListener() {
|
||||
public void removeAuthStateListener(String appName) {
|
||||
Log.d(TAG, "removeAuthStateListener");
|
||||
FirebaseAuth.AuthStateListener mAuthListener = mAuthListeners.get(appName);
|
||||
|
||||
if (mAuthListener != null) {
|
||||
mAuth.removeAuthStateListener(mAuthListener);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#import "RNFirebase.h"
|
||||
#import "FirebaseCore/FirebaseCore.h"
|
||||
|
||||
@implementation RNFirebase
|
||||
RCT_EXPORT_MODULE(RNFirebase);
|
||||
@@ -15,4 +16,43 @@ RCT_EXPORT_MODULE(RNFirebase);
|
||||
return @[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a new firebase app instance or ignore if currently exists.
|
||||
* @return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(initializeApp:
|
||||
(NSString *) name
|
||||
options:
|
||||
(NSDictionary *) options
|
||||
callback:
|
||||
(RCTResponseSenderBlock) callback) {
|
||||
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
FIRApp *existingApp = [FIRApp appNamed:name];
|
||||
|
||||
if (!existingApp) {
|
||||
FIROptions *firOptions = [
|
||||
[FIROptions alloc]
|
||||
initWithGoogleAppID:[options valueForKey:@"iosAppId"]
|
||||
GCMSenderID:[options valueForKey:@"messagingSenderId"]
|
||||
];
|
||||
|
||||
firOptions.APIKey = [options valueForKey:@"apiKey"];
|
||||
firOptions.projectID = [options valueForKey:@"projectId"];
|
||||
firOptions.clientID = [options valueForKey:@"iosClientId"];
|
||||
firOptions.trackingID = [options valueForKey:@"trackingId"];
|
||||
firOptions.databaseURL = [options valueForKey:@"databaseURL"];
|
||||
firOptions.storageBucket = [options valueForKey:@"storageBucket"];
|
||||
firOptions.androidClientID = [options valueForKey:@"androidClientId"];
|
||||
firOptions.deepLinkURLScheme = [options valueForKey:@"deepLinkURLScheme"];
|
||||
firOptions.bundleID = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"];
|
||||
|
||||
[FIRApp configureWithName:name options:firOptions];
|
||||
}
|
||||
|
||||
// todo expand on callback result
|
||||
callback(@[[NSNull null], @{@"result": @"success"}]);
|
||||
});
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
@interface RNFirebaseAuth : RCTEventEmitter <RCTBridgeModule> {
|
||||
FIRAuthStateDidChangeListenerHandle authListenerHandle;
|
||||
Boolean listening;
|
||||
NSMutableDictionary *authStateHandlers;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#import "RNFirebaseAuth.h"
|
||||
#import "RNFirebaseEvents.h"
|
||||
#import "RCTDefines.h"
|
||||
|
||||
|
||||
#if __has_include(<FirebaseAuth/FIRAuth.h>)
|
||||
|
||||
@implementation RNFirebaseAuth
|
||||
RCT_EXPORT_MODULE();
|
||||
|
||||
@@ -10,28 +12,38 @@ RCT_EXPORT_MODULE();
|
||||
addAuthStateListener
|
||||
|
||||
*/
|
||||
RCT_EXPORT_METHOD(addAuthStateListener) {
|
||||
self->listening = true;
|
||||
self->authListenerHandle = [[FIRAuth auth] addAuthStateDidChangeListener:^(FIRAuth *_Nonnull auth, FIRUser *_Nullable user) {
|
||||
if (user != nil) {
|
||||
[self sendJSEvent:AUTH_CHANGED_EVENT props: @{ @"authenticated": @(true),@"user": [self firebaseUserToDict:user] }];
|
||||
} else {
|
||||
[self sendJSEvent:AUTH_CHANGED_EVENT props:@{ @"authenticated": @(false) }];
|
||||
}
|
||||
}];
|
||||
RCT_EXPORT_METHOD(addAuthStateListener:
|
||||
(NSString *) appName) {
|
||||
FIRApp *firApp = [FIRApp appNamed:appName];
|
||||
// todo
|
||||
// FIRAuthStateDidChangeListenerHandle *listenerBlock = [authStateHandlers valueForKey:appName];
|
||||
//
|
||||
// if (!listenerBlock) {
|
||||
// FIRAuthStateDidChangeListenerHandle *newlistenerHandle = [[FIRAuth authWithApp:firApp] addAuthStateDidChangeListener:^(FIRAuth *_Nonnull auth, FIRUser *_Nullable user) {
|
||||
// if (user != nil) {
|
||||
// [self sendJSEventWithAppName:appName title:AUTH_CHANGED_EVENT props:@{@"authenticated": @(true), @"user": [self firebaseUserToDict:user]}];
|
||||
// } else {
|
||||
// [self sendJSEventWithAppName:appName title:AUTH_CHANGED_EVENT props:@{@"authenticated": @(false)}];
|
||||
// }
|
||||
// }];
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
removeAuthStateListener
|
||||
|
||||
*/
|
||||
RCT_EXPORT_METHOD(removeAuthStateListener) {
|
||||
RCT_EXPORT_METHOD(removeAuthStateListener:
|
||||
(NSString *) appName) {
|
||||
FIRApp *firApp = [FIRApp appNamed:appName];
|
||||
|
||||
if (self->authListenerHandle != nil) {
|
||||
[[FIRAuth auth] removeAuthStateDidChangeListener:self->authListenerHandle];
|
||||
self->listening = false;
|
||||
[[FIRAuth authWithApp:firApp] removeAuthStateDidChangeListener:self->authListenerHandle];
|
||||
}
|
||||
}
|
||||
|
||||
// TODO refactor remaining methods to accept appName arg - just testing listeners for now
|
||||
|
||||
/**
|
||||
signOut
|
||||
|
||||
@@ -39,7 +51,10 @@ RCT_EXPORT_METHOD(removeAuthStateListener) {
|
||||
@param RCTPromiseRejectBlock reject
|
||||
@return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(signOut:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
RCT_EXPORT_METHOD(signOut:
|
||||
(RCTPromiseResolveBlock) resolve
|
||||
rejecter:
|
||||
(RCTPromiseRejectBlock) reject) {
|
||||
FIRUser *user = [FIRAuth auth].currentUser;
|
||||
|
||||
if (user) {
|
||||
@@ -60,7 +75,10 @@ RCT_EXPORT_METHOD(signOut:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseR
|
||||
@param RCTPromiseRejectBlock reject
|
||||
@return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(signInAnonymously:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
RCT_EXPORT_METHOD(signInAnonymously:
|
||||
(RCTPromiseResolveBlock) resolve
|
||||
rejecter:
|
||||
(RCTPromiseRejectBlock) reject) {
|
||||
[[FIRAuth auth] signInAnonymouslyWithCompletion:^(FIRUser *user, NSError *error) {
|
||||
if (error) {
|
||||
[self promiseRejectAuthException:reject error:error];
|
||||
@@ -80,7 +98,14 @@ RCT_EXPORT_METHOD(signInAnonymously:(RCTPromiseResolveBlock) resolve rejecter:(R
|
||||
@param RCTPromiseRejectBlock reject
|
||||
@return return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(signInWithEmailAndPassword:(NSString *)email pass:(NSString *)password resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
RCT_EXPORT_METHOD(signInWithEmailAndPassword:
|
||||
(NSString *) email
|
||||
pass:
|
||||
(NSString *) password
|
||||
resolver:
|
||||
(RCTPromiseResolveBlock) resolve
|
||||
rejecter:
|
||||
(RCTPromiseRejectBlock) reject) {
|
||||
[[FIRAuth auth] signInWithEmail:email password:password completion:^(FIRUser *user, NSError *error) {
|
||||
if (error) {
|
||||
[self promiseRejectAuthException:reject error:error];
|
||||
@@ -99,7 +124,14 @@ RCT_EXPORT_METHOD(signInWithEmailAndPassword:(NSString *)email pass:(NSString *)
|
||||
@param RCTPromiseRejectBlock reject
|
||||
@return return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(createUserWithEmailAndPassword:(NSString *)email pass:(NSString *)password resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
RCT_EXPORT_METHOD(createUserWithEmailAndPassword:
|
||||
(NSString *) email
|
||||
pass:
|
||||
(NSString *) password
|
||||
resolver:
|
||||
(RCTPromiseResolveBlock) resolve
|
||||
rejecter:
|
||||
(RCTPromiseRejectBlock) reject) {
|
||||
[[FIRAuth auth] createUserWithEmail:email password:password completion:^(FIRUser *user, NSError *error) {
|
||||
if (error) {
|
||||
[self promiseRejectAuthException:reject error:error];
|
||||
@@ -116,7 +148,10 @@ RCT_EXPORT_METHOD(createUserWithEmailAndPassword:(NSString *)email pass:(NSStrin
|
||||
@param RCTPromiseRejectBlock reject
|
||||
@return return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(delete:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
RCT_EXPORT_METHOD(delete:
|
||||
(RCTPromiseResolveBlock) resolve
|
||||
rejecter:
|
||||
(RCTPromiseRejectBlock) reject) {
|
||||
FIRUser *user = [FIRAuth auth].currentUser;
|
||||
|
||||
if (user) {
|
||||
@@ -139,7 +174,10 @@ RCT_EXPORT_METHOD(delete:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRe
|
||||
@param RCTPromiseRejectBlock reject
|
||||
@return return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(reload:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
RCT_EXPORT_METHOD(reload:
|
||||
(RCTPromiseResolveBlock) resolve
|
||||
rejecter:
|
||||
(RCTPromiseRejectBlock) reject) {
|
||||
FIRUser *user = [FIRAuth auth].currentUser;
|
||||
|
||||
if (user) {
|
||||
@@ -163,7 +201,10 @@ RCT_EXPORT_METHOD(reload:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRe
|
||||
@param RCTPromiseRejectBlock reject
|
||||
@return return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(sendEmailVerification:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
RCT_EXPORT_METHOD(sendEmailVerification:
|
||||
(RCTPromiseResolveBlock) resolve
|
||||
rejecter:
|
||||
(RCTPromiseRejectBlock) reject) {
|
||||
FIRUser *user = [FIRAuth auth].currentUser;
|
||||
|
||||
if (user) {
|
||||
@@ -188,7 +229,12 @@ RCT_EXPORT_METHOD(sendEmailVerification:(RCTPromiseResolveBlock) resolve rejecte
|
||||
@param RCTPromiseRejectBlock reject
|
||||
@return return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(updateEmail:(NSString *) email resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
RCT_EXPORT_METHOD(updateEmail:
|
||||
(NSString *) email
|
||||
resolver:
|
||||
(RCTPromiseResolveBlock) resolve
|
||||
rejecter:
|
||||
(RCTPromiseRejectBlock) reject) {
|
||||
FIRUser *user = [FIRAuth auth].currentUser;
|
||||
|
||||
if (user) {
|
||||
@@ -213,7 +259,12 @@ RCT_EXPORT_METHOD(updateEmail:(NSString *) email resolver:(RCTPromiseResolveBloc
|
||||
@param RCTPromiseRejectBlock reject
|
||||
@return return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(updatePassword:(NSString *) password resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
RCT_EXPORT_METHOD(updatePassword:
|
||||
(NSString *) password
|
||||
resolver:
|
||||
(RCTPromiseResolveBlock) resolve
|
||||
rejecter:
|
||||
(RCTPromiseRejectBlock) reject) {
|
||||
FIRUser *user = [FIRAuth auth].currentUser;
|
||||
|
||||
if (user) {
|
||||
@@ -238,7 +289,12 @@ RCT_EXPORT_METHOD(updatePassword:(NSString *) password resolver:(RCTPromiseResol
|
||||
@param RCTPromiseRejectBlock reject
|
||||
@return return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(updateProfile:(NSDictionary *) props resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
RCT_EXPORT_METHOD(updateProfile:
|
||||
(NSDictionary *) props
|
||||
resolver:
|
||||
(RCTPromiseResolveBlock) resolve
|
||||
rejecter:
|
||||
(RCTPromiseRejectBlock) reject) {
|
||||
FIRUser *user = [FIRAuth auth].currentUser;
|
||||
|
||||
if (user) {
|
||||
@@ -279,7 +335,12 @@ RCT_EXPORT_METHOD(updateProfile:(NSDictionary *) props resolver:(RCTPromiseResol
|
||||
@param RCTPromiseRejectBlock reject
|
||||
@return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(getToken:(BOOL)forceRefresh resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
RCT_EXPORT_METHOD(getToken:
|
||||
(BOOL) forceRefresh
|
||||
resolver:
|
||||
(RCTPromiseResolveBlock) resolve
|
||||
rejecter:
|
||||
(RCTPromiseRejectBlock) reject) {
|
||||
FIRUser *user = [FIRAuth auth].currentUser;
|
||||
|
||||
if (user) {
|
||||
@@ -305,7 +366,16 @@ RCT_EXPORT_METHOD(getToken:(BOOL)forceRefresh resolver:(RCTPromiseResolveBlock)
|
||||
@param RCTPromiseRejectBlock reject
|
||||
@return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(signInWithCredential:(NSString *)provider token:(NSString *)authToken secret:(NSString *)authSecret resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
RCT_EXPORT_METHOD(signInWithCredential:
|
||||
(NSString *) provider
|
||||
token:
|
||||
(NSString *) authToken
|
||||
secret:
|
||||
(NSString *) authSecret
|
||||
resolver:
|
||||
(RCTPromiseResolveBlock) resolve
|
||||
rejecter:
|
||||
(RCTPromiseRejectBlock) reject) {
|
||||
FIRAuthCredential *credential = [self getCredentialForProvider:provider token:authToken secret:authSecret];
|
||||
|
||||
if (credential == nil) {
|
||||
@@ -329,7 +399,12 @@ RCT_EXPORT_METHOD(signInWithCredential:(NSString *)provider token:(NSString *)au
|
||||
@param RCTPromiseRejectBlock reject
|
||||
@return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(sendPasswordResetEmail:(NSString *)email resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
RCT_EXPORT_METHOD(sendPasswordResetEmail:
|
||||
(NSString *) email
|
||||
resolver:
|
||||
(RCTPromiseResolveBlock) resolve
|
||||
rejecter:
|
||||
(RCTPromiseRejectBlock) reject) {
|
||||
[[FIRAuth auth] sendPasswordResetWithEmail:email completion:^(NSError *_Nullable error) {
|
||||
if (error) {
|
||||
[self promiseRejectAuthException:reject error:error];
|
||||
@@ -346,7 +421,10 @@ RCT_EXPORT_METHOD(sendPasswordResetEmail:(NSString *)email resolver:(RCTPromiseR
|
||||
@param RCTPromiseRejectBlock reject
|
||||
@return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(getCurrentUser:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
RCT_EXPORT_METHOD(getCurrentUser:
|
||||
(RCTPromiseResolveBlock) resolve
|
||||
rejecter:
|
||||
(RCTPromiseRejectBlock) reject) {
|
||||
FIRUser *user = [FIRAuth auth].currentUser;
|
||||
[self promiseWithUser:resolve rejecter:reject user:user];
|
||||
}
|
||||
@@ -359,7 +437,12 @@ RCT_EXPORT_METHOD(getCurrentUser:(RCTPromiseResolveBlock) resolve rejecter:(RCTP
|
||||
@param RCTPromiseRejectBlock reject
|
||||
@return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(signInWithCustomToken: (NSString *)customToken resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
RCT_EXPORT_METHOD(signInWithCustomToken:
|
||||
(NSString *) customToken
|
||||
resolver:
|
||||
(RCTPromiseResolveBlock) resolve
|
||||
rejecter:
|
||||
(RCTPromiseRejectBlock) reject) {
|
||||
[[FIRAuth auth] signInWithCustomToken:customToken completion:^(FIRUser *user, NSError *error) {
|
||||
if (error) {
|
||||
[self promiseRejectAuthException:reject error:error];
|
||||
@@ -379,7 +462,16 @@ RCT_EXPORT_METHOD(signInWithCustomToken: (NSString *)customToken resolver:(RCTPr
|
||||
@param RCTPromiseRejectBlock reject
|
||||
@return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(link:(NSString *)provider authToken:(NSString *)authToken authSecret:(NSString *)authSecret resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
RCT_EXPORT_METHOD(link:
|
||||
(NSString *) provider
|
||||
authToken:
|
||||
(NSString *) authToken
|
||||
authSecret:
|
||||
(NSString *) authSecret
|
||||
resolver:
|
||||
(RCTPromiseResolveBlock) resolve
|
||||
rejecter:
|
||||
(RCTPromiseRejectBlock) reject) {
|
||||
FIRAuthCredential *credential = [self getCredentialForProvider:provider token:authToken secret:authSecret];
|
||||
|
||||
if (credential == nil) {
|
||||
@@ -411,7 +503,16 @@ RCT_EXPORT_METHOD(link:(NSString *)provider authToken:(NSString *)authToken auth
|
||||
@param RCTPromiseRejectBlock reject
|
||||
@return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(reauthenticate:(NSString *)provider authToken:(NSString *)authToken authSecret:(NSString *)authSecret resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
RCT_EXPORT_METHOD(reauthenticate:
|
||||
(NSString *) provider
|
||||
authToken:
|
||||
(NSString *) authToken
|
||||
authSecret:
|
||||
(NSString *) authSecret
|
||||
resolver:
|
||||
(RCTPromiseResolveBlock) resolve
|
||||
rejecter:
|
||||
(RCTPromiseRejectBlock) reject) {
|
||||
FIRAuthCredential *credential = [self getCredentialForProvider:provider token:authToken secret:authSecret];
|
||||
|
||||
if (credential == nil) {
|
||||
@@ -442,7 +543,12 @@ RCT_EXPORT_METHOD(reauthenticate:(NSString *)provider authToken:(NSString *)auth
|
||||
@param RCTPromiseRejectBlock reject
|
||||
@return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(fetchProvidersForEmail:(NSString *)email resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
RCT_EXPORT_METHOD(fetchProvidersForEmail:
|
||||
(NSString *) email
|
||||
resolver:
|
||||
(RCTPromiseResolveBlock) resolve
|
||||
rejecter:
|
||||
(RCTPromiseRejectBlock) reject) {
|
||||
[[FIRAuth auth] fetchProvidersForEmail:email completion:^(NSArray<NSString *> *_Nullable providers, NSError *_Nullable error) {
|
||||
if (error) {
|
||||
[self promiseRejectAuthException:reject error:error];
|
||||
@@ -484,7 +590,6 @@ RCT_EXPORT_METHOD(fetchProvidersForEmail:(NSString *)email resolver:(RCTPromiseR
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Resolve or reject a promise based on isError value
|
||||
|
||||
@@ -492,7 +597,7 @@ RCT_EXPORT_METHOD(fetchProvidersForEmail:(NSString *)email resolver:(RCTPromiseR
|
||||
@param reject RCTPromiseRejectBlock
|
||||
@param isError BOOL
|
||||
*/
|
||||
- (void) promiseNoUser:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject isError:(BOOL) isError {
|
||||
- (void)promiseNoUser:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject isError:(BOOL)isError {
|
||||
if (isError) {
|
||||
reject(@"auth/no-current-user", @"No user currently signed in.", nil);
|
||||
} else {
|
||||
@@ -506,7 +611,7 @@ RCT_EXPORT_METHOD(fetchProvidersForEmail:(NSString *)email resolver:(RCTPromiseR
|
||||
@param reject RCTPromiseRejectBlock
|
||||
@param error NSError
|
||||
*/
|
||||
- (void) promiseRejectAuthException:(RCTPromiseRejectBlock) reject error:(NSError *)error {
|
||||
- (void)promiseRejectAuthException:(RCTPromiseRejectBlock)reject error:(NSError *)error {
|
||||
NSString *code = @"auth/unknown";
|
||||
NSString *message = [error localizedDescription];
|
||||
|
||||
@@ -629,7 +734,7 @@ RCT_EXPORT_METHOD(fetchProvidersForEmail:(NSString *)email resolver:(RCTPromiseR
|
||||
@param reject RCTPromiseRejectBlock
|
||||
@param user FIRUser
|
||||
*/
|
||||
- (void) promiseWithUser:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject user:(FIRUser *) user {
|
||||
- (void)promiseWithUser:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject user:(FIRUser *)user {
|
||||
if (user) {
|
||||
NSDictionary *userDict = [self firebaseUserToDict:user];
|
||||
resolve(userDict);
|
||||
@@ -646,17 +751,22 @@ RCT_EXPORT_METHOD(fetchProvidersForEmail:(NSString *)email resolver:(RCTPromiseR
|
||||
@param title sendEventWithName
|
||||
@param props <#props description#>
|
||||
*/
|
||||
- (void) sendJSEvent:(NSString *)title props:(NSDictionary *)props {
|
||||
- (void)sendJSEvent:(NSString *)title props:(NSDictionary *)props {
|
||||
@try {
|
||||
if (self->listening) {
|
||||
[self sendEventWithName:title body:props];
|
||||
}
|
||||
}
|
||||
@catch (NSException *error) {
|
||||
[self sendEventWithName:title body:props];
|
||||
} @catch (NSException *error) {
|
||||
NSLog(@"An error occurred in sendJSEvent: %@", [error debugDescription]);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sendJSEventWithAppName:(NSString *)appName title:(NSString *)title props:(NSDictionary *)props {
|
||||
[props setValue:appName forKey:@"appName"];
|
||||
@try {
|
||||
[self sendEventWithName:title body:props];
|
||||
} @catch (NSException *error) {
|
||||
NSLog(@"An error occurred in sendJSEvent: %@", [error debugDescription]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Converts an array of FIRUserInfo instances into the correct format to match the web sdk
|
||||
@@ -664,30 +774,30 @@ RCT_EXPORT_METHOD(fetchProvidersForEmail:(NSString *)email resolver:(RCTPromiseR
|
||||
@param providerData FIRUser.providerData
|
||||
@return NSArray
|
||||
*/
|
||||
- (NSArray <NSObject *> *) convertProviderData:(NSArray <id<FIRUserInfo>> *) providerData {
|
||||
- (NSArray <NSObject *> *)convertProviderData:(NSArray <id <FIRUserInfo>> *)providerData {
|
||||
NSMutableArray *output = [NSMutableArray array];
|
||||
|
||||
for (id<FIRUserInfo> userInfo in providerData) {
|
||||
for (id <FIRUserInfo> userInfo in providerData) {
|
||||
NSMutableDictionary *pData = [NSMutableDictionary dictionary];
|
||||
|
||||
if (userInfo.providerID != nil) {
|
||||
[pData setValue: userInfo.providerID forKey:@"providerId"];
|
||||
[pData setValue:userInfo.providerID forKey:@"providerId"];
|
||||
}
|
||||
|
||||
if (userInfo.uid != nil) {
|
||||
[pData setValue: userInfo.uid forKey:@"uid"];
|
||||
[pData setValue:userInfo.uid forKey:@"uid"];
|
||||
}
|
||||
|
||||
if (userInfo.displayName != nil) {
|
||||
[pData setValue: userInfo.displayName forKey:@"displayName"];
|
||||
[pData setValue:userInfo.displayName forKey:@"displayName"];
|
||||
}
|
||||
|
||||
if (userInfo.photoURL != nil) {
|
||||
[pData setValue: [userInfo.photoURL absoluteString] forKey:@"photoURL"];
|
||||
[pData setValue:[userInfo.photoURL absoluteString] forKey:@"photoURL"];
|
||||
}
|
||||
|
||||
if (userInfo.email != nil) {
|
||||
[pData setValue: userInfo.email forKey:@"email"];
|
||||
[pData setValue:userInfo.email forKey:@"email"];
|
||||
}
|
||||
|
||||
[output addObject:pData];
|
||||
@@ -702,21 +812,11 @@ RCT_EXPORT_METHOD(fetchProvidersForEmail:(NSString *)email resolver:(RCTPromiseR
|
||||
@param user FIRUser
|
||||
@return NSDictionary
|
||||
*/
|
||||
- (NSDictionary *) firebaseUserToDict:(FIRUser *) user {
|
||||
NSMutableDictionary *userDict = [
|
||||
@{ @"uid": user.uid,
|
||||
@"email": user.email ? user.email : [NSNull null],
|
||||
@"emailVerified": @(user.emailVerified),
|
||||
@"isAnonymous": @(user.anonymous),
|
||||
@"displayName": user.displayName ? user.displayName : [NSNull null],
|
||||
@"refreshToken": user.refreshToken,
|
||||
@"providerId": [user.providerID lowercaseString],
|
||||
@"providerData": [self convertProviderData: user.providerData]
|
||||
} mutableCopy
|
||||
];
|
||||
- (NSDictionary *)firebaseUserToDict:(FIRUser *)user {
|
||||
NSMutableDictionary *userDict = [@{@"uid": user.uid, @"email": user.email ? user.email : [NSNull null], @"emailVerified": @(user.emailVerified), @"isAnonymous": @(user.anonymous), @"displayName": user.displayName ? user.displayName : [NSNull null], @"refreshToken": user.refreshToken, @"providerId": [user.providerID lowercaseString], @"providerData": [self convertProviderData:user.providerData]} mutableCopy];
|
||||
|
||||
if ([user valueForKey:@"photoURL"] != nil) {
|
||||
[userDict setValue: [user.photoURL absoluteString] forKey:@"photoURL"];
|
||||
[userDict setValue:[user.photoURL absoluteString] forKey:@"photoURL"];
|
||||
}
|
||||
|
||||
return userDict;
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import { reverseKeyValues } from './utils';
|
||||
|
||||
export const ConnectionResult = {
|
||||
SUCCESS: 0,
|
||||
SERVICE_MISSING: 1,
|
||||
SERVICE_VERSION_UPDATE_REQUIRED: 2,
|
||||
SERVICE_DISABLED: 3,
|
||||
SIGN_IN_REQUIRED: 4,
|
||||
INVALID_ACCOUNT: 5,
|
||||
RESOLUTION_REQUIRED: 6,
|
||||
NETWORK_ERROR: 7,
|
||||
INTERNAL_ERROR: 8,
|
||||
SERVICE_INVALID: 9,
|
||||
DEVELOPER_ERROR: 10,
|
||||
LICENSE_CHECK_FAILED: 11,
|
||||
CANCELED: 13,
|
||||
TIMEOUT: 14,
|
||||
INTERRUPTED: 15,
|
||||
API_UNAVAILABLE: 16,
|
||||
SIGN_IN_FAILED: 17,
|
||||
SERVICE_UPDATING: 18,
|
||||
SERVICE_MISSING_PERMISSION: 19,
|
||||
RESTRICTED_PROFILE: 20,
|
||||
};
|
||||
|
||||
export const ConnectionResultReverse = reverseKeyValues(ConnectionResult);
|
||||
94
lib/firebase-app.js
Normal file
94
lib/firebase-app.js
Normal file
@@ -0,0 +1,94 @@
|
||||
import { NativeModules } from 'react-native';
|
||||
|
||||
import INTERNALS from './internals';
|
||||
|
||||
// modules
|
||||
import Crash from './modules/crash';
|
||||
import Performance from './modules/perf';
|
||||
import RemoteConfig from './modules/config';
|
||||
import Analytics from './modules/analytics';
|
||||
import Auth, { statics as AuthStatics } from './modules/auth';
|
||||
import AdMob, { statics as AdMobStatics } from './modules/admob';
|
||||
import Storage, { statics as StorageStatics } from './modules/storage';
|
||||
import Database, { statics as DatabaseStatics } from './modules/database';
|
||||
import Messaging, { statics as MessagingStatics } from './modules/messaging';
|
||||
|
||||
|
||||
const FirebaseCoreModule = NativeModules.RNFirebase;
|
||||
|
||||
|
||||
export default class FirebaseApp {
|
||||
constructor(name: string, options: Object = {}) {
|
||||
this._name = name;
|
||||
this._namespaces = {};
|
||||
this._options = Object.assign({}, options);
|
||||
|
||||
// native ios/android to confirm initialized
|
||||
this._intialized = false;
|
||||
}
|
||||
|
||||
_initializeApp() {
|
||||
FirebaseCoreModule.initializeApp(this._name, this._options, (error, result) => {
|
||||
// todo check error/result
|
||||
this._initialized = true;
|
||||
});
|
||||
}
|
||||
|
||||
get name() {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
get options() {
|
||||
return Object.assign({}, this._options);
|
||||
}
|
||||
|
||||
delete() {
|
||||
// todo
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* MODULES
|
||||
*/
|
||||
|
||||
get auth() {
|
||||
return this._staticsOrModuleInstance('auth', AuthStatics, Auth);
|
||||
}
|
||||
|
||||
get database() {
|
||||
return this._staticsOrModuleInstance('database', DatabaseStatics, Database);
|
||||
}
|
||||
|
||||
get messaging() {
|
||||
return this._staticsOrModuleInstance('messaging', MessagingStatics, Messaging);
|
||||
}
|
||||
|
||||
get storage() {
|
||||
return this._staticsOrModuleInstance('storage', StorageStatics, Storage);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param name
|
||||
* @param statics
|
||||
* @param InstanceClass
|
||||
* @return {function()}
|
||||
* @private
|
||||
*/
|
||||
_staticsOrModuleInstance(name, statics = {}, InstanceClass): Function {
|
||||
const getInstance = () => {
|
||||
const _name = `_${name}`;
|
||||
|
||||
if (!this._namespaces[_name]) {
|
||||
this._namespaces[_name] = new InstanceClass(this);
|
||||
}
|
||||
|
||||
return this._namespaces[_name];
|
||||
};
|
||||
|
||||
Object.assign(getInstance, statics);
|
||||
return getInstance;
|
||||
}
|
||||
}
|
||||
277
lib/firebase.js
277
lib/firebase.js
@@ -2,171 +2,186 @@
|
||||
* @providesModule Firebase
|
||||
* @flow
|
||||
*/
|
||||
import { NativeModules } from 'react-native';
|
||||
import { NativeModules, NativeEventEmitter } from 'react-native';
|
||||
|
||||
import Log from './utils/log';
|
||||
import { isObject } from './utils';
|
||||
import { isObject, isString } from './utils';
|
||||
|
||||
// modules
|
||||
import INTERNALS from './internals';
|
||||
import PACKAGE from './../package.json';
|
||||
import FirebaseApp from './firebase-app';
|
||||
|
||||
// module imports
|
||||
import Auth, { statics as AuthStatics } from './modules/auth';
|
||||
import Storage, { statics as StorageStatics } from './modules/storage';
|
||||
import Database, { statics as DatabaseStatics } from './modules/database';
|
||||
import Messaging, { statics as MessagingStatics } from './modules/messaging';
|
||||
import Analytics from './modules/analytics';
|
||||
import Crash from './modules/crash';
|
||||
import RemoteConfig from './modules/config';
|
||||
import Performance from './modules/perf';
|
||||
import AdMob, { statics as AdMobStatics } from './modules/admob';
|
||||
|
||||
const instances: Object = { default: null };
|
||||
const FirebaseModule = NativeModules.RNFirebase;
|
||||
const FirebaseCoreModule = NativeModules.RNFirebase;
|
||||
|
||||
/**
|
||||
* @class Firebase
|
||||
*/
|
||||
export default class Firebase {
|
||||
_log: ?Object;
|
||||
_auth: ?Object;
|
||||
_store: ?Object;
|
||||
_storage: ?Object;
|
||||
_database: ?Object;
|
||||
_presence: ?Object;
|
||||
_analytics: ?Object;
|
||||
_constants: ?Object;
|
||||
_messaging: ?Object;
|
||||
_config: ?Object;
|
||||
_crash: ?Object;
|
||||
_perf: ?Object;
|
||||
_admob: ?Object;
|
||||
class FirebaseCore {
|
||||
constructor() {
|
||||
this._nativeEmitters = {};
|
||||
|
||||
auth: Function;
|
||||
crash: Function;
|
||||
storage: Function;
|
||||
database: Function;
|
||||
analytics: Function;
|
||||
messaging: Function;
|
||||
config: Function;
|
||||
perf: Function;
|
||||
admob: Function;
|
||||
|
||||
eventHandlers: Object;
|
||||
debug: boolean;
|
||||
options: {
|
||||
errorOnMissingPlayServices: boolean,
|
||||
debug?: boolean,
|
||||
persistence?: boolean
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param options
|
||||
*/
|
||||
constructor(options: Object = {}) {
|
||||
this.eventHandlers = {};
|
||||
this.debug = options.debug || false;
|
||||
this.options = Object.assign({ errorOnMissingPlayServices: true, promptOnMissingPlayServices: true }, options);
|
||||
|
||||
if (this.debug) {
|
||||
Log.enable(this.debug);
|
||||
}
|
||||
|
||||
this._log = new Log('firebase');
|
||||
|
||||
if (!this.googleApiAvailability.isAvailable) {
|
||||
if (this.options.promptOnMissingPlayServices && this.googleApiAvailability.isUserResolvableError) {
|
||||
FirebaseModule.promptPlayServices();
|
||||
} else {
|
||||
const error = `Google Play Services is required to run this application but no valid installation was found (Code ${this.googleApiAvailability.status}).`;
|
||||
if (this.options.errorOnMissingPlayServices) {
|
||||
throw new Error(error);
|
||||
} else {
|
||||
console.warn(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.auth = this._staticsOrInstance('auth', AuthStatics, Auth);
|
||||
this.storage = this._staticsOrInstance('storage', StorageStatics, Storage);
|
||||
this.database = this._staticsOrInstance('database', DatabaseStatics, Database);
|
||||
this.messaging = this._staticsOrInstance('messaging', MessagingStatics, Messaging);
|
||||
this.analytics = this._staticsOrInstance('analytics', {}, Analytics);
|
||||
this.crash = this._staticsOrInstance('crash', {}, Crash);
|
||||
this.config = this._staticsOrInstance('config', {}, RemoteConfig);
|
||||
this.perf = this._staticsOrInstance('perf', {}, Performance);
|
||||
this.admob = this._staticsOrInstance('admob', AdMobStatics, AdMob);
|
||||
|
||||
// init auth to start listeners
|
||||
// todo init other modules if available on native
|
||||
// todo generalise this so adding other modules isn't so repetitive:
|
||||
if (NativeModules.RNFirebaseAuth) {
|
||||
this.auth();
|
||||
this._nativeEmitters.auth = new NativeEventEmitter(NativeModules.RNFirebaseAuth);
|
||||
this._subscribeForDistribution('onAuthStateChanged', this._nativeEmitters.auth);
|
||||
}
|
||||
// ...
|
||||
}
|
||||
|
||||
/**
|
||||
* Support web version of initApp.
|
||||
* Web SDK initializeApp
|
||||
*
|
||||
* @param options
|
||||
* @param name
|
||||
* @returns {*}
|
||||
* @return {*}
|
||||
*/
|
||||
static initializeApp(options: Object = {}, name: string = 'default') {
|
||||
initializeApp(options: Object = {}, name: string): FirebaseApp {
|
||||
if (!isObject(options)) {
|
||||
throw new Error('Firebase.initializeApp(options <- requires a configuration object');
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_INIT_OBJECT);
|
||||
}
|
||||
|
||||
if (typeof name !== 'string') {
|
||||
throw new Error('Firebase.initializeApp(options, name <- requires a string value');
|
||||
// todo validate required options
|
||||
|
||||
if (name && !isString(name)) {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_INIT_STRING_NAME);
|
||||
}
|
||||
|
||||
if (name !== 'default') {
|
||||
throw new Error('RNFirebase currently only supports one instance of firebase - the default one.');
|
||||
const _name = (name || INTERNALS.STRINGS.DEFAULT_APP_NAME).toUpperCase();
|
||||
|
||||
if (!INTERNALS.APPS[_name]) {
|
||||
INTERNALS.APPS[_name] = new FirebaseApp(_name, options);
|
||||
INTERNALS.APPS[_name]._initializeApp();
|
||||
}
|
||||
|
||||
if (!instances[name]) instances[name] = new Firebase(options);
|
||||
return instances[name];
|
||||
}
|
||||
|
||||
get apps(): Array<string> {
|
||||
return Object.keys(instances);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns androids GoogleApiAvailability status and message if available.
|
||||
* @returns {GoogleApiAvailabilityType|{isAvailable: boolean, status: number}}
|
||||
*/
|
||||
get googleApiAvailability(): GoogleApiAvailabilityType {
|
||||
// if not available then return a fake object for ios - saves doing platform specific logic.
|
||||
return FirebaseModule.googleApiAvailability || { isAvailable: true, status: 0 };
|
||||
}
|
||||
|
||||
/**
|
||||
* Logger
|
||||
*/
|
||||
get log(): Log {
|
||||
return this._log;
|
||||
return INTERNALS.APPS[_name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a Firebase app instance.
|
||||
*
|
||||
* When called with no arguments, the default app is returned.
|
||||
* When an app name is provided, the app corresponding to that name is returned.
|
||||
*
|
||||
* @param name
|
||||
* @param statics
|
||||
* @param InstanceClass
|
||||
* @returns {function()}
|
||||
* @return {*}
|
||||
*/
|
||||
app(name?: string): FirebaseApp {
|
||||
const _name = name ? name.toUpperCase() : INTERNALS.STRINGS.DEFAULT_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.
|
||||
* @return {Array}
|
||||
*/
|
||||
get apps(): Array<Object> {
|
||||
return Object.values(INTERNALS.APPS);
|
||||
}
|
||||
|
||||
/**
|
||||
* The current RNFirebase SDK version.
|
||||
*/
|
||||
get SDK_VERSION() {
|
||||
return PACKAGE.version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns props from the android GoogleApiAvailability sdk
|
||||
* @android
|
||||
* @return {RNFirebase.GoogleApiAvailabilityType|{isAvailable: boolean, status: number}}
|
||||
*/
|
||||
get googleApiAvailabilty(): GoogleApiAvailabilityType {
|
||||
return FirebaseCoreModule.googleApiAvailability || { isAvailable: true, status: 0 };
|
||||
}
|
||||
|
||||
/*
|
||||
* MODULES
|
||||
*/
|
||||
|
||||
get auth() {
|
||||
return this._appNamespaceOrStatics('auth', AuthStatics, Auth);
|
||||
}
|
||||
|
||||
get database() {
|
||||
return this._appNamespaceOrStatics('database', DatabaseStatics, Database);
|
||||
}
|
||||
|
||||
get messaging() {
|
||||
return this._appNamespaceOrStatics('messaging', MessagingStatics, Messaging);
|
||||
}
|
||||
|
||||
get storage() {
|
||||
return this._appNamespaceOrStatics('storage', StorageStatics, Storage);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CONFIG METHODS
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set the global logging level for all logs.
|
||||
*
|
||||
* @param booleanOrDebugString
|
||||
*/
|
||||
setLogLevel(booleanOrDebugString) {
|
||||
INTERNALS.OPTIONS.logLevel = booleanOrDebugString;
|
||||
Log.setLevel(booleanOrDebugString);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
_staticsOrInstance(name, statics, InstanceClass): Function {
|
||||
const getInstance = () => {
|
||||
const internalPropName = `_${name}`;
|
||||
|
||||
// $FlowFixMe
|
||||
if (!this[internalPropName]) {
|
||||
// $FlowFixMe
|
||||
this[internalPropName] = new InstanceClass(this);
|
||||
_subscribeForDistribution(eventName, nativeEmitter) {
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// $FlowFixMe
|
||||
return this[internalPropName];
|
||||
/**
|
||||
*
|
||||
* @param namespace
|
||||
* @param statics
|
||||
* @return {function(FirebaseApp=)}
|
||||
* @private
|
||||
*/
|
||||
_appNamespaceOrStatics(namespace, statics = {}): Function {
|
||||
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);
|
||||
return INTERNALS.APPS[_app.name][namespace](_app);
|
||||
};
|
||||
|
||||
Object.assign(getInstance, statics || {});
|
||||
return getInstance;
|
||||
Object.assign(getNamespace, statics);
|
||||
return getNamespace;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default new FirebaseCore();
|
||||
|
||||
61
lib/internals.js
Normal file
61
lib/internals.js
Normal file
@@ -0,0 +1,61 @@
|
||||
import EventEmitter from 'EventEmitter';
|
||||
|
||||
const DEFAULT_APP_NAME = 'DEFAULT';
|
||||
|
||||
// am still thinking ;p
|
||||
export default {
|
||||
// default options
|
||||
OPTIONS: {
|
||||
logLevel: 'warn',
|
||||
},
|
||||
|
||||
// track all initialized firebase apps
|
||||
APPS: {
|
||||
[DEFAULT_APP_NAME]: null,
|
||||
},
|
||||
|
||||
STRINGS: {
|
||||
ERROR_INIT_OBJECT: 'Firebase.initializeApp(options <-- requires a valid configuration object.',
|
||||
ERROR_INIT_STRING_NAME: 'Firebase.initializeApp(options, name <-- requires a valid string value.',
|
||||
|
||||
/**
|
||||
* @param moduleName
|
||||
* @return {string}
|
||||
*/
|
||||
ERROR_MISSING_MODULE(moduleName) {
|
||||
return `Attempted to call a method for a module that is not installed natively (${moduleName}).`;
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {string}
|
||||
*/
|
||||
ERROR_APP_NOT_INIT(appName) {
|
||||
return `The [${{ appName }}] firebase app has not been initialized!`;
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {string}
|
||||
*/
|
||||
ERROR_NOT_APP(namespace) {
|
||||
return `Invalid FirebaseApp instance passed to firebase.${namespace}(app <--).`;
|
||||
},
|
||||
|
||||
DEFAULT_APP_NAME,
|
||||
},
|
||||
|
||||
|
||||
SharedEventEmitter: new EventEmitter(),
|
||||
|
||||
|
||||
// internal utils
|
||||
deleteApp(name: String) {
|
||||
const app = this.APPS[name];
|
||||
if (!app) return Promise.resolve();
|
||||
|
||||
// https://firebase.google.com/docs/reference/js/firebase.app.App#delete
|
||||
return app.delete().then(() => {
|
||||
delete this.APPS[name];
|
||||
return true;
|
||||
});
|
||||
},
|
||||
};
|
||||
@@ -2,8 +2,7 @@
|
||||
import { NativeModules, NativeEventEmitter } from 'react-native';
|
||||
|
||||
import User from './user';
|
||||
import { Base } from './../base';
|
||||
import { nativeSDKMissing } from './../../utils';
|
||||
import ModuleBase from './../../utils/ModuleBase';
|
||||
|
||||
// providers
|
||||
import EmailAuthProvider from './providers/Email';
|
||||
@@ -13,26 +12,19 @@ import TwitterAuthProvider from './providers/Twitter';
|
||||
import GithubAuthProvider from './providers/Github';
|
||||
|
||||
const FirebaseAuth = NativeModules.RNFirebaseAuth;
|
||||
const FirebaseAuthEvt = FirebaseAuth && new NativeEventEmitter(FirebaseAuth);
|
||||
|
||||
export default class Auth extends Base {
|
||||
export default class Auth extends ModuleBase {
|
||||
_user: User | null;
|
||||
_authResult: AuthResultType | null;
|
||||
authenticated: boolean;
|
||||
|
||||
constructor(firebase: Object, options: Object = {}) {
|
||||
super(firebase, options);
|
||||
if (!FirebaseAuth) {
|
||||
return nativeSDKMissing('auth');
|
||||
}
|
||||
|
||||
constructor(firebaseApp: Object, options: Object = {}) {
|
||||
super(firebaseApp, options, 'auth');
|
||||
this._user = null;
|
||||
this._authResult = null;
|
||||
this.authenticated = false;
|
||||
|
||||
// start listening immediately for auth changes
|
||||
FirebaseAuthEvt.addListener('onAuthStateChanged', this._onAuthStateChanged.bind(this));
|
||||
FirebaseAuth.addAuthStateListener();
|
||||
this.addListener('onAuthStateChanged', this._onAuthStateChanged.bind(this));
|
||||
this._native.addAuthStateListener(); // this is the native function on ios/android:
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,64 +2,7 @@
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import EventEmitter from 'react-native/Libraries/EventEmitter/EventEmitter';
|
||||
import Log from '../utils/log';
|
||||
|
||||
const logs = {};
|
||||
const SharedEventEmitter = new EventEmitter();
|
||||
|
||||
export class Base {
|
||||
|
||||
/**
|
||||
* Return a namespaced instance of Log
|
||||
* @returns {*}
|
||||
*/
|
||||
get log(): Log {
|
||||
if (logs[this.namespace]) return logs[this.namespace];
|
||||
|
||||
// todo grab log level from global config provider (still todo);
|
||||
return logs[this.namespace] = new Log(this.namespace, '*');
|
||||
}
|
||||
|
||||
/*
|
||||
* Proxy functions to shared event emitter instance
|
||||
* https://github.com/facebook/react-native/blob/master/Libraries/EventEmitter/EventEmitter.js
|
||||
*/
|
||||
|
||||
get sharedEventEmitter () {
|
||||
return SharedEventEmitter;
|
||||
}
|
||||
|
||||
get addListener() {
|
||||
return SharedEventEmitter.addListener.bind(SharedEventEmitter);
|
||||
}
|
||||
|
||||
get on() {
|
||||
return SharedEventEmitter.addListener.bind(SharedEventEmitter);
|
||||
}
|
||||
|
||||
get emit() {
|
||||
return SharedEventEmitter.emit.bind(SharedEventEmitter);
|
||||
}
|
||||
|
||||
get listeners() {
|
||||
return SharedEventEmitter.listeners.bind(SharedEventEmitter);
|
||||
}
|
||||
|
||||
hasListeners(eventType: string): Boolean {
|
||||
const subscriptions = SharedEventEmitter._subscriber.getSubscriptionsForType(eventType);
|
||||
return subscriptions && subscriptions.length;
|
||||
}
|
||||
|
||||
get removeListener() {
|
||||
return SharedEventEmitter.removeListener.bind(SharedEventEmitter);
|
||||
}
|
||||
|
||||
get removeAllListeners() {
|
||||
return SharedEventEmitter.removeAllListeners.bind(SharedEventEmitter);
|
||||
}
|
||||
}
|
||||
|
||||
// todo move out
|
||||
export class ReferenceBase extends Base {
|
||||
constructor(path: string) {
|
||||
super();
|
||||
@@ -72,7 +15,7 @@ export class ReferenceBase extends Base {
|
||||
* @type {String}
|
||||
* {@link https://firebase.google.com/docs/reference/js/firebase.database.Reference#key}
|
||||
*/
|
||||
get key(): string|null {
|
||||
get key(): string | null {
|
||||
return this.path === '/' ? null : this.path.substring(this.path.lastIndexOf('/') + 1);
|
||||
}
|
||||
}
|
||||
|
||||
83
lib/utils/ModuleBase.js
Normal file
83
lib/utils/ModuleBase.js
Normal file
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
import { NativeModules } from 'react-native';
|
||||
import Log from '../utils/log';
|
||||
import { nativeWithApp } from './../utils';
|
||||
import INTERNALS from './../internals';
|
||||
|
||||
// logging instances
|
||||
|
||||
const logs = {};
|
||||
|
||||
export default class ModuleBase {
|
||||
constructor(firebaseApp, options, moduleName) {
|
||||
this._options = Object.assign({}, options);
|
||||
this._module = moduleName;
|
||||
this._firebaseApp = firebaseApp;
|
||||
this._appName = firebaseApp.name;
|
||||
this._namespace = `${this._appName}:${this._module}`;
|
||||
|
||||
// check if native module exists as all native modules are now optionally part of build
|
||||
const nativeModule = NativeModules[`RNFirebase${moduleName}`];
|
||||
|
||||
if (!nativeModule) {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_MODULE(moduleName));
|
||||
}
|
||||
|
||||
// used by the modules that extend ModuleBase to access their native module counterpart
|
||||
this._native = nativeWithApp(this._appName, nativeModule);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the FirebaseApp instance for current module
|
||||
* @return {*}
|
||||
*/
|
||||
get app() {
|
||||
return this._firebaseApp;
|
||||
}
|
||||
|
||||
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() {
|
||||
return INTERNALS.SharedEventEmitter;
|
||||
}
|
||||
|
||||
get addListener() {
|
||||
return INTERNALS.SharedEventEmitter.addListener.bind(INTERNALS.SharedEventEmitter);
|
||||
}
|
||||
|
||||
get on() {
|
||||
return INTERNALS.SharedEventEmitter.addListener.bind(INTERNALS.SharedEventEmitter);
|
||||
}
|
||||
|
||||
get emit() {
|
||||
return INTERNALS.SharedEventEmitter.emit.bind(INTERNALS.SharedEventEmitter);
|
||||
}
|
||||
|
||||
get listeners() {
|
||||
return INTERNALS.SharedEventEmitter.listeners.bind(INTERNALS.SharedEventEmitter);
|
||||
}
|
||||
|
||||
hasListeners(eventType: string): Boolean {
|
||||
const subscriptions = INTERNALS.SharedEventEmitter._subscriber.getSubscriptionsForType(eventType);
|
||||
return subscriptions && subscriptions.length;
|
||||
}
|
||||
|
||||
get removeListener() {
|
||||
return INTERNALS.SharedEventEmitter.removeListener.bind(INTERNALS.SharedEventEmitter);
|
||||
}
|
||||
|
||||
get removeAllListeners() {
|
||||
return INTERNALS.SharedEventEmitter.removeAllListeners.bind(INTERNALS.SharedEventEmitter);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Platform } from 'react-native';
|
||||
|
||||
// todo cleanup unused utilities from legacy code
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
@@ -109,6 +110,15 @@ export function isFunction(item?: any): boolean {
|
||||
return Boolean(item && typeof item === 'function');
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple is string check
|
||||
* @param value
|
||||
* @return {boolean}
|
||||
*/
|
||||
export function isString(value): Boolean {
|
||||
return typeof value === 'string';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string
|
||||
@@ -334,3 +344,23 @@ export function nativeToJSError(code: string, message: string) {
|
||||
error.code = code;
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends appName arg to all native method calls
|
||||
* @param appName
|
||||
* @param NativeModule
|
||||
*/
|
||||
export function nativeWithApp(appName, NativeModule) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,36 +5,15 @@ import { windowOrGlobal } from './';
|
||||
if (!window.localStorage) window.localStorage = {};
|
||||
})(windowOrGlobal);
|
||||
|
||||
// clean up time
|
||||
|
||||
export default class Log {
|
||||
constructor(namespace) {
|
||||
this._namespace = namespace || 'RNFirebase';
|
||||
require('bows').config({ padLength: 20 });
|
||||
this.loggers = {};
|
||||
static createLogger(namespace) {
|
||||
return require('bows')(namespace);
|
||||
}
|
||||
|
||||
get warn() {
|
||||
return this._createOrGetLogger('warn');
|
||||
}
|
||||
|
||||
get info() {
|
||||
return this._createOrGetLogger('info');
|
||||
}
|
||||
|
||||
get error() {
|
||||
return this._createOrGetLogger('error');
|
||||
}
|
||||
|
||||
get debug() {
|
||||
return this._createOrGetLogger('debug');
|
||||
}
|
||||
|
||||
static enable(booleanOrStringDebug) {
|
||||
window.localStorage.debug = booleanOrStringDebug;
|
||||
window.localStorage.debugColors = !!window.localStorage.debug;
|
||||
}
|
||||
|
||||
_createOrGetLogger(level) {
|
||||
if (!this.loggers[level]) this.loggers[level] = require('bows')(this._namespace, `[${level}]`);
|
||||
return this.loggers[level];
|
||||
static setLevel(booleanOrDebugString) {
|
||||
window.localStorage.debug = booleanOrDebugString;
|
||||
window.localStorage.debugColors = !!booleanOrDebugString;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user