ReactNative 源码分析6——Native Modules通信机制

0 阅读3分钟

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 负责模块发现,nativeCallSyncHooknativeFlushQueueImmediate 负责方法调用(同步/异步),globalEvalWithSourceUrl 负责代码动态加载。

全局名称类型核心功能
nativeModuleProxyHostObjectJS 访问所有 Native Module 的代理对象
nativeFlushQueueImmediateFunction(1 arg)立即执行积压的原生方法调用队列
nativeCallSyncHookFunction(3 args)同步调用指定原生模块的方法并获取返回值
globalEvalWithSourceUrlFunction(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 调用队列 或 nullcallNativeModules(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的调用