RN与原生的通信源码解析

194 阅读14分钟

1.基本原理

JS要与原生通信,都依赖于引擎的能力,不论是hermes,还是V8,还是JSCore.向引擎注入额外方法,并实现 JS 调用. 基本思想都是一致的,都是要将 JS 所需的内容设法绑定到 JS 执行环境下的 全局对象 global 上,这样在 JS 侧就可以通过 global 来获取注入的内容了. 实际上是借助于 Js 执行上下文 Context 来实现的。首先需要获取这个 Context 上下文 和 JS global ,然后将 需要注入的 方法 和 变量 设置到 global 当中,最后再将 global 与 Context 进行关联,就完成了向引擎注入的操作。这样就可以在 Js 运行环境中,调用我们注入的方法和变量了。 这里是注入的方法或者变量:

runtime.global().setProperty(

      runtime,

      "__turboModuleProxy",

      jsi::Function::createFromHostFunction(

          runtime,

          jsi::PropNameID::forAscii(runtime, "__turboModuleProxy"),

          1,

          //$hyrn begin

          // [binding =

          //      TurboModuleBinding(bindingMode, std::move(moduleProvider))](

          [binding =

               TurboModuleBinding(bindingMode, std::move(moduleProvider), runtime)](

          //$hyrn end

              jsi::Runtime &rt,

              const jsi::Value &thisVal,

              const jsi::Value *args,

              size_t count) {

            if (count < 1) {

              throw std::invalid_argument(

                  "__turboModuleProxy must be called with at least 1 argument");

            }

            std::string moduleName = args[0].getString(rt).utf8(rt);

            return binding.getModule(rt, moduleName);

          }));

JS中使用的地方是(TurboModuleRegistry.js文件里面):

const turboModuleProxy = global.__turboModuleProxy;

当然与之对应的,原生也可以直接通过Context操作global中JS的方法或者变量:

m_genNativeModuleJS = rt.global().getPropertyAsFunction(rt, "__fbGenNativeModule");

JS中对应的地方是(NativeModules.js文件里面):

// export this method as a global so we can call it from native
global.__fbGenNativeModule = genModule;

2.NativeModules VS TurboModules

这里是2者的对比图,文章主要不是介绍这里,大家可以看一下.

image.png

3.NativeModules实现原理

基本原理是先创建通信bridge的类实例,通过Json传递数据. 先看创建NativeModules原生实现步骤:
1、创建类Module实现协议RCTBridgeModule 2、在.m文件中新增RCT_EXPORT_MODULE() 3、如要导出方法给js用,那么新增:RCT_EXPORT_METHOD 大概代码是:

#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
@interface TestModule : NSObject<RCTBridgeModule>
@end

@implementation TestModule 
RCT_EXPORT_MODULE() 

RCT_EXPORT_METHOD(add:(int)a b:(int)b callback:(RCTResponseSenderBlock)callback){
    callback(@[ [NSNumber numberWithInt: a+b ] ]); 
} 
@end

  

查看RCT_EXPORT_MODULE源码:

#define RCT_EXPORT_MODULE(js_name)          \

  RCT_EXTERN void RCTRegisterModule(Class); \

  +(NSString *)moduleName                   \

  {                                         \

    return @ #js_name;                      \

  }                                         \

  +(void)load                               \

  {                                         \

    RCTRegisterModule(self);                \

  }

RCTRegisterModule

void RCTRegisterModule(Class);

void RCTRegisterModule(Class moduleClass)

{

  static dispatch_once_t onceToken;

  dispatch_once(&onceToken, ^{

    RCTModuleClasses = [NSMutableArray new];

    RCTModuleClassesSyncQueue =

        dispatch_queue_create("com.facebook.react.ModuleClassesSyncQueue", DISPATCH_QUEUE_CONCURRENT);

  });

  


  RCTAssert(

      [moduleClass conformsToProtocol:@protocol(RCTBridgeModule)],

      @"%@ does not conform to the RCTBridgeModule protocol",

      moduleClass);

  


  // Register module

  dispatch_barrier_async(RCTModuleClassesSyncQueue, ^{

    [RCTModuleClasses addObject:moduleClass];

  });

}

主要作用是在+load阶段,将moduleClass记录在RCTModuleClasses数组中.

然后我们看下这个RCTModuleClasses在哪里被使用的呢?是在RCTCxxBridge下面的代码使用的:

- (void)start

{
......

  [self registerExtraModules];

  // Initialize all native modules that cannot be loaded lazily

  (void)[self _initializeModules:RCTGetModuleClasses() withDispatchGroup:prepareBridge lazilyDiscovered:NO];

  [self registerExtraLazyModules];
  ......
}

那这个start是在哪里调用的呢?看堆栈是在bridge创建的时候调用的

image.png

接下来看_initializeModules:具体干了啥?

- (NSArray<RCTModuleData *> *)_initializeModules:(NSArray<Class> *)modules

                               withDispatchGroup:(dispatch_group_t)dispatchGroup

                                lazilyDiscovered:(BOOL)lazilyDiscovered

