This commit is contained in:
Salakar 2018-08-14 02:03:39 +01:00
commit c6d0470b14
33 changed files with 12518 additions and 120 deletions

View File

@ -61,9 +61,9 @@ Using the native Firebase SDKs with **React Native Firebase** allows you to cons
| | 3.3.x | 4.3.x | 5.0.x | | | 3.3.x | 4.3.x | 5.0.x |
| ------------------------- | :------: | :-----: | :---: | | ------------------------- | :------: | :-----: | :---: |
| React Native | 0.50 + | 0.52-55 | 0.56+ | | React Native | 0.50-52 | 0.52-55 | 0.56 |
| Play Services Android SDK | 11.8.0 + | 15.0.1 | TBC | | Play Services Android SDK | 11.8.0 + | 15.0.1 | TBC |
| Firebase iOS SDK | 4.7.0 + | 5.3.0 | TBC | | Firebase iOS SDK | 4.7.0 + | 5.3.0 | 5.5.0 |
--- ---
@ -87,7 +87,7 @@ For feature requests please visit our [Feature Request Board](https://boards.inv
Detailed changes for each release are documented in the [releases notes](https://github.com/invertase/react-native-firebase/releases). Detailed changes for each release are documented in the [releases notes](https://github.com/invertase/react-native-firebase/releases).
---- ---
## Supporting RNFirebase ## Supporting RNFirebase

View File

@ -73,10 +73,15 @@ public class RNFirebaseModule extends ReactContextBaseJavaModule {
} }
} }
@ReactMethod
public void getPlayServicesStatus(Promise promise) {
promise.resolve(getPlayServicesStatusMap());
}
/** /**
* @return * @return
*/ */
private WritableMap getPlayServicesStatus() { private WritableMap getPlayServicesStatusMap() {
GoogleApiAvailability gapi = GoogleApiAvailability.getInstance(); GoogleApiAvailability gapi = GoogleApiAvailability.getInstance();
final int status = gapi.isGooglePlayServicesAvailable(getReactApplicationContext()); final int status = gapi.isGooglePlayServicesAvailable(getReactApplicationContext());
WritableMap result = Arguments.createMap(); WritableMap result = Arguments.createMap();
@ -176,7 +181,7 @@ public class RNFirebaseModule extends ReactContextBaseJavaModule {
} }
constants.put("apps", appMapsList); constants.put("apps", appMapsList);
constants.put("playServicesAvailability", getPlayServicesStatus()); constants.put("playServicesAvailability", getPlayServicesStatusMap());
return constants; return constants;
} }
} }

View File

