mirror of
https://github.com/zhigang1992/react-native-firebase.git
synced 2026-04-24 04:24:52 +08:00
started work on multiple app initialization
This commit is contained in:
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();
|
||||
|
||||
Reference in New Issue
Block a user