{

  // Set up moduleData for automatically-exported modules

  NSArray<RCTModuleData *> *moduleDataById = [self _registerModulesForClasses:modules

                                                             lazilyDiscovered:lazilyDiscovered];

......
                                                             
 for (RCTModuleData *moduleData in _moduleDataByID) {

      if (moduleData.hasInstance && (!moduleData.requiresMainQueueSetup || RCTIsMainQueue())) {

        // Modules that were pre-initialized should ideally be set up before

        // bridge init has finished, otherwise the caller may try to access the

        // module directly rather than via `[bridge moduleForClass:]`, which won't

        // trigger the lazy initialization process. If the module cannot safely be

        // set up on the current thread, it will instead be async dispatched

        // to the main thread to be set up in _prepareModulesWithDispatchGroup:.

        (void)[moduleData instance];

      }

    }                                                            

......

  return moduleDataById;

}

调用了_registerModulesForClasses方法,将moduleName和moduleDataByID和RCTModuleData等信息通过属性的形式保存在bridge中.

- (NSArray<RCTModuleData *> *)_registerModulesForClasses:(NSArray<Class> *)moduleClasses

                                        lazilyDiscovered:(BOOL)lazilyDiscovered

{

  RCT_PROFILE_BEGIN_EVENT(

      RCTProfileTagAlways, @"-[RCTCxxBridge initModulesWithDispatchGroup:] autoexported moduleData", nil);

  


  NSArray *moduleClassesCopy = [moduleClasses copy];

  NSMutableArray<RCTModuleData *> *moduleDataByID = [NSMutableArray arrayWithCapacity:moduleClassesCopy.count];

  for (Class moduleClass in moduleClassesCopy) {

    //$hyrn begin

    if (RCTTurboModuleEnabled() && [moduleClass conformsToProtocol:@protocol(RCTTurboModule)] && moduleClass == NSClassFromString(@"HYDataCenterV2")) {

    // if (RCTTurboModuleEnabled() && [moduleClass conformsToProtocol:@protocol(RCTTurboModule)]) {

    //$hyrn end

      continue;

    }

    NSString *moduleName = RCTBridgeModuleNameForClass(moduleClass);

  


    // Check for module name collisions

    RCTModuleData *moduleData = _moduleDataByName[moduleName];

    if (moduleData) {

      if (moduleData.hasInstance || lazilyDiscovered) {

        // Existing module was preregistered, so it takes precedence

        continue;

      } else if ([moduleClass new] == nil) {

        // The new module returned nil from init, so use the old module

        continue;

      } else if ([moduleData.moduleClass new] != nil) {

        // Both modules were non-nil, so it's unclear which should take precedence

        RCTLogWarn(

            @"Attempted to register RCTBridgeModule class %@ for the "

             "name '%@', but name was already registered by class %@",

            moduleClass,

            moduleName,

            moduleData.moduleClass);

      }

    }

  


    // Instantiate moduleData

    // TODO #13258411: can we defer this until config generation?

    int32_t moduleDataId = getUniqueId();

    BridgeNativeModulePerfLogger::moduleDataCreateStart([moduleName UTF8String], moduleDataId);

    moduleData = [[RCTModuleData alloc] initWithModuleClass:moduleClass

                                                     bridge:self

                                             moduleRegistry:_objCModuleRegistry

                                    viewRegistry_DEPRECATED:_viewRegistry_DEPRECATED

                                              bundleManager:_bundleManager

                                          callableJSModules:_callableJSModules];

    BridgeNativeModulePerfLogger::moduleDataCreateEnd([moduleName UTF8String], moduleDataId);

  


    _moduleDataByName[moduleName] = moduleData;

    [_moduleClassesByID addObject:moduleClass];

    [moduleDataByID addObject:moduleData];

  }

  [_moduleDataByID addObjectsFromArray:moduleDataByID];

  


  RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");

  


  return moduleDataByID;

}

然后调用每个[RCTModuleData instance]方法,最后返回一个RCTModuleData对象的列表.在instance里面就会把具体的NativeModules bridge类实例化.具体可以自己断点看下.

image.png

那这些信息是怎么被JS知道的呢?我们继续往下看start方法中_initializeBridge:的调用,最终会调到下面这个方法:

void Instance::initializeBridge(
    std::unique_ptr<InstanceCallback> callback,

    std::shared_ptr<JSExecutorFactory> jsef,

    std::shared_ptr<MessageQueueThread> jsQueue,

    std::shared_ptr<ModuleRegistry> moduleRegistry) {

  callback_ = std::move(callback);

  moduleRegistry_ = std::move(moduleRegistry);

  jsQueue->runOnQueueSync([this, &jsef, jsQueue]() mutable {

    nativeToJsBridge_ = std::make_shared<NativeToJsBridge>(

        jsef.get(), moduleRegistry_, jsQueue, callback_);

    nativeToJsBridge_->initializeRuntime();

    /**

     * After NativeToJsBridge is created, the jsi::Runtime should exist.

     * Also, the JS message queue thread exists. So, it's safe to

     * schedule all queued up js Calls.

     */

    jsCallInvoker_->setNativeToJsBridgeAndFlushCalls(nativeToJsBridge_);

  


    std::lock_guard<std::mutex> lock(m_syncMutex);

    m_syncReady = true;

    m_syncCV.notify_all();

  });

  CHECK(nativeToJsBridge_);

}