@ -5,14 +5,14 @@ import android.util.Log;
import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.WritableMap;
import com.google.android.gms.tasks.OnFailureListener; import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener; import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.FirebaseApp;
import com.google.firebase.functions.FirebaseFunctions; import com.google.firebase.functions.FirebaseFunctions;
import com.google.firebase.functions.FirebaseFunctionsException; import com.google.firebase.functions.FirebaseFunctionsException;
import com.google.firebase.functions.HttpsCallableReference; import com.google.firebase.functions.HttpsCallableReference;
@ -39,17 +39,56 @@ public class RNFirebaseFunctions extends ReactContextBaseJavaModule {
return TAG; return TAG;
} }
/**
* Changes this instance to point to a Cloud Functions emulator running
* locally.
* <p>
* See https://firebase.google.com/docs/functions/local-emulator
*
* @param origin the origin string of the local emulator started via firebase tools
* "http://10.0.0.8:1337".
* @param appName
* @param region
* @param origin
* @param promise
*/
@ReactMethod @ReactMethod
public void httpsCallable(final String name, ReadableMap wrapper, final Promise promise) { public void useFunctionsEmulator(
String appName,
String region,
String origin,
Promise promise
) {
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
FirebaseFunctions functionsInstance = FirebaseFunctions.getInstance(firebaseApp, region);
functionsInstance.useFunctionsEmulator(origin);
promise.resolve(null);
}
/**
* @param appName
* @param region
* @param name
* @param wrapper
* @param promise
*/
@ReactMethod
public void httpsCallable(
String appName,
String region,
final String name,
ReadableMap wrapper,
final Promise promise
) {
Object input = wrapper Object input = wrapper
.toHashMap() .toHashMap()
.get(DATA_KEY); .get(DATA_KEY);
Log.d(TAG, "function:call:input:" + name + ":" + (input != null ? input.toString() : "null")); Log.d(TAG, "function:call:input:" + name + ":" + (input != null ? input.toString() : "null"));
HttpsCallableReference httpsCallableReference = FirebaseFunctions FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
.getInstance() FirebaseFunctions functionsInstance = FirebaseFunctions.getInstance(firebaseApp, region);
.getHttpsCallable(name); HttpsCallableReference httpsCallableReference = functionsInstance.getHttpsCallable(name);
httpsCallableReference httpsCallableReference
.call(input) .call(input)
@ -96,9 +135,9 @@ public class RNFirebaseFunctions extends ReactContextBaseJavaModule {
code = ffe code = ffe
.getCode() .getCode()
.name(); .name();
message = ffe.getLocalizedMessage(); message = ffe.getMessage();
} else { } else {
message = exception.getLocalizedMessage(); message = exception.getMessage();
} }
Utils.mapPutValue(CODE_KEY, code, map); Utils.mapPutValue(CODE_KEY, code, map);

View File

@ -82,7 +82,7 @@ dependencies {
//noinspection GradleDynamicVersion //noinspection GradleDynamicVersion
implementation project(':react-native-firebase') implementation project(':react-native-firebase')
implementation(project(':bridge')) { implementation(project(':jet')) {
transitive = false transitive = false
} }
@ -100,8 +100,8 @@ dependencies {
implementation "com.google.firebase:firebase-auth:16.0.2" implementation "com.google.firebase:firebase-auth:16.0.2"
implementation "com.google.firebase:firebase-config:16.0.0" implementation "com.google.firebase:firebase-config:16.0.0"
implementation "com.google.firebase:firebase-database:16.0.1" implementation "com.google.firebase:firebase-database:16.0.1"
implementation "com.google.firebase:firebase-firestore:17.0.2" implementation "com.google.firebase:firebase-firestore:17.0.4"
implementation "com.google.firebase:firebase-functions:16.0.1" implementation "com.google.firebase:firebase-functions:16.1.0"
implementation "com.google.firebase:firebase-invites:16.0.1" implementation "com.google.firebase:firebase-invites:16.0.1"
implementation "com.google.firebase:firebase-storage:16.0.1" implementation "com.google.firebase:firebase-storage:16.0.1"
implementation "com.google.firebase:firebase-messaging:17.1.0" implementation "com.google.firebase:firebase-messaging:17.1.0"

View File

@ -1,6 +1,6 @@
rootProject.name = 'RNFTests' rootProject.name = 'RNFTests'
include ':bridge' include ':jet'
project(':bridge').projectDir = new File(rootProject.projectDir, '../node_modules/bridge/android') project(':jet').projectDir = new File(rootProject.projectDir, '../node_modules/jet/android')
include ':react-native-firebase' include ':react-native-firebase'
project(':react-native-firebase').projectDir = new File(rootProject.projectDir, './../../android') project(':react-native-firebase').projectDir = new File(rootProject.projectDir, './../../android')

View File

@ -2,7 +2,7 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { AppRegistry, Text, View } from 'react-native'; import { AppRegistry, Text, View } from 'react-native';
import bridge from 'bridge/platform/react-native'; import bridge from 'jet/platform/react-native';
import firebase from 'react-native-firebase'; import firebase from 'react-native-firebase';
require('sinon'); require('sinon');

View File

@ -4,5 +4,5 @@
--slow 600 --slow 600
--bail --bail
--exit --exit
--require bridge/platform/node --require jet/platform/node
--require ./helpers --require ./helpers

12247
bridge/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -20,7 +20,7 @@
"ios:pod:install": "cd ios && rm -rf ReactNativeFirebaseDemo.xcworkspace && pod install && cd .." "ios:pod:install": "cd ios && rm -rf ReactNativeFirebaseDemo.xcworkspace && pod install && cd .."
}, },
"dependencies": { "dependencies": {
"bridge": "^0.2.7", "jet": "0.0.2",
"detox": "^8.1.1", "detox": "^8.1.1",
"fbjs": "^0.8.16", "fbjs": "^0.8.16",
"firebase-admin": "^5.12.0", "firebase-admin": "^5.12.0",

View File

@ -140,7 +140,7 @@ RCT_EXPORT_METHOD(getInitialLink:(RCTPromiseResolveBlock)resolve rejecter:(RCTPr
&& [self.bridge.launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey][UIApplicationLaunchOptionsUserActivityTypeKey] isEqualToString:NSUserActivityTypeBrowsingWeb]) { && [self.bridge.launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey][UIApplicationLaunchOptionsUserActivityTypeKey] isEqualToString:NSUserActivityTypeBrowsingWeb]) {
NSDictionary *dictionary = self.bridge.launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey]; NSDictionary *dictionary = self.bridge.launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey];
NSUserActivity* userActivity = (NSUserActivity*) dictionary[@"UIApplicationLaunchOptionsUserActivityKey"]; NSUserActivity* userActivity = (NSUserActivity*) dictionary[@"UIApplicationLaunchOptionsUserActivityKey"];
[[FIRDynamicLinks dynamicLinks] handleUniversalLink:userActivity.webpageURL BOOL handled = [[FIRDynamicLinks dynamicLinks] handleUniversalLink:userActivity.webpageURL
completion:^(FIRDynamicLink * _Nullable dynamicLink, NSError * _Nullable error) { completion:^(FIRDynamicLink * _Nullable dynamicLink, NSError * _Nullable error) {
if (error != nil){ if (error != nil){
NSLog(@"Failed to handle universal link: %@", [error localizedDescription]); NSLog(@"Failed to handle universal link: %@", [error localizedDescription]);
@ -151,6 +151,9 @@ RCT_EXPORT_METHOD(getInitialLink:(RCTPromiseResolveBlock)resolve rejecter:(RCTPr
resolve(urlString); resolve(urlString);
} }
}]; }];
if (!handled) {
resolve(nil);
}
} else { } else {
resolve(initialLink); resolve(initialLink);
} }

24
src/index.d.ts vendored
View File

@ -5,7 +5,7 @@
declare module 'react-native-firebase' { declare module 'react-native-firebase' {
/** 3rd party provider Credentials */ /** 3rd party provider Credentials */
type AuthCredential = { export type AuthCredential = {
providerId: string; providerId: string;
token: string; token: string;
secret: string; secret: string;
@ -974,7 +974,10 @@ declare module 'react-native-firebase' {
/** /**
* Asynchronously signs in using a phone number. * Asynchronously signs in using a phone number.
*/ */
signInWithPhoneNumber(phoneNumber: string, forceResend?: boolean): Promise<ConfirmationResult>; signInWithPhoneNumber(
phoneNumber: string,
forceResend?: boolean
): Promise<ConfirmationResult>;
/** /**
* Returns a PhoneAuthListener to listen to phone verification events, * Returns a PhoneAuthListener to listen to phone verification events,
@ -984,7 +987,7 @@ declare module 'react-native-firebase' {
verifyPhoneNumber( verifyPhoneNumber(
phoneNumber: string, phoneNumber: string,
autoVerifyTimeoutOrForceResend?: number | boolean, autoVerifyTimeoutOrForceResend?: number | boolean,
forceResend?: boolean, forceResend?: boolean
): PhoneAuthListener; ): PhoneAuthListener;
/** /**
@ -1665,7 +1668,7 @@ declare module 'react-native-firebase' {
/** /**
* Return an object of key-value attributes. * Return an object of key-value attributes.
*/ */
getAttributes(): Promise<Object> getAttributes(): Promise<Object>;
/** /**
* Set an attribute. Returns true if it was set, false if it was not. * Set an attribute. Returns true if it was set, false if it was not.
@ -1921,6 +1924,19 @@ declare module 'react-native-firebase' {
* @return The `HttpsCallable` instance. * @return The `HttpsCallable` instance.
*/ */
httpsCallable(name: string): HttpsCallable; httpsCallable(name: string): HttpsCallable;
/**
* Changes this instance to point to a Cloud Functions emulator running
* locally.
*
* See https://firebase.google.com/docs/functions/local-emulator
*
* @param origin the origin string of the local emulator started via firebase tools
* "http://10.0.0.8:1337".
*/
useFunctionsEmulator(origin: string): Promise<null>;
[key: string]: any;
} }
/** /**

View File

@ -41,8 +41,8 @@ export default class AdMob extends ModuleBase {
super(app, { super(app, {
events: NATIVE_EVENTS, events: NATIVE_EVENTS,
moduleName: MODULE_NAME, moduleName: MODULE_NAME,
multiApp: false, hasMultiAppSupport: false,
hasShards: false, hasCustomUrlSupport: false,
namespace: NAMESPACE, namespace: NAMESPACE,
}); });

View File

@ -33,8 +33,8 @@ export default class Analytics extends ModuleBase {
constructor(app: App) { constructor(app: App) {
super(app, { super(app, {
moduleName: MODULE_NAME, moduleName: MODULE_NAME,
multiApp: false, hasMultiAppSupport: false,
hasShards: false, hasCustomUrlSupport: false,
namespace: NAMESPACE, namespace: NAMESPACE,
}); });
} }

View File

@ -55,8 +55,8 @@ export default class Auth extends ModuleBase {
super(app, { super(app, {
events: NATIVE_EVENTS, events: NATIVE_EVENTS,
moduleName: MODULE_NAME, moduleName: MODULE_NAME,
multiApp: true, hasMultiAppSupport: true,
hasShards: false, hasCustomUrlSupport: false,
namespace: NAMESPACE, namespace: NAMESPACE,
}); });
this._user = null; this._user = null;

View File

@ -36,8 +36,8 @@ export default class RemoteConfig extends ModuleBase {
constructor(app: App) { constructor(app: App) {
super(app, { super(app, {
moduleName: MODULE_NAME, moduleName: MODULE_NAME,
multiApp: false, hasMultiAppSupport: false,
hasShards: false, hasCustomUrlSupport: false,
namespace: NAMESPACE, namespace: NAMESPACE,
}); });
this._developerModeEnabled = false; this._developerModeEnabled = false;

View File

@ -14,8 +14,8 @@ export default class Crashlytics extends ModuleBase {
constructor(app: App) { constructor(app: App) {
super(app, { super(app, {
moduleName: MODULE_NAME, moduleName: MODULE_NAME,
multiApp: false, hasMultiAppSupport: false,
hasShards: false, hasCustomUrlSupport: false,
namespace: NAMESPACE, namespace: NAMESPACE,
}); });
} }

View File

@ -32,35 +32,39 @@ export default class Database extends ModuleBase {
_serviceUrl: string; _serviceUrl: string;
constructor(appOrUrl: App | string, options: Object = {}) { constructor(appOrCustomUrl: App | string, customUrl?: string) {
let app; let app;
let serviceUrl; let url;
if (typeof appOrUrl === 'string') {
if (typeof appOrCustomUrl === 'string') {
app = firebase.app(); app = firebase.app();
serviceUrl = appOrUrl.endsWith('/') ? appOrUrl : `${appOrUrl}/`; url = appOrCustomUrl;
} else { } else {
app = appOrUrl; app = appOrCustomUrl;
serviceUrl = app.options.databaseURL; url = customUrl || app.options.databaseURL;
} }
// enforce trailing slash
url = url.endsWith('/') ? url : `${url}/`;
super( super(
app, app,
{ {
events: NATIVE_EVENTS, events: NATIVE_EVENTS,
moduleName: MODULE_NAME, moduleName: MODULE_NAME,
multiApp: true, hasMultiAppSupport: true,
hasShards: true, hasCustomUrlSupport: true,
namespace: NAMESPACE, namespace: NAMESPACE,
}, },
serviceUrl url
); );
this._serverTimeOffset = 0; this._serverTimeOffset = 0;
this._serviceUrl = serviceUrl; this._serviceUrl = serviceUrl;
this._transactionHandler = new TransactionHandler(this); this._transactionHandler = new TransactionHandler(this);
if (options.persistence) { if (app.options.persistence) {
getNativeModule(this).setPersistence(options.persistence); getNativeModule(this).setPersistence(app.options.persistence);
} }
// server time listener // server time listener

View File

@ -69,8 +69,8 @@ export default class Firestore extends ModuleBase {
super(app, { super(app, {
events: NATIVE_EVENTS, events: NATIVE_EVENTS,
moduleName: MODULE_NAME, moduleName: MODULE_NAME,
multiApp: true, hasMultiAppSupport: true,
hasShards: false, hasCustomUrlSupport: false,
namespace: NAMESPACE, namespace: NAMESPACE,
}); });

View File

@ -7,6 +7,8 @@ import { isObject } from '../../utils';
import { getNativeModule } from '../../utils/native'; import { getNativeModule } from '../../utils/native';
import type App from '../core/app'; import type App from '../core/app';
import firebase from '../core/firebase';
import HttpsError from './HttpsError'; import HttpsError from './HttpsError';
import type { import type {
@ -38,14 +40,32 @@ function errorOrResult(possibleError): HttpsCallablePromise {
return Promise.resolve(possibleError); return Promise.resolve(possibleError);
} }
/**
* -------------
* functions()
* -------------
*/
export default class Functions extends ModuleBase { export default class Functions extends ModuleBase {
constructor(app: App) { constructor(appOrRegion: App, region?: string = 'us-central1') {
super(app, { let _app = appOrRegion;
multiApp: false, let _region = region;
hasShards: false,
namespace: NAMESPACE, if (typeof _app === 'string') {
moduleName: MODULE_NAME, _region = _app;
}); _app = firebase.app();
}
super(
_app,
{
hasMultiAppSupport: true,
hasCustomUrlSupport: false,
hasRegionsSupport: true,
namespace: NAMESPACE,
moduleName: MODULE_NAME,
},
_region
);
} }
/** /**
@ -60,10 +80,26 @@ export default class Functions extends ModuleBase {
*/ */
httpsCallable(name: string): HttpsCallable { httpsCallable(name: string): HttpsCallable {
return (data?: any): HttpsCallablePromise => { return (data?: any): HttpsCallablePromise => {
const promise = getNativeModule(this).httpsCallable(name, { data }); const promise = getNativeModule(this).httpsCallable(name, {
data,
});
return promise.then(errorOrResult); return promise.then(errorOrResult);
}; };
} }
/**
* Changes this instance to point to a Cloud Functions emulator running
* locally.
*
* See https://firebase.google.com/docs/functions/local-emulator
*
* @param origin the origin string of the local emulator started via firebase tools
* "http://10.0.0.8:1337".
*/
useFunctionsEmulator(origin: string): Promise<null> {
return getNativeModule(this).useFunctionsEmulator(origin);
}
} }
export const statics: { HttpsErrorCode: HttpsErrorCode } = { export const statics: { HttpsErrorCode: HttpsErrorCode } = {

View File

@ -13,9 +13,9 @@ export const MODULE_NAME = 'RNFirebaseInstanceId';
export default class InstanceId extends ModuleBase { export default class InstanceId extends ModuleBase {
constructor(app: App) { constructor(app: App) {
super(app, { super(app, {
hasShards: false, hasCustomUrlSupport: false,
moduleName: MODULE_NAME, moduleName: MODULE_NAME,
multiApp: false, hasMultiAppSupport: false,
namespace: NAMESPACE, namespace: NAMESPACE,
}); });
} }

View File

@ -24,9 +24,9 @@ export default class Invites extends ModuleBase {
constructor(app: App) { constructor(app: App) {
super(app, { super(app, {
events: NATIVE_EVENTS, events: NATIVE_EVENTS,
hasShards: false, hasCustomUrlSupport: false,
moduleName: MODULE_NAME, moduleName: MODULE_NAME,
multiApp: false, hasMultiAppSupport: false,
namespace: NAMESPACE, namespace: NAMESPACE,
}); });

View File

@ -24,8 +24,8 @@ export default class Links extends ModuleBase {
super(app, { super(app, {
events: NATIVE_EVENTS, events: NATIVE_EVENTS,
moduleName: MODULE_NAME, moduleName: MODULE_NAME,
multiApp: false, hasMultiAppSupport: false,
hasShards: false, hasCustomUrlSupport: false,
namespace: NAMESPACE, namespace: NAMESPACE,
}); });

View File

@ -42,8 +42,8 @@ export default class Messaging extends ModuleBase {
super(app, { super(app, {
events: NATIVE_EVENTS, events: NATIVE_EVENTS,
moduleName: MODULE_NAME, moduleName: MODULE_NAME,
multiApp: false, hasMultiAppSupport: false,
hasShards: false, hasCustomUrlSupport: false,
namespace: NAMESPACE, namespace: NAMESPACE,
}); });

View File

@ -77,9 +77,9 @@ export default class Notifications extends ModuleBase {
constructor(app: App) { constructor(app: App) {
super(app, { super(app, {
events: NATIVE_EVENTS, events: NATIVE_EVENTS,
hasShards: false, hasCustomUrlSupport: false,
moduleName: MODULE_NAME, moduleName: MODULE_NAME,
multiApp: false, hasMultiAppSupport: false,
namespace: NAMESPACE, namespace: NAMESPACE,
}); });
this._android = new AndroidNotifications(this); this._android = new AndroidNotifications(this);

View File

@ -39,8 +39,8 @@ export default class PerformanceMonitoring extends ModuleBase {
constructor(app: App) { constructor(app: App) {
super(app, { super(app, {
moduleName: MODULE_NAME, moduleName: MODULE_NAME,
multiApp: false, hasMultiAppSupport: false,
hasShards: false, hasCustomUrlSupport: false,
namespace: NAMESPACE, namespace: NAMESPACE,
}); });
} }

View File

@ -30,8 +30,8 @@ export default class Storage extends ModuleBase {
super(app, { super(app, {
events: NATIVE_EVENTS, events: NATIVE_EVENTS,
moduleName: MODULE_NAME, moduleName: MODULE_NAME,
multiApp: true, hasMultiAppSupport: true,
hasShards: false, hasCustomUrlSupport: false,
namespace: NAMESPACE, namespace: NAMESPACE,
}); });

View File

@ -22,8 +22,8 @@ export default class RNFirebaseUtils extends ModuleBase {
constructor(app: App) { constructor(app: App) {
super(app, { super(app, {
moduleName: MODULE_NAME, moduleName: MODULE_NAME,
multiApp: false, hasMultiAppSupport: false,
hasShards: false, hasCustomUrlSupport: false,
namespace: NAMESPACE, namespace: NAMESPACE,
}); });
} }
@ -55,6 +55,11 @@ export default class RNFirebaseUtils extends ModuleBase {
} }
} }
getPlayServicesStatus(): Promise<GoogleApiAvailabilityType | null> {
if (isIOS) return Promise.resolve(null);
return FirebaseCoreModule.getPlayServicesStatus();
}
promptForPlayServices() { promptForPlayServices() {
if (isIOS) return null; if (isIOS) return null;
return FirebaseCoreModule.promptForPlayServices(); return FirebaseCoreModule.promptForPlayServices();

View File

@ -49,8 +49,9 @@ export type FirebaseModule = $Subtype<ModuleBase>;
export type FirebaseModuleConfig = { export type FirebaseModuleConfig = {
events?: string[], events?: string[],
moduleName: FirebaseModuleName, moduleName: FirebaseModuleName,
multiApp: boolean, hasMultiAppSupport: boolean,
hasShards: boolean, hasCustomUrlSupport: boolean,
hasRegionsSupport: boolean,
namespace: FirebaseNamespace, namespace: FirebaseNamespace,
}; };

View File

@ -10,7 +10,7 @@ import type { FirebaseModuleConfig, FirebaseNamespace } from '../types';
export default class ModuleBase { export default class ModuleBase {
_app: App; _app: App;
_serviceUrl: ?string; _customUrlOrRegion: ?string;
namespace: FirebaseNamespace; namespace: FirebaseNamespace;
@ -18,21 +18,29 @@ export default class ModuleBase {
* *
* @param app * @param app
* @param config * @param config
* @param customUrlOrRegion
*/ */
constructor(app: App, config: FirebaseModuleConfig, serviceUrl: ?string) { constructor(
app: App,
config: FirebaseModuleConfig,
customUrlOrRegion: ?string
) {
if (!config.moduleName) { if (!config.moduleName) {
throw new Error('Missing module name'); throw new Error('Missing module name');
} }
if (!config.namespace) { if (!config.namespace) {
throw new Error('Missing namespace'); throw new Error('Missing namespace');
} }
const { moduleName } = config; const { moduleName } = config;
this._app = app; this._app = app;
this._serviceUrl = serviceUrl; this._customUrlOrRegion = customUrlOrRegion;
this.namespace = config.namespace; this.namespace = config.namespace;
// check if native module exists as all native // check if native module exists as all native
initialiseNativeModule(this, config, serviceUrl); initialiseNativeModule(this, config, customUrlOrRegion);
initialiseLogger( initialiseLogger(
this, this,
`${app.name}:${moduleName.replace('RNFirebase', '')}` `${app.name}:${moduleName.replace('RNFirebase', '')}`

View File

@ -49,38 +49,50 @@ export default {
namespace: FirebaseNamespace, namespace: FirebaseNamespace,
InstanceClass: Class<M> InstanceClass: Class<M>
): () => FirebaseModule { ): () => FirebaseModule {
return (serviceUrl: ?string = null): M => { return (customUrlOrRegion: ?string = null): M => {
if (serviceUrl && namespace !== 'database') {
throw new Error(
INTERNALS.STRINGS.ERROR_INIT_SERVICE_URL_UNSUPPORTED(namespace)
);
}
const appOrShardName = serviceUrl || app.name;
if (!APP_MODULES[appOrShardName]) {
APP_MODULES[appOrShardName] = {};
}
if ( if (
isAndroid && customUrlOrRegion &&
namespace !== 'utils' && (namespace !== 'database' || namespace !== 'functions')
!INTERNALS.FLAGS.checkedPlayServices
) { ) {
INTERNALS.FLAGS.checkedPlayServices = true; throw new Error(
app.utils().checkPlayServicesAvailability(); INTERNALS.STRINGS.ERROR_INIT_SERVICE_URL_OR_REGION_UNSUPPORTED(
} namespace
)
if (!APP_MODULES[appOrShardName][namespace]) {
APP_MODULES[appOrShardName][namespace] = new InstanceClass(
serviceUrl || app,
app.options
); );
} }
return APP_MODULES[appOrShardName][namespace]; const appInstanceIdentifier = `${app.name}${customUrlOrRegion || ''}`;
if (!APP_MODULES[appInstanceIdentifier]) {
APP_MODULES[appInstanceIdentifier] = {};
}
if (!APP_MODULES[appInstanceIdentifier][namespace]) {
APP_MODULES[appInstanceIdentifier][namespace] = new InstanceClass(
app,
customUrlOrRegion
);
// only check once on new app namespace instance
if (
isAndroid &&
namespace !== 'utils' &&
!INTERNALS.FLAGS.checkedPlayServices
) {
INTERNALS.FLAGS.checkedPlayServices = true;
app.utils().checkPlayServicesAvailability();
}
}
return APP_MODULES[appInstanceIdentifier][namespace];
}; };
}, },
/**
*
* @param name
* @returns {*}
*/
deleteApp(name: string): Promise<boolean> { deleteApp(name: string): Promise<boolean> {
const app = APPS[name]; const app = APPS[name];
if (!app) return Promise.resolve(true); if (!app) return Promise.resolve(true);
@ -173,24 +185,34 @@ export default {
statics: S, statics: S,
moduleName: FirebaseModuleName moduleName: FirebaseModuleName
): FirebaseModuleAndStatics<M, S> { ): FirebaseModuleAndStatics<M, S> {
const getModule = (appOrUrl?: App | string): FirebaseModule => { const getModule = (
let _app = appOrUrl; appOrUrlOrRegion?: App | string,
let _serviceUrl: ?string = null; customUrlOrRegion?: string
if (typeof appOrUrl === 'string' && namespace === 'database') { ): FirebaseModule => {
let _app = appOrUrlOrRegion;
let _customUrlOrRegion: ?string = customUrlOrRegion || null;
if (typeof appOrUrlOrRegion === 'string' && namespace === 'database') {
_app = null; _app = null;
_serviceUrl = appOrUrl; _customUrlOrRegion = appOrUrlOrRegion;
}
if (typeof appOrUrlOrRegion === 'string' && namespace === 'functions') {
_app = null;
_customUrlOrRegion = appOrUrlOrRegion;
} }
// throw an error if it's not a valid app instance // throw an error if it's not a valid app instance
if (_app && !(_app instanceof App)) if (_app && !(_app instanceof App)) {
throw new Error(INTERNALS.STRINGS.ERROR_NOT_APP(namespace)); throw new Error(INTERNALS.STRINGS.ERROR_NOT_APP(namespace));
else if (!_app) } else if (!_app) {
// default to the 'DEFAULT' app if no arg provided - will throw an error // default to the 'DEFAULT' app if no arg provided - will throw an error
// if default app not initialized // if default app not initialized
_app = this.app(DEFAULT_APP_NAME); _app = this.app(DEFAULT_APP_NAME);
}
// $FlowExpectedError: Flow doesn't support indexable signatures on classes: https://github.com/facebook/flow/issues/1323 // $FlowExpectedError: Flow doesn't support indexable signatures on classes: https://github.com/facebook/flow/issues/1323
const module = _app[namespace]; const module = _app[namespace];
return module(_serviceUrl); return module(_customUrlOrRegion);
}; };
return Object.assign(getModule, statics, { return Object.assign(getModule, statics, {

View File

@ -23,9 +23,11 @@ const getNativeEmitter = (
): NativeEventEmitter => { ): NativeEventEmitter => {
const name = `${module.app.name}-${moduleName}`; const name = `${module.app.name}-${moduleName}`;
const nativeModule = NativeModules[moduleName]; const nativeModule = NativeModules[moduleName];
if (!NATIVE_EMITTERS[name]) { if (!NATIVE_EMITTERS[name]) {
NATIVE_EMITTERS[name] = new NativeEventEmitter(nativeModule); NATIVE_EMITTERS[name] = new NativeEventEmitter(nativeModule);
} }
return NATIVE_EMITTERS[name]; return NATIVE_EMITTERS[name];
}; };
@ -35,6 +37,7 @@ const getNativeEmitter = (
* so we use a single event send it to js and js then internally can prefix it * so we use a single event send it to js and js then internally can prefix it
* and distribute dynamically. * and distribute dynamically.
* *
* @param moduleName
* @param module * @param module
* @param eventName * @param eventName
* @private * @private
@ -65,6 +68,7 @@ export const initialiseNativeModuleEventEmitter = (
config: FirebaseModuleConfig config: FirebaseModuleConfig
): void => { ): void => {
const { events, moduleName } = config; const { events, moduleName } = config;
if (events && events.length) { if (events && events.length) {
for (let i = 0, len = events.length; i < len; i++) { for (let i = 0, len = events.length; i < len; i++) {
subscribeToNativeModuleEvents(moduleName, module, events[i]); subscribeToNativeModuleEvents(moduleName, module, events[i]);

View File

@ -100,8 +100,8 @@ export default {
/** /**
* @return {string} * @return {string}
*/ */
ERROR_INIT_SERVICE_URL_UNSUPPORTED(namespace: string) { ERROR_INIT_SERVICE_URL_OR_REGION_UNSUPPORTED(namespace: string) {
return `${namespace} does not support URL as a param, please pass in an app.`; return `${namespace} does not support a URL or region as a param, please pass in an app.`;
}, },
/** /**

View File

@ -32,7 +32,7 @@ const nativeWithArgs = (
}; };
const nativeModuleKey = (module: ModuleBase): string => const nativeModuleKey = (module: ModuleBase): string =>
`${module._serviceUrl || module.app.name}:${module.namespace}`; `${module._customUrlOrRegion || module.app.name}:${module.namespace}`;
export const getNativeModule = (module: ModuleBase): Object => export const getNativeModule = (module: ModuleBase): Object =>
NATIVE_MODULES[nativeModuleKey(module)]; NATIVE_MODULES[nativeModuleKey(module)];
@ -40,9 +40,15 @@ export const getNativeModule = (module: ModuleBase): Object =>
export const initialiseNativeModule = ( export const initialiseNativeModule = (
module: ModuleBase, module: ModuleBase,
config: FirebaseModuleConfig, config: FirebaseModuleConfig,
serviceUrl: ?string customUrlOrRegion: ?string
): Object => { ): Object => {
const { moduleName, multiApp, hasShards, namespace } = config; const {
moduleName,
hasMultiAppSupport,
hasCustomUrlSupport,
hasRegionsSupport,
namespace,
} = config;
const nativeModule = NativeModules[moduleName]; const nativeModule = NativeModules[moduleName];
const key = nativeModuleKey(module); const key = nativeModuleKey(module);
@ -55,11 +61,13 @@ export const initialiseNativeModule = (
// used by the modules that extend ModuleBase // used by the modules that extend ModuleBase
// to access their native module counterpart // to access their native module counterpart
const argToPrepend = []; const argToPrepend = [];
if (multiApp) {
if (hasMultiAppSupport) {
argToPrepend.push(module.app.name); argToPrepend.push(module.app.name);
} }
if (hasShards) {
argToPrepend.push(serviceUrl); if (hasCustomUrlSupport || hasRegionsSupport) {
argToPrepend.push(customUrlOrRegion);
} }
if (argToPrepend.length) { if (argToPrepend.length) {