2015-01-30 01:10:49 +00:00
|
|
|
/**
|
2015-03-23 22:07:33 +00:00
|
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the BSD-style license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
2015-01-30 01:10:49 +00:00
|
|
|
*
|
2015-02-19 14:57:05 +00:00
|
|
|
* @providesModule AppRegistry
|
2015-03-25 02:34:12 +00:00
|
|
|
* @flow
|
2015-01-30 01:10:49 +00:00
|
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
|
2015-12-08 23:57:34 +00:00
|
|
|
var BatchedBridge = require('BatchedBridge');
|
2016-04-20 15:07:43 +00:00
|
|
|
var BugReporting = require('BugReporting');
|
2016-10-15 01:50:14 +00:00
|
|
|
var ReactNative = require('ReactNative');
|
2015-12-08 23:57:34 +00:00
|
|
|
|
2016-09-29 10:43:59 +00:00
|
|
|
const infoLog = require('infoLog');
|
2016-03-02 12:27:13 +00:00
|
|
|
var invariant = require('fbjs/lib/invariant');
|
2015-01-30 01:10:49 +00:00
|
|
|
var renderApplication = require('renderApplication');
|
2016-09-29 10:43:59 +00:00
|
|
|
|
|
|
|
const { HeadlessJsTaskSupport } = require('NativeModules');
|
2015-01-30 01:10:49 +00:00
|
|
|
|
|
|
|
if (__DEV__) {
|
|
|
|
// In order to use Cmd+P to record/dump perf data, we need to make sure
|
|
|
|
// this module is available in the bundle
|
|
|
|
require('RCTRenderingPerf');
|
|
|
|
}
|
|
|
|
|
2016-09-29 10:43:59 +00:00
|
|
|
type Task = (taskData: any) => Promise<void>;
|
|
|
|
type TaskProvider = () => Task;
|
|
|
|
|
2015-01-30 01:10:49 +00:00
|
|
|
var runnables = {};
|
2016-04-21 03:44:28 +00:00
|
|
|
var runCount = 1;
|
2016-09-29 10:43:59 +00:00
|
|
|
const tasks: Map<string, TaskProvider> = new Map();
|
2015-01-30 01:10:49 +00:00
|
|
|
|
2016-03-08 20:38:52 +00:00
|
|
|
type ComponentProvider = () => ReactClass<any>;
|
2015-07-29 16:53:13 +00:00
|
|
|
|
2015-03-25 02:34:12 +00:00
|
|
|
type AppConfig = {
|
2016-08-09 13:32:41 +00:00
|
|
|
appKey: string,
|
|
|
|
component?: ComponentProvider,
|
|
|
|
run?: Function,
|
2015-03-25 02:34:12 +00:00
|
|
|
};
|
|
|
|
|
2015-02-19 14:57:05 +00:00
|
|
|
/**
|
|
|
|
* `AppRegistry` is the JS entry point to running all React Native apps. App
|
|
|
|
* root components should register themselves with
|
|
|
|
* `AppRegistry.registerComponent`, then the native system can load the bundle
|
|
|
|
* for the app and then actually run the app when it's ready by invoking
|
|
|
|
* `AppRegistry.runApplication`.
|
|
|
|
*
|
2015-12-08 23:57:34 +00:00
|
|
|
* To "stop" an application when a view should be destroyed, call
|
|
|
|
* `AppRegistry.unmountApplicationComponentAtRootTag` with the tag that was
|
2016-12-16 18:15:07 +00:00
|
|
|
* passed into `runApplication`. These should always be used as a pair.
|
2015-12-08 23:57:34 +00:00
|
|
|
*
|
2015-02-19 14:57:05 +00:00
|
|
|
* `AppRegistry` should be `require`d early in the `require` sequence to make
|
|
|
|
* sure the JS execution environment is setup before other modules are
|
|
|
|
* `require`d.
|
|
|
|
*/
|
|
|
|
var AppRegistry = {
|
2015-03-25 02:34:12 +00:00
|
|
|
registerConfig: function(config: Array<AppConfig>) {
|
2015-01-30 01:10:49 +00:00
|
|
|
for (var i = 0; i < config.length; ++i) {
|
2015-03-25 02:34:12 +00:00
|
|
|
var appConfig = config[i];
|
|
|
|
if (appConfig.run) {
|
|
|
|
AppRegistry.registerRunnable(appConfig.appKey, appConfig.run);
|
2015-01-30 01:10:49 +00:00
|
|
|
} else {
|
2015-07-29 16:53:13 +00:00
|
|
|
invariant(appConfig.component, 'No component provider passed in');
|
2015-03-25 02:34:12 +00:00
|
|
|
AppRegistry.registerComponent(appConfig.appKey, appConfig.component);
|
2015-01-30 01:10:49 +00:00
|
|
|
}
|
|
|
|
}
|
2015-02-19 14:57:05 +00:00
|
|
|
},
|
2015-01-30 01:10:49 +00:00
|
|
|
|
2015-07-29 16:53:13 +00:00
|
|
|
registerComponent: function(appKey: string, getComponentFunc: ComponentProvider): string {
|
2015-01-30 01:10:49 +00:00
|
|
|
runnables[appKey] = {
|
|
|
|
run: (appParameters) =>
|
|
|
|
renderApplication(getComponentFunc(), appParameters.initialProps, appParameters.rootTag)
|
|
|
|
};
|
|
|
|
return appKey;
|
2015-02-19 14:57:05 +00:00
|
|
|
},
|
2015-01-30 01:10:49 +00:00
|
|
|
|
2015-03-25 02:34:12 +00:00
|
|
|
registerRunnable: function(appKey: string, func: Function): string {
|
2015-01-30 01:10:49 +00:00
|
|
|
runnables[appKey] = {run: func};
|
|
|
|
return appKey;
|
2015-02-19 14:57:05 +00:00
|
|
|
},
|
2015-01-30 01:10:49 +00:00
|
|
|
|
2015-08-07 18:50:23 +00:00
|
|
|
getAppKeys: function(): Array<string> {
|
|
|
|
return Object.keys(runnables);
|
|
|
|
},
|
|
|
|
|
2015-03-25 02:34:12 +00:00
|
|
|
runApplication: function(appKey: string, appParameters: any): void {
|
2016-04-20 15:07:43 +00:00
|
|
|
const msg =
|
2015-03-11 02:11:28 +00:00
|
|
|
'Running application "' + appKey + '" with appParams: ' +
|
|
|
|
JSON.stringify(appParameters) + '. ' +
|
2015-06-22 16:43:30 +00:00
|
|
|
'__DEV__ === ' + String(__DEV__) +
|
2015-03-11 02:11:28 +00:00
|
|
|
', development-level warning are ' + (__DEV__ ? 'ON' : 'OFF') +
|
2016-04-20 15:07:43 +00:00
|
|
|
', performance optimizations are ' + (__DEV__ ? 'OFF' : 'ON');
|
2016-05-17 19:42:17 +00:00
|
|
|
infoLog(msg);
|
2016-04-21 03:44:28 +00:00
|
|
|
BugReporting.addSource('AppRegistry.runApplication' + runCount++, () => msg);
|
2015-01-30 01:10:49 +00:00
|
|
|
invariant(
|
|
|
|
runnables[appKey] && runnables[appKey].run,
|
2015-05-31 19:53:54 +00:00
|
|
|
'Application ' + appKey + ' has not been registered. This ' +
|
|
|
|
'is either due to a require() error during initialization ' +
|
|
|
|
'or failure to call AppRegistry.registerComponent.'
|
2015-01-30 01:10:49 +00:00
|
|
|
);
|
|
|
|
runnables[appKey].run(appParameters);
|
2015-02-19 14:57:05 +00:00
|
|
|
},
|
2015-12-08 23:57:34 +00:00
|
|
|
|
|
|
|
unmountApplicationComponentAtRootTag: function(rootTag : number) {
|
|
|
|
ReactNative.unmountComponentAtNodeAndRemoveContainer(rootTag);
|
|
|
|
},
|
|
|
|
|
2016-09-29 10:43:59 +00:00
|
|
|
/**
|
|
|
|
* Register a headless task. A headless task is a bit of code that runs without a UI.
|
|
|
|
* @param taskKey the key associated with this task
|
|
|
|
* @param task a promise returning function that takes some data passed from the native side as
|
|
|
|
* the only argument; when the promise is resolved or rejected the native side is
|
|
|
|
* notified of this event and it may decide to destroy the JS context.
|
|
|
|
*/
|
|
|
|
registerHeadlessTask: function(taskKey: string, task: TaskProvider): void {
|
|
|
|
if (tasks.has(taskKey)) {
|
|
|
|
console.warn(`registerHeadlessTask called multiple times for same key '${taskKey}'`);
|
|
|
|
}
|
|
|
|
tasks.set(taskKey, task);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Only called from native code. Starts a headless task.
|
|
|
|
*
|
|
|
|
* @param taskId the native id for this task instance to keep track of its execution
|
|
|
|
* @param taskKey the key for the task to start
|
|
|
|
* @param data the data to pass to the task
|
|
|
|
*/
|
|
|
|
startHeadlessTask: function(taskId: number, taskKey: string, data: any): void {
|
|
|
|
const taskProvider = tasks.get(taskKey);
|
|
|
|
if (!taskProvider) {
|
|
|
|
throw new Error(`No task registered for key ${taskKey}`);
|
|
|
|
}
|
|
|
|
taskProvider()(data)
|
|
|
|
.then(() => HeadlessJsTaskSupport.notifyTaskFinished(taskId))
|
|
|
|
.catch(reason => {
|
|
|
|
console.error(reason);
|
|
|
|
HeadlessJsTaskSupport.notifyTaskFinished(taskId);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2015-02-19 14:57:05 +00:00
|
|
|
};
|
2015-01-30 01:10:49 +00:00
|
|
|
|
2015-12-08 23:57:34 +00:00
|
|
|
BatchedBridge.registerCallableModule(
|
|
|
|
'AppRegistry',
|
|
|
|
AppRegistry
|
|
|
|
);
|
|
|
|
|
2015-02-19 14:57:05 +00:00
|
|
|
module.exports = AppRegistry;
|