Native Modules通信机制在初始化时创建,在《React Native 源码分析3——ReactActivity初始化》系列文章中其实已经讲了,C++层核心类是JSIExecutor,它有两个子类HermesExecutor和,它们负责实现JS与C++之间的通信。本篇文章只是将重点部分梳理出来,完整的通信流程后面会逐步分析。
JS调用C++
初始化
JS调用C++的流程是在JSIExecutor的initializeRuntime中初始化的
//JSIExecutor.cpp
void JSIExecutor::initializeRuntime() {
runtime_->global().setProperty(
*runtime_,
"nativeModuleProxy" ,
Object::createFromHostObject(
*runtime_, std::make_shared<NativeModuleProxy>(nativeModules_)));
runtime_->global().setProperty(
*runtime_,
"nativeFlushQueueImmediate" ,
Function::createFromHostFunction(
*runtime_,
PropNameID::forAscii(*runtime_, "nativeFlushQueueImmediate" ),
1,
[this](
jsi::Runtime&,
const jsi::Value&,
const jsi::Value* args,
size_t count) {
if (count != 1) {
throw std::invalid_argument(
"nativeFlushQueueImmediate arg count must be 1" );
}
callNativeModules(args[0], false);
return Value::undefined();
}));
runtime_->global().setProperty(
*runtime_,
"nativeCallSyncHook" ,
Function::createFromHostFunction(
*runtime_,
PropNameID::forAscii(*runtime_, "nativeCallSyncHook" ),
1,
[this](
jsi::Runtime&,
const jsi::Value&,
const jsi::Value* args,
size_t count) { return nativeCallSyncHook(args, count); }));
runtime_->global().setProperty(
*runtime_,
"globalEvalWithSourceUrl" ,
Function::createFromHostFunction(
*runtime_,
PropNameID::forAscii(*runtime_, "globalEvalWithSourceUrl" ),
1,
[this](
jsi::Runtime&,
const jsi::Value&,
const jsi::Value* args,
size_t count) { return globalEvalWithSourceUrl(args, count); }));
}
这四个注册项构成了 JS → Native 通信的核心桥梁:nativeModuleProxy 负责模块发现,nativeCallSyncHook 和 nativeFlushQueueImmediate 负责方法调用(同步/异步),globalEvalWithSourceUrl 负责代码动态加载。
| 全局名称 | 类型 | 核心功能 |
|---|---|---|
| nativeModuleProxy | HostObject | JS 访问所有 Native Module 的代理对象 |
| nativeFlushQueueImmediate | Function(1 arg) | 立即执行积压的原生方法调用队列 |
| nativeCallSyncHook | Function(3 args) | 同步调用指定原生模块的方法并获取返回值 |
| globalEvalWithSourceUrl | Function(1-2 args) | 带 source URL 动态执行 JS 代码 |
调用
MessageQueue.js中封装了上面这些方法用于JS → C++通信
enqueueNativeCall
JS异步调用C++通信,结果返回是通过CallbackId返回的
enqueueNativeCall(
moduleID: number,
methodID: number,
params: mixed[],
onFail: ?(...mixed[]) => void,
onSucc: ?(...mixed[]) => void,
)
callNativeSyncHook
JS同步调用C++通信
callNativeSyncHook(
moduleID: number,
methodID: number,
params: mixed[],
onFail: ?(...mixed[]) => void,
onSucc: ?(...mixed[]) => void,
)
C++调用JS
初始化
C++调用JS的流程是在JSIExecutor的bindBridge中初始化的
void JSIExecutor::bindBridge() {
std::call_once(bindFlag_, [this] {
SystraceSection s( "JSIExecutor::bindBridge (once)" );
Value batchedBridgeValue =
runtime_->global().getProperty(*runtime_, "__fbBatchedBridge" );
if (batchedBridgeValue.isUndefined() || !batchedBridgeValue.isObject()) {
throw JSINativeException(
"Could not get BatchedBridge, make sure your bundle is packaged correctly" );
}
Object batchedBridge = batchedBridgeValue.asObject(*runtime_);
callFunctionReturnFlushedQueue_ = batchedBridge.getPropertyAsFunction(
*runtime_, "callFunctionReturnFlushedQueue" );
invokeCallbackAndReturnFlushedQueue_ = batchedBridge.getPropertyAsFunction(
*runtime_, "invokeCallbackAndReturnFlushedQueue" );
flushedQueue_ =
batchedBridge.getPropertyAsFunction(*runtime_, "flushedQueue" );
});
}
__fbBatchedBridge位于BatchedBridge.js文件中,可以看到它其实就是MessageQueue对象
const MessageQueue = require( './MessageQueue' );
const BatchedBridge: MessageQueue = new MessageQueue();
Object.defineProperty(global, '__fbBatchedBridge' , {
configurable: true,
value: BatchedBridge,
});
module.exports = BatchedBridge;
MessageQueue对象中这三个方法的核心模式一致:被C++层调用,在 JS 侧执行某些操作后,把执行期间产生的 Native 调用队列批量返回给 C++ 侧处理,形成了 Native → JS(其中可能会调用Native API) → Native 的完整调用闭环
| 方法 | JS 签名 | 触发场景 | JS 侧执行 | 返回值 | C++ 对返回值的处理 |
|---|---|---|---|---|---|
| callFunctionReturnFlushedQueue | (module, method, args) | Native 调用 JS 模块方法 | __callFunction(module, method, args) | 积压的 Native 调用队列 | callNativeModules(ret, true) |
| invokeCallbackAndReturnFlushedQueue | (cbID, args) | Native 触发 JS 回调(如 Promise resolve/reject) | __invokeCallback(cbID, args) | 积压的 Native 调用队列 | callNativeModules(ret, true) |
| flushedQueue | () | 无需执行 JS 函数,仅刷新积压队列 | __callReactNativeMicrotasks() | 积压的 Native 调用队列 或 null | callNativeModules(ret, true) |
调用
JSIExecutor中封装了上面这些方法用于C++ → JS通信
callFunction
用于C++主动调用JS方法
- moduleId:JS中模块名
- methodId:JS中模块名下的方法名
- arguments:方法所需参数
void JSIExecutor::callFunction(const std::string& moduleId, const std::string& methodId,
const folly::dynamic& arguments)
invokeCallback
它是用于JS主动调用C++后,用于返回数据的
- callbackId:JS主动调用C++时创建的唯一ID
- arguments:返回数据
void JSIExecutor::invokeCallback(const double callbackId,
const folly::dynamic& arguments)
flush
获取JS中所有积压的队列,这里队列存放的JS对Native Modules的调用