我们来看看里面关键的的代码:

1.ModuleRegistry

moduleRegistry 中包括了所有 native module 信息,即 RCTModuleData;他是取上面保存的_moduleDataByID的信息保存到ModuleRegistry类,具体代码如下:

- (std::shared_ptr<ModuleRegistry>)_buildModuleRegistryUnlocked

{

  if (!self.valid) {

    return {};

  }

  [_performanceLogger markStartForTag:RCTPLNativeModulePrepareConfig];

  RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge buildModuleRegistry]", nil);

  __weak __typeof(self) weakSelf = self;

  ModuleRegistry::ModuleNotFoundCallback moduleNotFoundCallback = ^bool(const std::string &name) {

    __strong __typeof(weakSelf) strongSelf = weakSelf;

    return [strongSelf.delegate respondsToSelector:@selector(bridge:didNotFindModule:)] &&

        [strongSelf.delegate bridge:strongSelf didNotFindModule:@(name.c_str())];

  };

  auto registry = std::make_shared<ModuleRegistry>(

      createNativeModules(_moduleDataByID, self, _reactInstance), moduleNotFoundCallback);

  [_performanceLogger markStopForTag:RCTPLNativeModulePrepareConfig];

  RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");

  return registry;

}

2.NativeToJsBridge 的初始化

下面我们就来具体 NativeToJsBridge 是干嘛的

NativeToJsBridge::NativeToJsBridge(

    JSExecutorFactory *jsExecutorFactory,

    std::shared_ptr<ModuleRegistry> registry,

    std::shared_ptr<MessageQueueThread> jsQueue,

    std::shared_ptr<InstanceCallback> callback)

    : m_destroyed(std::make_shared<bool>(false)),

      m_delegate(std::make_shared<JsToNativeBridge>(registry, callback)),

      m_executor(jsExecutorFactory->createJSExecutor(m_delegate, jsQueue)),

      m_executorMessageQueueThread(std::move(jsQueue)),

      m_inspectable(m_executor->isInspectable()) {}

具体作用如下

1.其中 registry 和 callback 作为入参生成了一个 JsToNativeBridge 类型实例赋值给 m_delegate

2.使用 JSExecutorFactory 和 _delegate 创建了一个 JSExecutor;

3.从 RCTxxBridge 中创建的JSExecutorFactory得知此 JSExecutor 就是 JSIExecutor

JSIExecutor

前面我们已经将 RCTBridge 的初始化都讲解完成,还剩余最后一个部分,就是 JSIExecutor; 从前面的部分我们知道 NativeToJsBridge持有 JSIExecutor 的实例.我门来看看JSIExecutor具体是干嘛的?

JSIExecutor::JSIExecutor(

    std::shared_ptr<jsi::Runtime> runtime,

    std::shared_ptr<ExecutorDelegate> delegate,

    const JSIScopedTimeoutInvoker &scopedTimeoutInvoker,

    RuntimeInstaller runtimeInstaller)

    : runtime_(runtime),

      delegate_(delegate),

      nativeModules_(std::make_shared<JSINativeModules>(

          delegate ? delegate->getModuleRegistry() : nullptr)),

      moduleRegistry_(delegate ? delegate->getModuleRegistry() : nullptr),

      scopedTimeoutInvoker_(scopedTimeoutInvoker),

      runtimeInstaller_(runtimeInstaller) {

  runtime_->global().setProperty(

      *runtime, "__jsiExecutorDescription", runtime->description());

}

我们看下nativeModules_,这是一个JSINativeModules类.JSINativeModules 由上层传入的 ModuleRegistry 构造而成;而 ModuleRegistry 又是在 RCTxxBridge 中构造而成。前面的代码中,有调用

