
react-native.js 其實(shí)就是聲明了ReactNative提供的可以在js中使用的各種模塊。
var ReactNative = Object.assign(Object.create(require('React')), {
...
ToastAndroid: require('ToastAndroid'),
});
module.exports = ReactNative;
ToastAndroid.android.js show方法其實(shí)就是調(diào)用了RCTToastAndroid.show(message, duration)
var RCTToastAndroid = require('NativeModules').ToastAndroid;
var ToastAndroid = {
SHORT: RCTToastAndroid.SHORT,
LONG: RCTToastAndroid.LONG,
show: function (
message: string,
duration: number
): void {
RCTToastAndroid.show(message, duration);
},
};
NativeModules.js RCTToastAndroid是定義在NativeModules中的
var NativeModules = require('BatchedBridge').RemoteModules;
var nativeModulePrefixNormalizer = require('nativeModulePrefixNormalizer');
nativeModulePrefixNormalizer(NativeModules);
module.exports = NativeModules;
BatchedBridge.js 最終,所有的模塊都是來(lái)自BatchedBridge,它做的事情就是構(gòu)造一個(gè)MessageQueue對(duì)象。
let MessageQueue = require('MessageQueue');
let BatchedBridge = new MessageQueue(
__fbBatchedBridgeConfig.remoteModuleConfig,
__fbBatchedBridgeConfig.localModulesConfig,
);
module.exports = BatchedBridge;
ToastAndroid.show方法其實(shí)最終調(diào)用的是MessageQueue.ToastAndroid.show方法。
__fbBatchedBridgeConfig 是一個(gè)全局js變量,它是在CatalystInstance.java中聲明賦值的,通過(guò)調(diào)用ReactBridge.setGlobalVariable方法。setGlobalVariable是在Jni中聲明的方法,最終會(huì)調(diào)用JavaScriptCore,把Java中定義的JSON字符串,賦值給js的全局對(duì)象__fbBatchedBridgeConfig,這個(gè)對(duì)象會(huì)有兩個(gè)屬性remoteModuleConfig和localModulesConfig。
__fbBatchedBridgeConfig.remoteModuleConfig,
__fbBatchedBridgeConfig.localModulesConfig,
CatalystInstanceImpl.java
private native void initializeBridge(
ReactCallback callback,
JavaScriptExecutor jsExecutor,
MessageQueueThread jsQueue,
MessageQueueThread moduleQueue,
Collection<JavaModuleWrapper> javaModules,
Collection<ModuleHolder> cxxModules);
private void initializeBridge(
JavaScriptExecutor jsExecutor,
NativeModuleRegistry registry,
JavaScriptModulesConfig jsModulesConfig,
JSBundleLoader jsBundleLoader) {
mCatalystQueueConfiguration.getJSQueueThread().assertIsOnThread();
Assertions.assertCondition(mBridge == null, "initializeBridge should be called once");
mBridge = new ReactBridge(
jsExecutor,
new NativeModulesReactCallback(),
mCatalystQueueConfiguration.getNativeModulesQueueThread());
mBridge.setGlobalVariable(
"__fbBatchedBridgeConfig",
buildModulesConfigJSONProperty(registry, jsModulesConfig));
jsBundleLoader.loadScript(mBridge);
}
__fbBatchedBridgeConfig.remoteModuleConfig 代表的是Java中定義的一些模塊,這些模塊可以在js中被調(diào)用。格式如下:
{
"remoteModuleConfig": {
"Logger": {
"constants": { /* If we had exported constants... */ },
"moduleID": 1,
"methods": {
"requestPermissions": {
"type": "remote",
"methodID": 1
}
}
}
}
}
{
'ToastAndroid': {
moduleId: 0,
methods: {
'show': {
methodID: 0
}
},
constants: {
'SHORT': '0',
'LONG': '1'
}
},
'moduleB': {
moduleId: 0,
methods: {
'method1': {
methodID: 0
}
},
'key1': 'value1',
'key2': 'value2'
}
}
MessageQueue.js 構(gòu)造函數(shù)中首先定義了一些實(shí)例變量,注釋里面的js module指的是只在js中定義的模塊,native module指的是在native(這里就是Java)層定義的模塊,這些模塊都可以在js中使用。
this.RemoteModules = {};//存儲(chǔ)最終生成的各個(gè)模塊信息,包含模塊名,模塊中的方法,常量等信息
this._require = customRequire || require;//用于加載模塊的函數(shù)
this._queue = [[],[],[]];//隊(duì)列,用于存放調(diào)用的模塊,方法和參數(shù)信息,分別存儲(chǔ)在第一二三個(gè)數(shù)組中
this._moduleTable = {};//moduleId查找moduleName的map,用于js module
this._methodTable = {};//methodId查找methodName的map,用于js module
this._callbacks = [];//回調(diào)函數(shù)數(shù)組,和queue一一對(duì)應(yīng),每個(gè)queue中調(diào)用的方法,如果有回調(diào)函數(shù),那么就在這個(gè)數(shù)組的對(duì)應(yīng)坐標(biāo)上
this._callbackID = 0;//回調(diào)函數(shù)的id,自增
this._genModules(remoteModules);
localModules && this._genLookupTables(
localModules, this._moduleTable, this._methodTable);
this._debugInfo = {};//放置一些debug相關(guān)的信息,主要是調(diào)用模塊,函數(shù),參數(shù)的信息
this._remoteModuleTable = {};//moduleId查找moduleName的map,用于native module
this._remoteMethodTable = {};//methodId查找methodName的map,用于native module
this._genLookupTables(
remoteModules, this._remoteModuleTable, this._remoteMethodTable);
_genModules(remoteModules) 遍歷傳過(guò)來(lái)的remoteModules所有的key,得到moduleName,然后針對(duì)每個(gè)module調(diào)用_genModule方法
_genModules(remoteModules) {
let moduleNames = Object.keys(remoteModules);
for (var i = 0, l = moduleNames.length; i < l; i++) {
let moduleName = moduleNames[i];
let moduleConfig = remoteModules[moduleName];
this.RemoteModules[moduleName] = this._genModule({}, moduleConfig);
}
}
_genModule(module, moduleConfig) _genModule方法和_genModules方法類似,遍歷module下面的所有的方法,對(duì)每個(gè)方法,調(diào)用_genMethod方法。
_genModule(module, moduleConfig) {
let methodNames = Object.keys(moduleConfig.methods);
for (var i = 0, l = methodNames.length; i < l; i++) {
let methodName = methodNames[i];
let methodConfig = moduleConfig.methods[methodName];
module[methodName] = this._genMethod(
moduleConfig.moduleID, methodConfig.methodID, methodConfig.type);
}
Object.assign(module, moduleConfig.constants);
return module;
}
_genMethod(module, method, type) {
...
fn = function(...args) {
let lastArg = args.length > 0 ? args[args.length - 1] : null;
let secondLastArg = args.length > 1 ? args[args.length - 2] : null;
let hasSuccCB = typeof lastArg === 'function';
let hasErrorCB = typeof secondLastArg === 'function';
hasErrorCB && invariant(
hasSuccCB,
'Cannot have a non-function arg after a function arg.'
);
let numCBs = hasSuccCB + hasErrorCB;
let onSucc = hasSuccCB ? lastArg : null;
let onFail = hasErrorCB ? secondLastArg : null;
args = args.slice(0, args.length - numCBs);
return self.__nativeCall(module, method, args, onFail, onSucc);
};
}
__nativeCall(module, method, params, onFail, onSucc)
- 方法首先檢查是否有onFail和onSucc,如果有的話就壓入_callbacks棧中,同時(shí)把_callbackID存入?yún)?shù)中。
- 接著可以看到,_queue其實(shí)被當(dāng)做了三個(gè)棧來(lái)使用,分別壓入模塊名,方法名和參數(shù)信息。
- 到這里MessageQueue的構(gòu)造函數(shù)就分析的差不多了,那么我們最開(kāi)始的ToastAndroid.show(message, duration);方法調(diào)用,其實(shí)就是往_queue棧中壓入了一些信息而已,那么最終是怎么在Java層調(diào)用到Android原生的Toast模塊的呢?
__nativeCall(module, method, params, onFail, onSucc) {
if (onFail || onSucc) {
// eventually delete old debug info
(this._callbackID > (1 << 5)) &&
(this._debugInfo[this._callbackID >> 5] = null);
this._debugInfo[this._callbackID >> 1] = [module, method];
onFail && params.push(this._callbackID);
this._callbacks[this._callbackID++] = onFail;
onSucc && params.push(this._callbackID);
this._callbacks[this._callbackID++] = onSucc;
}
this._queue[MODULE_IDS].push(module);
this._queue[METHOD_IDS].push(method);
this._queue[PARAMS].push(params);
var now = new Date().getTime();
if (global.nativeFlushQueueImmediate &&
now - this._lastFlush >= MIN_TIME_BETWEEN_FLUSHES_MS) {
global.nativeFlushQueueImmediate(this._queue);
this._queue = [[],[],[]];
this._lastFlush = now;
}
if (__DEV__ && SPY_MODE && isFinite(module)) {
console.log('JS->N : ' + this._remoteModuleTable[module] + '.' +
this._remoteMethodTable[module][method] + '(' + JSON.stringify(params) + ')');
}
}
- 這里的關(guān)鍵就是__nativeCall中調(diào)用的nativeFlushQueueImmediate方法,這個(gè)方法其實(shí)C++代碼中注入到Js的一個(gè)全局變量,具體怎么注入的,就是在JSCExecutor.cpp中調(diào)用installGlobalFunction,installGlobalFunction的是通過(guò)JavaScriptCore的API來(lái)實(shí)現(xiàn)讓Js可以調(diào)用C++代碼的。
- nativeFlushQueueImmediate其實(shí)又調(diào)用了JSCExecutor.cpp中的flushQueueImmediate方法。
- 其中,m_flushImmediateCallback是在JSCExecutor的構(gòu)造函數(shù)中初始化。
- 那么JSCExecutor對(duì)象又是在哪了被創(chuàng)建出來(lái)的呢?RN中是通過(guò)JSCExecutorFactory這個(gè)工廠的createJSExecutor方法來(lái)創(chuàng)建JSCExecutor對(duì)象的,而這個(gè)方法的實(shí)現(xiàn)剛好就在JSCExecutor.cpp中。
JSCExecutor.cpp
JSCExecutor::JSCExecutor(FlushImmediateCallback cb) :
m_flushImmediateCallback(cb) {}
installGlobalFunction(m_context, "nativeFlushQueueImmediate", nativeFlushQueueImmediate);
installGlobalFunction(m_context, "nativeLoggingHook", nativeLoggingHook);
installGlobalFunction(m_context, "nativePerformanceNow", nativePerformanceNow);
void JSCExecutor::flushQueueImmediate(std::string queueJSON) {
m_flushImmediateCallback(queueJSON);
}
std::unique_ptr<JSExecutor> JSCExecutorFactory::createJSExecutor(FlushImmediateCallback cb) {
return std::unique_ptr<JSExecutor>(new JSCExecutor(cb));
}
- 接下來(lái)問(wèn)題又來(lái)了,又是誰(shuí)調(diào)用了JSCExecutorFactory.createJSExecutor呢?答案就是Bridge.cpp,
- Bridge.cpp是RN的Jni層的入口,Java層大部分調(diào)用的Jni函數(shù)都是在這個(gè)文件中定義的。
Bridge.cpp
Bridge::Bridge(const RefPtr<JSExecutorFactory>& jsExecutorFactory, Callback callback) :
m_threadState.reset(new JSThreadState(jsExecutorFactory, std::move(proxyCallback)));
JSThreadState(const RefPtr<JSExecutorFactory>& jsExecutorFactory, Bridge::Callback&& callback) :
m_callback(callback)
{
m_jsExecutor = jsExecutorFactory->createJSExecutor([this, callback] (std::string queueJSON) {
m_callback(parseMethodCalls(queueJSON), false /* = isEndOfBatch */);
});
}
ReactBridge.java回去調(diào)用jni中注冊(cè)的initialize方法。RN所有jni中注冊(cè)的方法,都在OnLoad.cpp。
OnLoad.cpp 可以看到initialize方法其實(shí)就是OnLoad.cpp中的bridge這個(gè)namespace下得create方法
registerNatives("com/facebook/react/bridge/ReactBridge", {
makeNativeMethod("initialize", "(Lcom/facebook/react/bridge/JavaScriptExecutor;Lcom/facebook/react/bridge/ReactCallback;Lcom/facebook/react/bridge/queue/MessageQueueThread;)V", bridge::create),
makeNativeMethod(
"loadScriptFromAssets", "(Landroid/content/res/AssetManager;Ljava/lang/String;)V",
bridge::loadScriptFromAssets),
makeNativeMethod("loadScriptFromFile", bridge::loadScriptFromFile),
makeNativeMethod("callFunction", bridge::callFunction),
makeNativeMethod("invokeCallback", bridge::invokeCallback),
makeNativeMethod("setGlobalVariable", bridge::setGlobalVariable),
makeNativeMethod("supportsProfiling", bridge::supportsProfiling),
makeNativeMethod("startProfiler", bridge::startProfiler),
makeNativeMethod("stopProfiler", bridge::stopProfiler),
makeNativeMethod("handleMemoryPressureModerate", bridge::handleMemoryPressureModerate),
makeNativeMethod("handleMemoryPressureCritical", bridge::handleMemoryPressureCritical),
});
static void create(JNIEnv* env, jobject obj, jobject executor, jobject callback,
jobject callbackQueueThread) {
auto weakCallback = createNew<WeakReference>(callback);
auto weakCallbackQueueThread = createNew<WeakReference>(callbackQueueThread);
auto bridgeCallback = [weakCallback, weakCallbackQueueThread] (std::vector<MethodCall> calls, bool isEndOfBatch) {
dispatchCallbacksToJava(weakCallback, weakCallbackQueueThread, std::move(calls), isEndOfBatch);
};
auto nativeExecutorFactory = extractRefPtr<JSExecutorFactory>(env, executor);
auto bridge = createNew<Bridge>(nativeExecutorFactory, bridgeCallback);
setCountableForJava(env, obj, std::move(bridge));
}
這里調(diào)用了Bridge類的構(gòu)造函數(shù),而B(niǎo)ridge的構(gòu)造函數(shù)中,回去構(gòu)造一個(gè)JSThreadState對(duì)象,Bridge所有的API調(diào)用都會(huì)委托給這個(gè)創(chuàng)建的JSThreadState對(duì)象。
Bridge::Bridge(const RefPtr<JSExecutorFactory>& jsExecutorFactory, Callback callback) :
m_callback(callback),
m_destroyed(std::shared_ptr<bool>(new bool(false)))
{
auto destroyed = m_destroyed;
auto proxyCallback = [this, destroyed] (std::vector<MethodCall> calls, bool isEndOfBatch) {
if (*destroyed) {
return;
}
m_callback(std::move(calls), isEndOfBatch);
};
m_threadState.reset(new JSThreadState(jsExecutorFactory, std::move(proxyCallback)));
}
- JSThreadState的構(gòu)造函數(shù)中,會(huì)去創(chuàng)建一個(gè)JSCExecutor類的對(duì)象
- 這里createJSExecutor方法中,傳遞的是一個(gè)C++的函數(shù),這個(gè)函數(shù)會(huì)被賦值給m_flushImmediateCallback成員變量。
JSThreadState(const RefPtr<JSExecutorFactory>& jsExecutorFactory, Bridge::Callback&& callback) :
m_callback(callback)
{
m_jsExecutor = jsExecutorFactory->createJSExecutor([this, callback] (std::string queueJSON) {
m_callback(parseMethodCalls(queueJSON), false /* = isEndOfBatch */);
});
}
找到了創(chuàng)建JSCExecutor對(duì)象的地方了,回到剛才,我們說(shuō),所有的Js調(diào)用Native Module的API的時(shí)候,都會(huì)調(diào)用flushQueueImmediate方法,而flushQueueImmediate方法中會(huì)去調(diào)用m_flushImmediateCallback函數(shù)。
JSCExecutor::JSCExecutor(FlushImmediateCallback cb) :
m_flushImmediateCallback(cb) {
std::unique_ptr<JSExecutor> JSCExecutorFactory::createJSExecutor(FlushImmediateCallback cb) {
return std::unique_ptr<JSExecutor>(new JSCExecutor(cb));
}
也就是說(shuō),Js層所有的API調(diào)用,都會(huì)走到這個(gè)m_flushImmediateCallback函數(shù)的調(diào)用中,這個(gè)函數(shù)是實(shí)現(xiàn)Js和Native通訊的核心。而這里的m_flushImmediateCallback在CPP層,最終是在OnLoad.cpp的bridge::create方法中傳入的,這個(gè)create方法又是由Java層來(lái)調(diào)用的,Bridge.java的構(gòu)造函數(shù)中會(huì)調(diào)用這個(gè)create方法,所以說(shuō),Js層調(diào)用Native API的時(shí)候,最終就是調(diào)用了Bridge.java中傳遞過(guò)來(lái)的ReactCallback對(duì)象
public ReactBridge(
JavaScriptExecutor jsExecutor,
ReactCallback callback,
MessageQueueThread nativeModulesQueueThread) {
.....
}
- ReactBridge對(duì)象的創(chuàng)建,是在CatalystInstanceImpl.java中
- 這里傳遞的是ReactCallback類的子類NativeModulesReactCallback,最終調(diào)用的是call方法,而call方法又調(diào)用了mJavaRegistry.call方法??吹絤JavaRegistry,開(kāi)發(fā)過(guò)RN應(yīng)用的同學(xué)應(yīng)該感到很熟悉了,對(duì)的,這里就是對(duì)應(yīng)我們?cè)趹?yīng)用啟動(dòng)的時(shí)候注冊(cè)的NativeModule對(duì)象。
private ReactBridge initializeBridge
bridge = new ReactBridge(
jsExecutor,
new NativeModulesReactCallback(),
mCatalystQueueConfiguration.getNativeModulesQueueThread());
private class NativeModulesReactCallback implements ReactCallback {
public void call(int moduleId, int methodId, ReadableNativeArray parameters) {
mJavaRegistry.call(CatalystInstanceImpl.this, moduleId, methodId, parameters);
}
}
NativeModuleRegistry.Java
/* package */ void call(
CatalystInstance catalystInstance,
int moduleId,
int methodId,
ReadableNativeArray parameters) {
ModuleDefinition definition = mModuleTable.get(moduleId);
if (definition == null) {
throw new RuntimeException("Call to unknown module: " + moduleId);
}
definition.call(catalystInstance, methodId, parameters);
}
我們?cè)赗N中注冊(cè)NativeModule是通過(guò)add一個(gè)ReactPackage對(duì)象來(lái)實(shí)現(xiàn),家下來(lái)我們看一下,RN是如何把我們注冊(cè)的各個(gè)module添加到NativeModuleRegistry中的。
mReactInstanceManager = ReactInstanceManager.builder()
.addPackage(new MainReactPackage())
.build();
ReactInstanceManager.Builder的build方法,會(huì)new一個(gè)ReactInstanceManagerImpl對(duì)象,把我們的ReactPackage對(duì)象傳遞過(guò)去。ReactInstanceManagerImpl類的核心就是createReactContext方法,createReactContext會(huì)首先遍歷所有注冊(cè)的ReactPackage,對(duì)所有的NativeModule,構(gòu)造一個(gè)ModuleDefinition對(duì)象,保存到nativeModuleRegistry對(duì)象的mModuleTable中。最后,createReactContext會(huì)通過(guò)CatalystInstanceImpl.Builder構(gòu)造一個(gè)CatalystInstance對(duì)象,并把包含各個(gè)NativeModule信息的nativeModuleRegistry對(duì)象傳遞過(guò)去。具體的模塊的注冊(cè)過(guò)程,我后面再寫一篇單獨(dú)的博客介紹,此處就不啰嗦了。
private ReactApplicationContext createReactContext(JavaScriptExecutor jsExecutor, JSBundleLoader jsBundleLoader) {
...
for (ReactPackage reactPackage : mPackages) {
processPackage(reactPackage, reactContext, nativeRegistryBuilder, jsModulesBuilder);
}
...
CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder()
.setCatalystQueueConfigurationSpec(CatalystQueueConfigurationSpec.createDefault())
.setJSExecutor(jsExecutor)
.setRegistry(nativeModuleRegistry)
.setJSModulesConfig(javaScriptModulesConfig)
.setJSBundleLoader(jsBundleLoader)
.setNativeModuleCallExceptionHandler(exceptionHandler);
}
回到我們最開(kāi)始的例子中,我們要在Js中使用Toast,那么我們的MainReactPackage中,就需要構(gòu)造一個(gè)ToastModule,來(lái)注冊(cè)給RN,這樣才可以給Js調(diào)用。
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Arrays.<NativeModule>asList(
new ToastModule(reactContext));
}
需要注意的是,所有要給Js中使用的模塊,都需要在Native這邊注冊(cè)一個(gè)對(duì)應(yīng)的Module
在Js中調(diào)用ToastAndroid這個(gè)模塊的流程就是,Js調(diào)用會(huì)調(diào)用到C++中m_flushImmediateCallback函數(shù),參數(shù)就是Js函數(shù)的參數(shù)加上調(diào)用的模塊名構(gòu)成的一個(gè)JSON字符串。C++中,有一個(gè)parseMethodCalls方法,會(huì)從Js傳遞的JSON中,解析出moduleName,functionName,參數(shù)等一系列信息,然后C++層會(huì)調(diào)用Java層的ReactCallback類,Java代碼中,會(huì)根據(jù)傳遞來(lái)的moduleName,functionName找到對(duì)應(yīng)的模塊中的方法,然后通過(guò)反射執(zhí)行這些方法,并把參數(shù)傳遞過(guò)去。這樣就完成了Js對(duì)Native代碼的調(diào)用。