void JSIExecutor::initializeRuntime() {

  SystraceSection s("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); }));

  


  if (runtimeInstaller_) {

    runtimeInstaller_(*runtime_);

  }

  bool hasLogger(ReactMarker::logTaggedMarkerImpl);

  if (hasLogger) {

    ReactMarker::logMarker(ReactMarker::CREATE_REACT_CONTEXT_STOP);

  }

}

里面有个注入nativeModuleProxy,对应RN NativeModule.js里

let NativeModules: {[moduleName: string]: $FlowFixMe, ...} = {};
if (global.nativeModuleProxy) {
  NativeModules = global.nativeModuleProxy;

最终会调到下面的方法:

Value get(Runtime &rt, const PropNameID &name) override {

    if (name.utf8(rt) == "name") {

      return jsi::String::createFromAscii(rt, "NativeModules");

    }

    auto nativeModules = weakNativeModules_.lock();

    if (!nativeModules) {

      return nullptr;

    }

    return nativeModules->getModule(rt, name);

  }

getModule会调下面方法:

folly::Optional<Object> JSINativeModules::createModule(

//$hyrn end

    Runtime &rt,

    const std::string &name) {

  bool hasLogger(ReactMarker::logTaggedMarkerImpl);

  if (hasLogger) {

    ReactMarker::logTaggedMarker(

        ReactMarker::NATIVE_MODULE_SETUP_START, name.c_str());

  }

  


  if (!m_genNativeModuleJS) {

    m_genNativeModuleJS =

        rt.global().getPropertyAsFunction(rt, "__fbGenNativeModule");

  }

  


  auto result = m_moduleRegistry->getConfig(name);

  if (!result.has_value()) {

      //$hyrn begin

      // return std::nullopt;

      return folly::none;

      //$hyrn end

  }

  


  Value moduleInfo = m_genNativeModuleJS->call(

      rt,

      valueFromDynamic(rt, result->config),

      static_cast<double>(result->index));

  CHECK(!moduleInfo.isNull()) << "Module returned from genNativeModule is null";

  CHECK(moduleInfo.isObject())

      << "Module returned from genNativeModule isn't an Object";

  //$hyrn begin

  // std::optional<Object> module(

  //    moduleInfo.asObject(rt).getPropertyAsObject(rt, "module"));

  folly::Optional<Object> module(

      moduleInfo.asObject(rt).getPropertyAsObject(rt, "module"));

  //$hyrn end

  if (hasLogger) {

    ReactMarker::logTaggedMarker(

        ReactMarker::NATIVE_MODULE_SETUP_STOP, name.c_str());

  }
  return module;

}

上面这个方法有个__fbGenNativeModule,实际调用的是JS的genModule方法:

function genModule(
  config: ?ModuleConfig,
  moduleID: number,
): ?{
  name: string,
  module?: {...},
  ...
} {
  if (!config) {
    return null;
  }

  const [moduleName, constants, methods, promiseMethods, syncMethods] = config;
  invariant(
    !moduleName.startsWith('RCT') && !moduleName.startsWith('RK'),
    "Module name prefixes should've been stripped by the native side " +
      "but wasn't for " +
      moduleName,
  );

  if (!constants && !methods) {
    // Module contents will be filled in lazily later
    return {name: moduleName};
  }

  const module: {[string]: mixed} = {};
  methods &&
    methods.forEach((methodName, methodID) => {
      const isPromise =
        (promiseMethods && arrayContains(promiseMethods, methodID)) || false;
      const isSync =
        (syncMethods && arrayContains(syncMethods, methodID)) || false;
      invariant(
        !isPromise || !isSync,
        'Cannot have a method that is both async and a sync hook',
      );
      const methodType = isPromise ? 'promise' : isSync ? 'sync' : 'async';
      module[methodName] = genMethod(moduleID, methodID, methodType);
    });

  Object.assign(module, constants);

  if (module.getConstants == null) {
    module.getConstants = () => constants || Object.freeze({});
  } else {
    console.warn(
      `Unable to define method 'getConstants()' on NativeModule '${moduleName}'. NativeModule '${moduleName}' already has a constant or method called 'getConstants'. Please remove it.`,
    );
  }

  if (__DEV__) {
    BatchedBridge.createDebugLookup(moduleID, moduleName, methods);
  }

  return {name: moduleName, module};
}

这里JS中就获取到原生moduleName和方法信息,并对他做了对应的映射,所以JS调用了NativeModule最终获取到{name: moduleName, module},也就是有原生全部的信息了.至于调用具体的方法,对应的JS方法是下面的:

function genMethod(moduleID: number, methodID: number, type: MethodType) {
  let fn = null;
  if (type === 'promise') {
    fn = function promiseMethodWrapper(...args: Array<mixed>) {
      // In case we reject, capture a useful stack trace here.
      /* $FlowFixMe[class-object-subtyping] added when improving typing for
       * this parameters */
      const enqueueingFrameError: ExtendedError = new Error();
      return new Promise((resolve, reject) => {
        BatchedBridge.enqueueNativeCall(
          moduleID,
          methodID,
          args,
          data => resolve(data),
          errorData =>
            reject(
              updateErrorWithErrorData(
                (errorData: $FlowFixMe),
                enqueueingFrameError,
              ),
            ),
        );
      });
    };
  } else {
    fn = function nonPromiseMethodWrapper(...args: Array<mixed>) {
      const lastArg = args.length > 0 ? args[args.length - 1] : null;
      const secondLastArg = args.length > 1 ? args[args.length - 2] : null;
      const hasSuccessCallback = typeof lastArg === 'function';
      const hasErrorCallback = typeof secondLastArg === 'function';
      hasErrorCallback &&
        invariant(
          hasSuccessCallback,
          'Cannot have a non-function arg after a function arg.',
        );
      // $FlowFixMe[incompatible-type]
      const onSuccess: ?(mixed) => void = hasSuccessCallback ? lastArg : null;
      // $FlowFixMe[incompatible-type]
      const onFail: ?(mixed) => void = hasErrorCallback ? secondLastArg : null;
      // $FlowFixMe[unsafe-addition]
      const callbackCount = hasSuccessCallback + hasErrorCallback;
      const newArgs = args.slice(0, args.length - callbackCount);
      if (type === 'sync') {
        return BatchedBridge.callNativeSyncHook(
          moduleID,
          methodID,
          newArgs,
          onFail,
          onSuccess,
        );
      } else {
        BatchedBridge.enqueueNativeCall(
          moduleID,
          methodID,
          newArgs,
          onFail,
          onSuccess,
        );
      }
    };
  }
  // $FlowFixMe[prop-missing]
  fn.type = type;
  return fn;
}

enqueueNativeCall,callNativeSyncHook,enqueueNativeCall是不是很眼熟,就是之前initializeRuntime另外几个注入的信息,真正会调原生nativeCallSyncHook,或者nativeFlushQueueImmediate注入的方法.另外异步函数调用解析对应json的代码是在下面代码这里parseMethodCalls,大家可以看下实现.所以NativeModules是以json为数据结构通信的.最终moduleId和methodid找到对应的方法,动态调用对应的原生接口代码,具体看下m_registry->callNativeMethod.

void callNativeModules(

      [[maybe_unused]] JSExecutor &executor,

      folly::dynamic &&calls,

      bool isEndOfBatch) override {

    CHECK(m_registry || calls.empty())

        << "native module calls cannot be completed with no native modules";

    m_batchHadNativeModuleOrTurboModuleCalls =

        m_batchHadNativeModuleOrTurboModuleCalls || !calls.empty();

    std::vector<MethodCall> methodCalls = parseMethodCalls(std::move(calls));

    BridgeNativeModulePerfLogger::asyncMethodCallBatchPreprocessEnd(

        (int)methodCalls.size());

    // An exception anywhere in here stops processing of the batch.  This

    // was the behavior of the Android bridge, and since exception handling

    // terminates the whole bridge, there's not much point in continuing.

    for (auto &call : methodCalls) {

      m_registry->callNativeMethod(

          call.moduleId, call.methodId, std::move(call.arguments), call.callId);

    }

    if (isEndOfBatch) {

      // onBatchComplete will be called on the native (module) queue, but

      // decrementPendingJSCalls will be called sync. Be aware that the bridge

      // may still be processing native calls when the bridge idle signaler

      // fires.

      if (m_batchHadNativeModuleOrTurboModuleCalls) {

        m_callback->onBatchComplete();

        m_batchHadNativeModuleOrTurboModuleCalls = false;

      }

      m_callback->decrementPendingJSCalls();

    }

  }

4.TurboModules实现原理

上面说是NativeModules的,如果换成TurboModules,就会在RCTCxxBridge start中执行RCTTurboModuleManager中的下面这个方法:

- (void)installJSBindingWithRuntimeExecutor:(facebook::react::RuntimeExecutor &)runtimeExecutor

{

  if (!runtimeExecutor) {

    // jsi::Runtime doesn't exist when attached to Chrome debugger.

    return;

  }

  


  /**

   * We keep TurboModuleManager alive until the JS VM is deleted.

   * It is perfectly valid to only use/create TurboModules from JS.

   * In such a case, we shouldn't dealloc TurboModuleManager if there

   * aren't any strong references to it in ObjC. Hence, we give

   * __**turboModuleProxy a strong reference to TurboModuleManager.**

   */

  auto turboModuleProvider = [self](const std::string &name) -> std::shared_ptr<react::TurboModule> {

    auto moduleName = name.c_str();

  


    TurboModulePerfLogger::moduleJSRequireBeginningStart(moduleName);

    auto moduleWasNotInitialized = ![self moduleIsInitialized:moduleName];

    if (moduleWasNotInitialized) {

      [self->_bridge.performanceLogger markStartForTag:RCTPLTurboModuleSetup];

    }

  


    /**

     * By default, all TurboModules are long-lived.

     * Additionally, if a TurboModule with the name `name` isn't found, then we

     * trigger an assertion failure.

     */

    auto turboModule = [self provideTurboModule:moduleName];

  


    if (moduleWasNotInitialized && [self moduleIsInitialized:moduleName]) {

      [self->_bridge.performanceLogger markStopForTag:RCTPLTurboModuleSetup];

      [self notifyAboutTurboModuleSetup:moduleName];

    }

  


    if (turboModule) {

      TurboModulePerfLogger::moduleJSRequireEndingEnd(moduleName);

    } else {

      TurboModulePerfLogger::moduleJSRequireEndingFail(moduleName);

    }

  


    return turboModule;

  };

  


  runtimeExecutor([turboModuleProvider = std::move(turboModuleProvider)](jsi::Runtime &runtime) {

    TurboModuleBinding::install(runtime, sTurboModuleBindingMode, std::move(turboModuleProvider));

  });

}

方法有个turboModuleProvider,类似于block,再用这个作为参数调用TurboModuleBinding::install方法,如下:

void TurboModuleBinding::install(

    jsi::Runtime &runtime,

    TurboModuleBindingMode bindingMode,

    TurboModuleProviderFunctionType &&moduleProvider) {

  runtime.global().setProperty(

      runtime,

      "__turboModuleProxy",

      jsi::Function::createFromHostFunction(

          runtime,

          jsi::PropNameID::forAscii(runtime, "__turboModuleProxy"),

          1,

          //$hyrn begin

          // [binding =

          //      TurboModuleBinding(bindingMode, std::move(moduleProvider))](

          [binding =

               TurboModuleBinding(bindingMode, std::move(moduleProvider), runtime)](

          //$hyrn end

              jsi::Runtime &rt,

              const jsi::Value &thisVal,

              const jsi::Value *args,

              size_t count) {

            if (count < 1) {

              throw std::invalid_argument(

                  "__turboModuleProxy must be called with at least 1 argument");

            }

            std::string moduleName = args[0].getString(rt).utf8(rt);

            return binding.getModule(rt, moduleName);

          }));

}

这个方法往JS注入一个属性__turboModuleProxy,对应JS代码是TurboModuleRegistry.js文件里的:

const turboModuleProxy = global.__turboModuleProxy;

最终返回的就是上面的turboModuleProvider的返回值.我们看看这个方法具体干了什么,最终断点到下面代码:

- (id<RCTTurboModule>)_provideRCTTurboModule:(const char *)moduleName

                                moduleHolder:(TurboModuleHolder *)moduleHolder

                               shouldPerfLog:(BOOL)shouldPerfLog

{

  bool shouldCreateModule = false;

  


  {

    std::lock_guard<std::mutex> guard(moduleHolder->mutex());

  


    if (moduleHolder->isDoneCreatingModule()) {

      if (shouldPerfLog) {

        TurboModulePerfLogger::moduleCreateCacheHit(moduleName, moduleHolder->getModuleId());

      }

      return moduleHolder->getModule();

    }

  


    if (!moduleHolder->isCreatingModule()) {

      shouldCreateModule = true;

      moduleHolder->startCreatingModule();

    }

  }

  


  if (shouldCreateModule) {

    Class moduleClass;

  


    /**

     * Step 2a: Resolve platform-specific class.

     */

  


    if ([_delegate respondsToSelector:@selector(getModuleClassFromName:)]) {

      if (RCTTurboModuleManagerDelegateLockingDisabled()) {

        moduleClass = [_delegate getModuleClassFromName:moduleName];

      } else {

        std::lock_guard<std::mutex> delegateGuard(_turboModuleManagerDelegateMutex);

        moduleClass = [_delegate getModuleClassFromName:moduleName];

      }

    }

  


    if (!moduleClass) {

      moduleClass = getFallbackClassFromName(moduleName);

    }

  


    __block id<RCTTurboModule> module = nil;

  


    if ([moduleClass conformsToProtocol:@protocol(RCTTurboModule)]) {

      __weak __typeof(self) weakSelf = self;

      dispatch_block_t work = ^{

        auto strongSelf = weakSelf;

        if (!strongSelf) {

          return;

        }

        module = [strongSelf _createAndSetUpRCTTurboModule:moduleClass

                                                moduleName:moduleName

                                                  moduleId:moduleHolder->getModuleId()];

      };

  


      if ([self _requiresMainQueueSetup:moduleClass]) {

        /**

         * When TurboModule eager initialization is enabled, there shouldn't be any TurboModule initializations on the

         * main queue.

         * TODO(T69449176) Roll out TurboModule eager initialization, and remove this check.

         */

        if (RCTTurboModuleEagerInitEnabled() && !RCTIsMainQueue()) {

          RCTLogWarn(

              @"TurboModule \"%@\" requires synchronous dispatch onto the main queue to be initialized. This may lead to deadlock.",

              moduleClass);

        }

  


        RCTUnsafeExecuteOnMainQueueSync(work);

      } else {

        work();

      }

    }

  


    {

      std::lock_guard<std::mutex> guard(moduleHolder->mutex());

  


      moduleHolder->setModule(module);

      moduleHolder->endCreatingModule();

    }

  


    moduleHolder->cv().notify_all();

  


    return module;

  }

  


  std::unique_lock<std::mutex> guard(moduleHolder->mutex());

  


  while (moduleHolder->isCreatingModule()) {

    /**

     * TODO(T65905574):

     * If the thread responsible for creating and initializing the NativeModule stalls, we'll wait here indefinitely.

     * This is the behaviour in legacy NativeModules. Changing this now could lead to more crashes/problems in

     * TurboModules than in NativeModules, which'll make it more difficult to test the TurboModules infra. Therefore,

     * we should consider making it post TurboModule 100% rollout.

     */

    moduleHolder->cv().wait(guard);

  }

  


  return moduleHolder->getModule();

}

这个方法是获取Class,调用下面的方法:

- (id<RCTTurboModule>)_createAndSetUpRCTTurboModule:(Class)moduleClass

                                         moduleName:(const char *)moduleName

                                           moduleId:(int32_t)moduleId

{

  id<RCTTurboModule> module = nil;

  


  /**

   * Step 2b: Ask hosting application/delegate to instantiate this class

   */

  


  TurboModulePerfLogger::moduleCreateConstructStart(moduleName, moduleId);

  if ([_delegate respondsToSelector:@selector(getModuleInstanceFromClass:)]) {

    if (RCTTurboModuleManagerDelegateLockingDisabled()) {

      module = [_delegate getModuleInstanceFromClass:moduleClass];

    } else {

      std::lock_guard<std::mutex> delegateGuard(_turboModuleManagerDelegateMutex);

      module = [_delegate getModuleInstanceFromClass:moduleClass];

    }

  


    /**

     * If the application is unable to create the TurboModule object from its class:

     * abort TurboModule creation, and early return nil.

     */

    if (!module) {

      RCTLogError(

          @"TurboModuleManager delegate %@ returned nil TurboModule object for module with name=\"%s\" and class=%@",

          NSStringFromClass([_delegate class]),

          moduleName,

          NSStringFromClass(moduleClass));

      return nil;

    }

  } else {

    module = [moduleClass new];

  }

  TurboModulePerfLogger::moduleCreateConstructEnd(moduleName, moduleId);

  


  TurboModulePerfLogger::moduleCreateSetUpStart(moduleName, moduleId);

  


  /**

   * It is reasonable for NativeModules to not want/need the bridge.

   * In such cases, they won't have `@synthesize bridge = _bridge` in their

   * implementation, and a `- (RCTBridge *) bridge { ... }` method won't be

   * generated by the ObjC runtime. The property will also not be backed

   * by an ivar, which makes writing to it unsafe. Therefore, we check if

   * this method exists to know if we can safely set the bridge to the

   * NativeModule.

   */

  if ([module respondsToSelector:@selector(bridge)] && _bridge) {

    /**

     * Just because a NativeModule has the `bridge` method, it doesn't mean

     * that it has synthesized the bridge in its implementation. Therefore,

     * we need to surround the code that sets the bridge to the NativeModule

     * inside a try/catch. This catches the cases where the NativeModule

     * author specifies a `bridge` method manually.

     */

    @try {

      /**

       * RCTBridgeModule declares the bridge property as readonly.

       * Therefore, when authors of NativeModules synthesize the bridge

       * via @synthesize bridge = bridge;, the ObjC runtime generates

       * only a - (RCTBridge * *) bridge: { ... } method. No setter is*

       * *generated, so we have have to rely on the KVC API of ObjC to set*

       * *the bridge property of these NativeModules.*

       */

      [(id)module setValue:_bridge forKey:@"bridge"];

    } @catch (NSException *exception) {

      RCTLogError(

          @"%@ has no setter or ivar for its bridge, which is not "

           "permitted. You must either @synthesize the bridge property, "

           "or provide your own setter method.",

          RCTBridgeModuleNameForClass([module class]));

    }

  }

  


  /**

   * Some modules need their own queues, but don't provide any, so we need to create it for them.

   * These modules typically have the following:

   *   `@synthesize methodQueue = _methodQueue`

   */

  


  dispatch_queue_t methodQueue = nil;

  BOOL moduleHasMethodQueueGetter = [module respondsToSelector:@selector(methodQueue)];

  


  if (moduleHasMethodQueueGetter) {

    methodQueue = [(id<RCTBridgeModule>)module methodQueue];

  }

  


  /**

   * Note: RCTJSThread, which is a valid method queue, is defined as (id)kCFNull. It should rightfully not enter the

   * following if condition's block.

   */

  if (!methodQueue) {

    NSString *methodQueueName = [NSString stringWithFormat:@"com.facebook.react.%sQueue", moduleName];

    methodQueue = dispatch_queue_create(methodQueueName.UTF8String, DISPATCH_QUEUE_SERIAL);

  


    if (moduleHasMethodQueueGetter) {

      /**

       * If the module has a method queue getter, two cases are possible:

       *  - We @synthesized the method queue. In this case, the getter will initially return nil.

       *  - We had a custom methodQueue function on the NativeModule. If we got this far, then that getter returned

       *    nil.

       *

       * Therefore, we do a try/catch and use ObjC's KVC API and try to assign the method queue to the NativeModule.

       * In case 1, we'll succeed. In case 2, an exception will be thrown, which we'll ignore.

       */

  


      @try {

        [(id)module setValue:methodQueue forKey:@"methodQueue"];

      } @catch (NSException *exception) {

        RCTLogError(

            @"%@ has no setter or ivar for its methodQueue, which is not "

             "permitted. You must either @synthesize the methodQueue property, "

             "or provide your own setter method.",

            RCTBridgeModuleNameForClass([module class]));

      }

    }

  }

  


  /**

   * Decorate TurboModules with bridgeless-compatible APIs that call into the bridge.

   */

  if (_bridge) {

    [_bridge attachBridgeAPIsToTurboModule:module];

  }

  


  /**

   * If the TurboModule conforms to RCTInitializing, invoke its initialize method.

   */

  if ([module respondsToSelector:@selector(initialize)]) {

    [(id<RCTInitializing>)module initialize];

  }

  


  /**

   * Attach method queue to id<RCTTurboModule> object.

   * This is necessary because the id<RCTTurboModule> object can be eagerly created/initialized before the method

   * queue is required. The method queue is required for an id<RCTTurboModule> for JS -> Native calls. So, we need it

   * before we create the id<RCTTurboModule>'s TurboModule jsi::HostObject in provideTurboModule:.

   */

  objc_setAssociatedObject(module, &kAssociatedMethodQueueKey, methodQueue, OBJC_ASSOCIATION_RETAIN);

  


  /**

   * NativeModules that implement the RCTFrameUpdateObserver protocol

   * require registration with RCTDisplayLink.

   *

   * TODO(T55504345): Investigate whether we can improve this after TM

   * rollout.

   */

  if (_bridge) {

    RCTModuleData *data = [[RCTModuleData alloc] initWithModuleInstance:(id<RCTBridgeModule>)module

                                                                 bridge:_bridge

                                                         moduleRegistry:_bridge.moduleRegistry

                                                viewRegistry_DEPRECATED:nil

                                                          bundleManager:nil

                                                      callableJSModules:nil];

    [_bridge registerModuleForFrameUpdates:(id<RCTBridgeModule>)module withModuleData:data];

  }

  


  /**

   * Broadcast that this TurboModule was created.

   *

   * TODO(T41180176): Investigate whether we can delete this after TM

   * rollout.

   */

  [[NSNotificationCenter defaultCenter]

      postNotificationName:RCTDidInitializeModuleNotification

                    object:_bridge

                  userInfo:@{@"module" : module, @"bridge" : RCTNullIfNil([_bridge parentBridge])}];

  


  TurboModulePerfLogger::moduleCreateSetUpEnd(moduleName, moduleId);

  


  return module;

}

里面会把一些信息通过registerModuleForFrameUpdates:注册到bridge中去,并通过上面的Class创建一个id的对象返回,而这个对象更好是是我们创建需要继承的协议

@protocol RCTTurboModule <NSObject>

- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:

    (const facebook::react::ObjCTurboModule::InitParams &)params;

@end

而这个协议必须实现getTurboModule,他返回一个TurboModule对象,这个继承自HostObject,而前面turboModuleProvider正是获取这个返回.也就是JS中调用TurboModuleRegistry.get('xxx'),实际上是放回一个HostObject对象.然后我们看下TurboModule的get方法:

    facebook::jsi::Value get(

      facebook::jsi::Runtime &runtime,

      const facebook::jsi::PropNameID &propName) override {

    {

      std::string propNameUtf8 = propName.utf8(runtime);

      auto p = methodMap_.find(propNameUtf8);

      if (p == methodMap_.end()) {

        // Method was not found, let JS decide what to do.

        return facebook::jsi::Value::undefined();

      } else {

        auto moduleMethod = createHostFunction(runtime, propName, p->second);

        // If we have a JS wrapper, cache the result of this lookup

        // We don't cache misses, to allow for methodMap_ to dynamically be

        // extended

        if (jsRepresentation_) {

          jsRepresentation_->lock(runtime).asObject(runtime).setProperty(

              runtime, propName, moduleMethod);

        }

        return moduleMethod;

      }

    }

  }

上面的方法,通过methodMap_创建HostFunction,并通过setProperty设置给JS调用.而methodMap_是在

    NativeTestSpecJSI::NativeTestSpecJSI(const ObjCTurboModule::InitParams &params)

  : ObjCTurboModule(params {
        // __hostFunction_NativeTurboTestSpecJSI_add详见3.5.1
        methodMap_["add"] = MethodMetadata {2, __hostFunction_NativeTurboTestSpecJSI_add};
    }

设置的,所以实际执行的是__hostFunction_NativeTurboTestSpecJSI_add,这个方法是:

    static facebook::jsi::Value __hostFunction_NativeTurboTestSpecJSI_add(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
      return static_cast<ObjCTurboModule &>(turboModule).invokeObjCMethod(rt, PromiseKind, "test", @selector(test:resolve:reject:), args, count);

}

最终通过runtime调用到具体方法,实现是:

    jsi::Value ObjCTurboModule::invokeObjCMethod(

    jsi::Runtime &runtime,

    TurboModuleMethodValueKind returnType,

    const std::string &methodNameStr,

    SEL selector,

    const jsi::Value *args,

    size_t count)

{

  const char *moduleName = name_.c_str();

  const char *methodName = methodNameStr.c_str();

  


  if (isMethodSync(returnType)) {

    TurboModulePerfLogger::syncMethodCallStart(moduleName, methodName);

  } else {

    TurboModulePerfLogger::asyncMethodCallStart(moduleName, methodName);

  }

  


  NSMutableArray *retainedObjectsForInvocation = [NSMutableArray arrayWithCapacity:count + 2];

  NSInvocation *inv =

      getMethodInvocation(runtime, returnType, methodName, selector, args, count, retainedObjectsForInvocation);

  


  jsi::Value returnValue = returnType == PromiseKind

      ? createPromise(

            runtime,

            methodNameStr,

            ^(RCTPromiseResolveBlock resolveBlock, RCTPromiseRejectBlock rejectBlock) {

              RCTPromiseResolveBlock resolveCopy = [resolveBlock copy];

              RCTPromiseRejectBlock rejectCopy = [rejectBlock copy];
    
              [inv setArgument:(void *)&resolveCopy atIndex:count + 2];

              [inv setArgument:(void *)&rejectCopy atIndex:count + 3];

              [retainedObjectsForInvocation addObject:resolveCopy];

              [retainedObjectsForInvocation addObject:rejectCopy];

              // The return type becomes void in the ObjC side.

              performMethodInvocation(runtime, VoidKind, methodName, inv, retainedObjectsForInvocation);

            })

      : performMethodInvocation(runtime, returnType, methodName, inv, retainedObjectsForInvocation);

  if (isMethodSync(returnType)) {

    TurboModulePerfLogger::syncMethodCallEnd(moduleName, methodName);

  } else {

    TurboModulePerfLogger::asyncMethodCallEnd(moduleName, methodName);

  }

    return returnValue;

}

刚看了下源码,有问题欢迎大家指证.中间也找了些文章粘贴复制,希望大家不要介意.