阅读视图

发现新文章,点击刷新页面。

ReactNative新架构之iOS端TurboModule源码剖析

ReactNative新架构之iOS端TurboModule源码剖析

前言

注意,本文是基于React Native 0.83版本源码进行分析。

前面已经通过《ReactNative新架构之Android端TurboModule机制完全解析》了解了很多TurboModule的关键信息,接下来iOS端的分析将会略过一些已知内容,聚焦重点。

初始化

先回顾一下《React Native新架构之iOS端初始化源码分析》一文我们提过的TurboModule初始化流程:

AppDelegate中有:

    // 1: 创建 ReactNativeDelegate
    let delegate = ReactNativeDelegate()
    // 2: 创建 RCTReactNativeFactory
    let factory = RCTReactNativeFactory(delegate: delegate)
    // 3: 配置依赖提供者(Codegen 生成的模块)
    delegate.dependencyProvider = RCTAppDependencyProvider()

接下来再看看RCTReactNativeFactory 中对RCTTurboModuleManagerDelegate协议的实现:

- (Class)getModuleClassFromName:(const char *)name
{
#if RN_DISABLE_OSS_PLUGIN_HEADER
  return RCTTurboModulePluginClassProvider(name);
#else
  // 先尝试从 delegate 获取
  if ([_delegate respondsToSelector:@selector(getModuleClassFromName:)]) {
    Class moduleClass = [_delegate getModuleClassFromName:name];
    if (moduleClass != nil) {
      return moduleClass;
    }
  }
  return RCTCoreModulesClassProvider(name);
#endif
}

- (nullable id<RCTModuleProvider>)getModuleProvider:(const char *)name
{
  if ([_delegate respondsToSelector:@selector(getModuleProvider:)]) {
    return [_delegate getModuleProvider:name];
  }
  return nil;
}

- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
                                                      jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
{
  if ([_delegate respondsToSelector:@selector(getTurboModule:jsInvoker:)]) {
    return [_delegate getTurboModule:name jsInvoker:jsInvoker];
  }

  return facebook::react::DefaultTurboModules::getTurboModule(name, jsInvoker);
}

- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
{
#if USE_OSS_CODEGEN
  if (self.delegate.dependencyProvider == nil) {
    [NSException raise:@"ReactNativeFactoryDelegate dependencyProvider is nil"
                format:@"Delegate must provide a valid dependencyProvider"];
  }
#endif
  if ([_delegate respondsToSelector:@selector(getModuleInstanceFromClass:)]) {
    id<RCTTurboModule> moduleInstance = [_delegate getModuleInstanceFromClass:moduleClass];
    if (moduleInstance != nil) {
      return moduleInstance;
    }
  }
  // 使用默认方式创建(通过 dependencyProvider)
  return RCTAppSetupDefaultModuleFromClass(moduleClass, self.delegate.dependencyProvider);
}

可以看到,这里面优先调用_delegate中的方法,而我们在自定义的ReactNativeDelegate中并未实现这些方法,那么只能去父类找,也就是RCTDefaultReactNativeFactoryDelegate.mm

@implementation RCTDefaultReactNativeFactoryDelegate

@synthesize dependencyProvider;

// 省略部分代码......

- (nullable id<RCTModuleProvider>)getModuleProvider:(const char *)name
{
  NSString *providerName = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
  return (self.dependencyProvider != nullptr) ? self.dependencyProvider.moduleProviders[providerName] : nullptr;
}

- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
                                                      jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
{
  return facebook::react::DefaultTurboModules::getTurboModule(name, jsInvoker);
}

- (Class)getModuleClassFromName:(const char *)name
{
  return nullptr;
}

- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
{
  return nullptr;
}

@end

可以看到,getModuleClassFromNamegetModuleInstanceFromClass并没有具体实现。而getModuleProvider方法,也依赖其属性dependencyProvider。这里的dependencyProvider是由外部赋值,也就是初始化时创建的RCTAppDependencyProvider对象。

这里的RCTAppDependencyProvider实际上是由codegen工具自动生成的,并不在代码中。

TurboModule是懒加载的,这里主要是设置了Provider。继续回顾一下RCTInstance.mm中的_start方法:

  // 创建 TurboModuleManager
  _turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridgeProxy:bridgeProxy
                                                     bridgeModuleDecorator:_bridgeModuleDecorator
                                                                  delegate:self
                                                                 jsInvoker:jsCallInvoker
                                             devMenuConfigurationDecorator:_devMenuConfigurationDecorator];

  // 省略......

  // 创建 ContextContainer
  auto contextContainer = std::make_shared<ContextContainer>();
  [_delegate didCreateContextContainer:contextContainer];
  // 插入核心模块
  contextContainer->insert(
      "RCTImageLoader", facebook::react::wrapManagedObject([_turboModuleManager moduleForName:"RCTImageLoader"]));
  contextContainer->insert(
      "RCTEventDispatcher",
      facebook::react::wrapManagedObject([_turboModuleManager moduleForName:"RCTEventDispatcher"]));


  // 初始化 JS Runtime 
  _reactInstance->initializeRuntime(options, [=](jsi::Runtime &runtime) {
    __strong __typeof(self) strongSelf = weakSelf;
    if (!strongSelf) {
      return;
    }

    // 安装 TurboModule JS 绑定
    [strongSelf->_turboModuleManager installJSBindings:runtime];
    // 绑定 Native Logger
    facebook::react::bindNativeLogger(runtime, [](const std::string &message, unsigned int logLevel) {
      _RCTLogJavaScriptInternal(static_cast<RCTLogLevel>(logLevel), [NSString stringWithUTF8String:message.c_str()]);
    });

    // 安装 Native Component Registry 绑定
    RCTInstallNativeComponentRegistryBinding(runtime);
    // 省略......
  });

继续跟踪RCTTurboModuleManager的初始化,源码react-native/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.mm

- (instancetype)initWithBridgeProxy:(RCTBridgeProxy *)bridgeProxy
              bridgeModuleDecorator:(RCTBridgeModuleDecorator *)bridgeModuleDecorator
                           delegate:(id<RCTTurboModuleManagerDelegate>)delegate
                          jsInvoker:(std::shared_ptr<CallInvoker>)jsInvoker
      devMenuConfigurationDecorator:(RCTDevMenuConfigurationDecorator *)devMenuConfigurationDecorator
{
  return [self initWithBridge:nil
                        bridgeProxy:bridgeProxy
              bridgeModuleDecorator:bridgeModuleDecorator
                           delegate:delegate
                          jsInvoker:jsInvoker
      devMenuConfigurationDecorator:devMenuConfigurationDecorator];
}



- (instancetype)initWithBridge:(RCTBridge *)bridge
                      bridgeProxy:(RCTBridgeProxy *)bridgeProxy
            bridgeModuleDecorator:(RCTBridgeModuleDecorator *)bridgeModuleDecorator
                         delegate:(id<RCTTurboModuleManagerDelegate>)delegate
                        jsInvoker:(std::shared_ptr<CallInvoker>)jsInvoker
    devMenuConfigurationDecorator:(RCTDevMenuConfigurationDecorator *)devMenuConfigurationDecorator
{
  if (self = [super init]) {
    _jsInvoker = std::move(jsInvoker);
    _delegate = delegate;
    _bridge = bridge;
    _bridgeProxy = bridgeProxy;
    _bridgeModuleDecorator = bridgeModuleDecorator;
    _invalidating = false;
    // 创建串行队列 _sharedModuleQueue 
    _sharedModuleQueue = dispatch_queue_create("com.meta.react.turbomodulemanager.queue", DISPATCH_QUEUE_SERIAL);
    _devMenuConfigurationDecorator = devMenuConfigurationDecorator;

    if (RCTTurboModuleInteropEnabled()) {
      // 省略旧架构兼容处理......
    }

    // 监听 RCTBridgeWillInvalidateModulesNotification 和 RCTBridgeDidInvalidateModulesNotification 通知,用于处理模块失效场景
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(bridgeWillInvalidateModules:)
                                                 name:RCTBridgeWillInvalidateModulesNotification
                                               object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(bridgeDidInvalidateModules:)
                                                 name:RCTBridgeDidInvalidateModulesNotification
                                               object:nil];
  }
  return self;
}

RCTTurboModuleManager初始化逻辑非常简单,我们继续查看[strongSelf->_turboModuleManager installJSBindings:runtime]方法调用,它是在JS Runtime初始化完成之后才回调的,现在跟踪一下具体实现,源码react-native/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.mm

- (void)installJSBindings:(facebook::jsi::Runtime &)runtime
{
  /**
   * 我们会一直保留 TurboModuleManager 实例,直到 JavaScript 虚拟机被销毁。
   * 仅从 JavaScript 端使用/创建 TurboModule 是完全有效的。
   * 在这种情况下,如果 Objective-C 代码中没有对 TurboModuleManager 的强引用,我们就不应该释放它。
   * 因此,我们让 __turboModuleProxy 持有对 TurboModuleManager 的强引用。
   */
  auto turboModuleProvider = [self,
                              runtime = &runtime](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];
    }

    /**
     * 默认情况下,所有 TurboModule 都是长期存在的。 
     * 此外,如果找不到名称为 `name` 的 TurboModule,则会触发断言失败。 
     */
    auto turboModule = [self provideTurboModule:moduleName runtime:runtime];

    if (moduleWasNotInitialized && [self moduleIsInitialized:moduleName]) {
      [self->_bridge.performanceLogger markStopForTag:RCTPLTurboModuleSetup];
    }

    if (turboModule) {
      TurboModulePerfLogger::moduleJSRequireEndingEnd(moduleName);
    } else {
      TurboModulePerfLogger::moduleJSRequireEndingFail(moduleName);
    }
    return turboModule;
  };

  if (RCTTurboModuleInteropEnabled()) {
     // 省略旧架构兼容代码......
  } else {
    TurboModuleBinding::install(runtime, std::move(turboModuleProvider));
  }
}

该方法是负责将 TurboModule 系统绑定到 JavaScript 运行时,建立 JS 与原生模块之间的桥梁。

这里的TurboModuleBinding::install方法我们在Android端时已经分析过了,不再赘述。TurboModulePerfLogger是性能日志相关的东西,直接忽略。

所以整个iOS的初始化流程,相比Android端简单太多了。

调用流程

《ReactNative新架构之Android端TurboModule机制完全解析》一文中,我们已经详细分析过了从JS层到C++层的查找逻辑。现在回顾一下关键地方:

// TurboModuleBinding.cpp

jsi::Value TurboModuleBinding::getModule(
    jsi::Runtime& runtime,
    const std::string& moduleName) const {
  std::shared_ptr<TurboModule> module;
  {
    TraceSection s("TurboModuleBinding::moduleProvider", "module", moduleName);
    module = moduleProvider_(moduleName);  // ← 调用moduleProvider获取模块
  }
  if (module) {
    TurboModuleWithJSIBindings::installJSIBindings(module, runtime);
    // 省略......

    // 状态:在 TurboModule 上未找到 jsRepresentation
    // 创建一个全新的 jsRepresentation,并将其附加到 TurboModule
    jsi::Object jsRepresentation(runtime);
    weakJsRepresentation =
        std::make_unique<jsi::WeakObject>(runtime, jsRepresentation);

    // 在属性访问时延迟填充 jsRepresentation。
    //
    // 这是如何工作的?
    //   1. 最初 jsRepresentation 是空的:{}
    //   2. 如果在 jsRepresentation 上的属性查找失败,JS 运行时将
    //   搜索 jsRepresentation 的原型:jsi::Object(TurboModule)。
    //   3. TurboModule::get(runtime, propKey) 执行。这会创建
    //   属性,将其缓存在 jsRepresentation 上,然后将其返回给JavaScript
    auto hostObject =
        jsi::Object::createFromHostObject(runtime, std::move(module));
    jsRepresentation.setProperty(runtime, "__proto__", std::move(hostObject));

    return jsRepresentation; 
  } else {
    return jsi::Value::null();
  }
}

这里是通过moduleProvider_方法返回TurboModule实例。而moduleProvider_实际上就是TurboModuleBinding::install方法调用时设置的那个provider闭包。也就是上面分析的installJSBindings中的turboModuleProvider。回顾一下其实现:

auto turboModule = [self provideTurboModule:moduleName runtime:runtime];

闭包中是调用provideTurboModule返回turboModule,跟踪一下实现:

// RCTTurboModuleManager.mm


/**
 * 给定一个 TurboModule 的名称,返回一个 C++ 对象,该对象是
 * TurboModule C++ 类的实例。这个类包装了 TurboModule 的 ObjC 实例。
 * 如果不存在提供名称的 TurboModule ObjC 类,程序将中止。
 *
 * 注意:所有 TurboModule 实例都被缓存,这意味着它们都是长生命周期的(目前如此)
 */
- (std::shared_ptr<TurboModule>)provideTurboModule:(const char *)moduleName runtime:(jsi::Runtime *)runtime
{
  // 缓存查找
  auto turboModuleLookup = _turboModuleCache.find(moduleName);
  if (turboModuleLookup != _turboModuleCache.end()) {
    TurboModulePerfLogger::moduleJSRequireBeginningCacheHit(moduleName);
    TurboModulePerfLogger::moduleJSRequireBeginningEnd(moduleName);
    return turboModuleLookup->second;
  }

  TurboModulePerfLogger::moduleJSRequireBeginningEnd(moduleName);

 /**
  * 步骤 1:查找纯 C++ 模块。
  * 纯 C++ 模块具有优先级。
  */
  if ([_delegate respondsToSelector:@selector(getTurboModule:jsInvoker:)]) {
    int32_t moduleId = getUniqueId();
    TurboModulePerfLogger::moduleCreateStart(moduleName, moduleId);
    // 尝试从代理获取纯 C++ TurboModule
    auto turboModule = [_delegate getTurboModule:moduleName jsInvoker:_jsInvoker];
    if (turboModule != nullptr) {
      _turboModuleCache.insert({moduleName, turboModule});
      TurboModulePerfLogger::moduleCreateEnd(moduleName, moduleId);
      return turboModule;
    }

    TurboModulePerfLogger::moduleCreateFail(moduleName, moduleId);
  }

  // 在全局导出的 C++ TurboModule 映射中查找
  auto &cxxTurboModuleMapProvider = globalExportedCxxTurboModuleMap();
  auto it = cxxTurboModuleMapProvider.find(moduleName);
  if (it != cxxTurboModuleMapProvider.end()) {
    auto turboModule = it->second(_jsInvoker);
    _turboModuleCache.insert({moduleName, turboModule});
    return turboModule;
  }

  /**
   * 步骤 2:查找平台特定模块
   */
  id<RCTModuleProvider> module = [self _moduleProviderForName:moduleName];

  TurboModulePerfLogger::moduleJSRequireEndingStart(moduleName);

  // 如果我们请求创建一个 TurboModule,其相应的 ObjC 类必须存在
  // 如果类不存在,那么 _provideObjCModule 返回 nil
  if (!module) {
    return nullptr;
  }

  std::shared_ptr<NativeMethodCallInvoker> nativeMethodCallInvoker = nullptr;
  dispatch_queue_t methodQueue = (dispatch_queue_t)objc_getAssociatedObject(module, &kAssociatedMethodQueueKey);
  if (methodQueue) {
    /**
     * 步骤 2c:从 TurboModule 的方法队列创建原生 CallInvoker。
     */
    nativeMethodCallInvoker = std::make_shared<ModuleNativeMethodCallInvoker>(methodQueue);

    /**
     * 让 RCTCxxBridge 装饰原生 CallInvoker,使其能够感知 TurboModule 异步方法调用。
     * 这有助于桥接器及时触发 onBatchComplete。
     */
    if ([_bridge respondsToSelector:@selector(decorateNativeMethodCallInvoker:)]) {
      nativeMethodCallInvoker = [_bridge decorateNativeMethodCallInvoker:nativeMethodCallInvoker];
    }
  }

该方法是多级查找策略。查找优先级:

  1. 缓存查找 (最高优先级)
  2. 代理提供的纯 C++ 模块
  3. 全局 C++ 模块映射
  4. 平台特定 ObjC 模块 (最低优先级)

我们先跟踪一下纯C++ TurboModule的查找流程,这里的代理查找,其实最终就是调用DefaultTurboModules::getTurboModule(name, jsInvoker),这是前面已经得到的结论。来看一下其实现,源码react-native/packages/react-native/ReactCommon/react/nativemodule/defaults/DefaultTurboModules.cpp

/* static */ std::shared_ptr<TurboModule> DefaultTurboModules::getTurboModule(
    const std::string& name,
    const std::shared_ptr<CallInvoker>& jsInvoker) {
  if (name == NativeReactNativeFeatureFlags::kModuleName) {
    return std::make_shared<NativeReactNativeFeatureFlags>(jsInvoker);
  }

  if (name == NativeMicrotasks::kModuleName) {
    return std::make_shared<NativeMicrotasks>(jsInvoker);
  }

  if (name == NativeIdleCallbacks::kModuleName) {
    return std::make_shared<NativeIdleCallbacks>(jsInvoker);
  }

  if (name == NativeDOM::kModuleName) {
    return std::make_shared<NativeDOM>(jsInvoker);
  }

  if (ReactNativeFeatureFlags::enableWebPerformanceAPIsByDefault()) {
    if (name == NativePerformance::kModuleName) {
      return std::make_shared<NativePerformance>(jsInvoker);
    }
  }

  if (ReactNativeFeatureFlags::enableIntersectionObserverByDefault()) {
    if (name == NativeIntersectionObserver::kModuleName) {
      return std::make_shared<NativeIntersectionObserver>(jsInvoker);
    }
  }

#ifdef REACT_NATIVE_DEBUGGER_ENABLED_DEVONLY
  if (name == DevToolsRuntimeSettingsModule::kModuleName) {
    return std::make_shared<DevToolsRuntimeSettingsModule>(jsInvoker);
  }
#endif

  return nullptr;
}

可见,此处都是RN内置的一些模块。第三方要实现纯C++ TurboModule,那么注册集成就得考虑从globalExportedCxxTurboModuleMap中下手了。

现在继续查看_moduleProviderForName方法实现:

- (id<RCTModuleProvider>)_moduleProviderForName:(const char *)moduleName
{
  id<RCTModuleProvider> moduleProvider = nil;
  // 从代理获取模块提供者
  if ([_delegate respondsToSelector:@selector(getModuleProvider:)]) {
    moduleProvider = [_delegate getModuleProvider:moduleName];
  }

  if (RCTTurboModuleInteropEnabled() && ![self _isTurboModule:moduleName] && !moduleProvider) {
    return nil;
  }

  if (moduleProvider) {
    if ([moduleProvider conformsToProtocol:@protocol(RCTTurboModule)]) {
      // 如果模块提供者符合 RCTTurboModule 协议,需要初始化 ObjC 属性(如调度队列)
      return (id<RCTModuleProvider>)[self _provideObjCModule:moduleName moduleProvider:moduleProvider];
    }
    // 否则直接返回(C++ 模块)
    return moduleProvider;
  }

  // 如果没有找到模块提供者,尝试创建通过传统方式注册的 ObjC 模块
  return (id<RCTModuleProvider>)[self _provideObjCModule:moduleName moduleProvider:nil];
}


/**
 * 给定一个 NativeModule 的名称,返回该 NativeModule Objective-C 类的实例对象。如果不存在名称与给定名称匹配的 NativeModule,则返回 nil。
 *
 * 注意:所有 NativeModule 实例都会被缓存,这意味着它们都是长期存在的(目前是这样)。
 */
- (id<RCTBridgeModule>)_provideObjCModule:(const char *)moduleName moduleProvider:(id<RCTModuleProvider>)moduleProvider
{
  if (strncmp("RCT", moduleName, 3) == 0) {
    moduleName = [[[NSString stringWithUTF8String:moduleName] substringFromIndex:3] UTF8String];
  }

  ModuleHolder *moduleHolder = [self _getOrCreateModuleHolder:moduleName];

  if (!moduleHolder) {
    return nil;
  }

  TurboModulePerfLogger::moduleCreateStart(moduleName, moduleHolder->getModuleId());
  id<RCTBridgeModule> module = [self _provideObjCModule:moduleName
                                           moduleHolder:moduleHolder
                                          shouldPerfLog:YES
                                         moduleProvider:moduleProvider];

  if (module) {
    TurboModulePerfLogger::moduleCreateEnd(moduleName, moduleHolder->getModuleId());
  } else {
    TurboModulePerfLogger::moduleCreateFail(moduleName, moduleHolder->getModuleId());
  }

  return module;
}

// 获取或者创建一个ModuleHolder
- (ModuleHolder *)_getOrCreateModuleHolder:(const char *)moduleName
{
  std::lock_guard<std::mutex> guard(_moduleHoldersMutex);
  if (_invalidating) {
    return nullptr;
  }

  return &_moduleHolders[moduleName];
}

// 创建和管理 Objective-C 原生模块的实例,确保线程安全和单例模式
- (id<RCTBridgeModule>)_provideObjCModule:(const char *)moduleName
                             moduleHolder:(ModuleHolder *)moduleHolder
                            shouldPerfLog:(BOOL)shouldPerfLog
                           moduleProvider:(id<RCTModuleProvider>)moduleProvider
{
  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) {
    /**
     * 步骤 2a:解析特定于平台的类
     */
    Class moduleClass = moduleProvider ? [moduleProvider class] : [self _getModuleClassFromName:moduleName];

    __block id<RCTBridgeModule> module = nil;

    // 判断是否应该创建模块(检查是否实现了RCTTurboModule协议)
    if ([self _shouldCreateObjCModule:moduleClass]) {
      __weak __typeof(self) weakSelf = self;
      dispatch_block_t work = ^{
        auto strongSelf = weakSelf;
        if (!strongSelf) {
          return;
        }
        module = [strongSelf _createAndSetUpObjCModule:moduleClass moduleName:moduleName moduleId:moduleHolder
                      ->getModuleId()];
      };

      // 某些模块需要在主线程初始化
      if ([self _requiresMainQueueSetup: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):
     * 如果负责创建和初始化 NativeModule 的线程发生阻塞,我们将在此处无限期等待
     * 这是传统 NativeModule 的行为。现在更改此行为可能会导致 TurboModule 中出现比 NativeModule 更多的崩溃/问题
     * 从而使 TurboModule 基础设施的测试更加困难。因此,我们应该考虑在 TurboModule 全面推广之后再进行更改
     */
    moduleHolder->cv().wait(guard);
  }

  return moduleHolder->getModule();
}

接下继续跟踪_createAndSetUpObjCModule实现:

/**
 * 给定一个 NativeModule 类及其名称,同步创建并初始化它。
 *
 * 此方法可以从两个不同的上下文中同步调用:
 *  - 调用 _provideObjCModule: 的线程
 *  - 主线程(如果 NativeModule 需要主队列初始化),阻塞调用 _provideObjCModule: 的线程。
 */
- (id<RCTBridgeModule>)_createAndSetUpObjCModule:(Class)moduleClass
                                      moduleName:(const char *)moduleName
                                        moduleId:(int32_t)moduleId
{
  id<RCTBridgeModule> module = nil;

  /**
   * 步骤 2b:请求宿主应用/代理来实例化此类
   */

  module = [self _getModuleInstanceFromClass:moduleClass];

  TurboModulePerfLogger::moduleCreateSetUpStart(moduleName, moduleId);

 /**
  * NativeModules 不需要/不想要 bridge 是合理的。
  * 在这种情况下,它们的实现中不会有 `@synthesize bridge = _bridge`,
  * ObjC 运行时也不会生成 `- (RCTBridge *) bridge { ... }` 方法。
  * 该属性也不会有 ivar 支持,这使得写入它变得不安全。
  * 因此,我们检查此方法是否存在,以确定是否可以安全地将 bridge 设置到 NativeModule。
  */
  if ([module respondsToSelector:@selector(bridge)] && (_bridge || _bridgeProxy)) {
    /**
      * 仅仅因为 NativeModule 有 `bridge` 方法,并不意味着
      * 它在其实现中合成了 bridge。因此,
      * 我们需要将设置 bridge 到 NativeModule 的代码
      * 包裹在 try/catch 中。这可以捕获 NativeModule
      * 作者手动指定 `bridge` 方法的情况。
      */
    @try {
        /**
         * RCTBridgeModule 将 bridge 属性声明为只读。
         * 因此,当 NativeModules 的作者通过 @synthesize bridge = bridge; 合成 bridge 时,
         * ObjC 运行时只生成 - (RCTBridge *) bridge: { ... } 方法。
         * 没有生成 setter,所以我们必须依赖 ObjC 的 KVC API
         * 来设置这些 NativeModules 的 bridge 属性。
         */
      if (_bridge) {
        [(id)module setValue:_bridge forKey:@"bridge"];
      } else if (_bridgeProxy) {
        [(id)module setValue:_bridgeProxy 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]));
    }
  }

  // 这是 conformsToProtocol:@protocol(RCTCallInvokerModule) 的更高性能替代方案
  if ([module respondsToSelector:@selector(setCallInvoker:)]) {
    RCTCallInvoker *callInvoker = [[RCTCallInvoker alloc] initWithCallInvoker:_jsInvoker];
    [(id<RCTCallInvokerModule>)module setCallInvoker:callInvoker];
  }

 /**
  * 一些模块需要自己的队列,但没有提供,所以我们需要为它们创建。
  * 这些模块通常有以下内容:
  *   `@synthesize methodQueue = _methodQueue`
  */

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

  if (moduleHasMethodQueueGetter) {
    methodQueue = [(id<RCTBridgeModule>)module methodQueue];
  }

  /**
   * 注意:RCTJSThread 是一个有效的方法队列,定义为 (id)kCFNull。
   * 它应该正确地不进入以下 if 条件块。
   */
  if (!methodQueue) {
    methodQueue = _sharedModuleQueue;

    if (moduleHasMethodQueueGetter) {
        /**
         * 如果模块有方法队列 getter,有两种情况:
         *  - 我们 @synthesize 了方法队列。在这种情况下,getter 最初会返回 nil。
         *  - 我们在 NativeModule 上有自定义的 methodQueue 函数。如果我们走到这里,
         *    那么该 getter 返回了 nil。
         *
         * 因此,我们使用 try/catch 和 ObjC 的 KVC API 尝试将方法队列分配给 NativeModule。
         * 在情况 1 中,我们会成功。在情况 2 中,会抛出异常,我们将忽略它。
         */

      @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]));
      }
    }
  }

  /**
   * 用 bridgeless 兼容的 API 装饰 NativeModules,这些 API 会调用 bridge。
   */
  if (_bridgeModuleDecorator) {
    [_bridgeModuleDecorator attachInteropAPIsToModule:module];
  }

  /**
   * 如果 NativeModule 符合 RCTInitializing 协议,调用其 initialize 方法
   */
  if ([module respondsToSelector:@selector(initialize)]) {
    [(id<RCTInitializing>)module initialize];
  }

#if RCT_DEV_MENU

  [_devMenuConfigurationDecorator decorate:module];

#endif

  /**
   * 将方法队列附加到 id<RCTBridgeModule> 对象。
   * 这是必要的,因为 id<RCTBridgeModule> 对象可以在需要方法队列之前被急切地创建/初始化。
   * 方法队列用于 id<RCTBridgeModule> 的 JS -> Native 调用。
   * 因此,我们需要在 provideTurboModule:runtime: 中创建 id<RCTBridgeModule> 的 
   * TurboModule jsi::HostObject 之前拥有它。
   */
  objc_setAssociatedObject(module, &kAssociatedMethodQueueKey, methodQueue, OBJC_ASSOCIATION_RETAIN);

  /**
   * 广播此 NativeModule 已创建
   *
   * 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;
}

这个方法实现很长,但其实就是创建 ObjC 模块实例并注入所有必要的依赖。具体说,就是:

  • 注入 BridgeProxy,让模块能调用 JS

  • 注入 CallInvoker,新架构的 JSI 调用机制

  • 配置方法队列,模块的异步方法在此队列执行

继续查看_getModuleInstanceFromClass方法的实现:

- (id<RCTBridgeModule>)_getModuleInstanceFromClass:(Class)moduleClass
{
  NSString *moduleNameStr = RCTBridgeModuleNameForClass(moduleClass);
  // 省略旧架构代码......

  id<RCTBridgeModule> module = (id<RCTBridgeModule>)[_delegate getModuleInstanceFromClass:moduleClass];

  if (!module) {
    module = [moduleClass new];
  }

  return module;
}

可见,最终还是通过代理的getModuleInstanceFromClass方法查找模块。前面已经分析过了,此方法最终也是调用RCTAppSetupDefaultModuleFromClass(moduleClass, self.delegate.dependencyProvider)方法查找,继续跟踪实现:

id<RCTTurboModule> RCTAppSetupDefaultModuleFromClass(Class moduleClass, id<RCTDependencyProvider> dependencyProvider)
{
  // private block used to filter out modules depending on protocol conformance
  NSArray * (^extractModuleConformingToProtocol)(RCTModuleRegistry *, Protocol *) =
      ^NSArray *(RCTModuleRegistry *moduleRegistry, Protocol *protocol) {
        NSArray<NSString *> *classNames = @[];

        if (protocol == @protocol(RCTImageURLLoader)) {
          classNames = (dependencyProvider != nullptr) ? dependencyProvider.imageURLLoaderClassNames : @[];
        } else if (protocol == @protocol(RCTImageDataDecoder)) {
          classNames = (dependencyProvider != nullptr) ? dependencyProvider.imageDataDecoderClassNames : @[];
        } else if (protocol == @protocol(RCTURLRequestHandler)) {
          classNames = (dependencyProvider != nullptr) ? dependencyProvider.URLRequestHandlerClassNames : @[];
        }

        NSMutableArray *modules = [NSMutableArray new];

        for (NSString *className in classNames) {
          const char *cModuleName = [className cStringUsingEncoding:NSUTF8StringEncoding];
          id moduleFromLibrary = [moduleRegistry moduleForName:cModuleName];
          if (![moduleFromLibrary conformsToProtocol:protocol]) {
            continue;
          }
          [modules addObject:moduleFromLibrary];
        }
        return modules;
      };
  // 省略......

  // No custom initializer here.
  return [moduleClass new];
}

三方TurboModule显然不符合上面的if判断逻辑,那么最终其实就是通过[moduleClass new]创建了RCTTurboModule的实例对象。

TurboModule注册

自动链接

首先打开react-native工程中提供的helloworld工程,配置文件react-native/private/helloworld/ios/Podfile

target 'HelloWorld' do
  config = use_native_modules!(['sh', '../scripts/config.sh'])

  use_react_native!(
    :path => "../../../packages/react-native",
    # An absolute path to your application root.
    :app_path => "#{Pod::Config.instance.installation_root}/.."
  )

  target 'HelloWorldTests' do
    inherit! :complete
    # Pods for testing
  end

  post_install do |installer|
    # scripts/react_native_pods.rb
    react_native_post_install(
      installer,
      config[:reactNativePath],
      :mac_catalyst_enabled => false,
      # :ccache_enabled => true
    )
  end
end

在以上的CocoaPod配置脚本中,use_native_modules! 函数是iOS端自动链接 (Autolinking) 的核心,它负责发现并链接所有第三方原生库,源码react-native/packages/react-native/scripts/cocoapods/autolinking.rb

# 自动链接原生模块
#
# Parameters:
# - config_command: 用于获取应用程序当前配置的命令,例如 ['npx', '@react-native-community/cli', 'config'],
# 您可以根据需要覆盖此命令,以避免依赖项。例如 ['cat', 'your_config.json']
def use_native_modules!(config_command = $default_command)
  return link_native_modules!(list_native_modules!(config_command))
end

继续查看list_native_modules!函数:

# 如果您使用这种方法来列出 React Native 模块,您的项目必须依赖于 @react-native-community/cli
#
# Parameters:
# - config_command: 用于获取应用程序当前配置的命令,例如 ['npx', '@react-native-community/cli', 'config']
def list_native_modules!(config_command)

  if !(config_command.is_a? Array and config_command.size > 0)
    # 省略日志打印......
    exit(1)
  end

  # 1. 执行 CLI 命令获取项目配置
  # 忽略标准错误输出,我们只关心标准输出和返回码。库可能会向标准错误输出警告信息,这会给 JSON 反序列化带来问题
  json, _, status = Pod::Executable.capture_command(config_command[0], config_command[1..], capture: :both)

  if not status.success?
    # 省略日志输出......
    exit(status.exitstatus)
  end

  config = JSON.parse(json)
  # 2. 获取所有依赖包
  packages = config["dependencies"]
  ios_project_root = Pathname.new(config["project"]["ios"]["sourceDir"])
  react_native_path = Pathname.new(config["reactNativePath"])
  codegen_output_path = ios_project_root.join("build/generated/autolinking/autolinking.json")

  # 3. 将配置写入 autolinking.json (供 Codegen 使用)
  FileUtils.mkdir_p(File.dirname(codegen_output_path))
  File.write(codegen_output_path, json)

  found_pods = []

  # 4. 遍历所有包,检查是否有 iOS 配置
  packages.each do |package_name, package|
    next unless package_config = package["platforms"]["ios"]

    name = package["name"]
    podspec_path = package_config["podspecPath"]
    script_phases = package_config["scriptPhases"]
    configurations = package_config["configurations"]

    # 跳过没有 podspec 的包
    if podspec_path.nil? || podspec_path.empty?
      # 省略......
      next
    end

    spec = Pod::Specification.from_file(podspec_path)

    # 跳过不支持当前目标平台的环境。
    next unless AutolinkingUtils.is_platform_supported?(current_target_definition, spec)

    podspec_dir_path = Pathname.new(File.dirname(podspec_path))

    relative_path = podspec_dir_path.relative_path_from ios_project_root

    found_pods.push({
      "configurations": configurations,
      "name": name,
      "root": package["root"],
      "path": relative_path.to_path,
      "podspec_path": podspec_path,
      "script_phases": script_phases
    })
  end

  if found_pods.size > 0
    pods = found_pods.map { |p| p[:name] }.sort.to_sentence
    Pod::UI.puts "Found #{found_pods.size} #{"module".pluralize(found_pods.size)} for target `#{current_target_definition.name}`"
  end

  return {
    "ios_packages": found_pods,
    "ios_project_root_path": ios_project_root.to_s,
    "react_native_path": react_native_path.relative_path_from(ios_project_root).to_s
  }
end

该函数主要是发现第三方库并返回扫描到的数据,生成autolinking.json。接下来查看link_native_modules!函数实现:

# Parameters:
# - config:
#   - :ios_packages - React Native iOS 包数组, e.g. [{ package_name: "Foo", package: { .. }}, ...]
#   - :ios_project_root_path - React Native 项目的 iOS 文件夹的绝对路径, e.g. /Users/foobar/project/rn_project/ios
#   - :react_native_path - React Native 相对于项目根目录的相对路径, e.g. ./node_modules/react-native
def link_native_modules!(config)
  Pod::UI.puts "link_native_modules! #{config}"

  if !(
    config[:ios_packages].is_a? Array and
    config[:ios_project_root_path].is_a? String and
    config[:react_native_path].is_a? String
  )
    # 省略日志打印......
    exit(1)
  end
  # 提取项目根路径
  ios_project_root = config[:ios_project_root_path]
  # 提取包列表
  packages = config[:ios_packages]
  found_pods = []

  # 遍历包并自动链接
  packages.each do |package|
    podspec_path = package[:podspec_path]
    configurations = package[:configurations]

    # 如果 podspec_path 为 nil 或空,添加警告到队列并继续处理下一个依赖
    if podspec_path.nil? || podspec_path.empty?
      # 省略日志打印......
      next
    end
    # 读取并解析 .podspec 文件,获取包的完整规范信息。
    spec = Pod::Specification.from_file(podspec_path)

    # 检查该包是否支持当前平台(iOS),如果不支持,跳过该包
    next unless AutolinkingUtils.is_platform_supported?(current_target_definition, spec)

    # 我们想在当前 CocoaPods target 内部进行查找
    # 以查看它是否已包含,这样做可以:
    #   1. 给你一个机会预先定义它
    #   2. 确保 CocoaPods 不会因为包含两次而崩溃
    #
    this_target = current_target_definition
    existing_deps = current_target_definition.dependencies

    # 跳过用户已经自己激活的依赖
    next if existing_deps.find do |existing_dep|
      existing_dep.name.split('/').first == spec.name
    end

    podspec_dir_path = Pathname.new(File.dirname(podspec_path))

    relative_path = podspec_dir_path.relative_path_from ios_project_root

    # 将找到的 React Native 模块注册到我们的 Pods 集合中(调用 CocoaPods 的 pod DSL 方法,添加依赖)
    pod spec.name, :path => relative_path.to_path, :configurations => configurations

    if package[:script_phases] && !this_target.abstract?
      # 可以是一个对象,或对象数组
      Array(package[:script_phases]).each do |phase|
        # see https://www.rubydoc.info/gems/cocoapods-core/Pod/Podfile/DSL#script_phase-instance_method
        # 获取完整的对象键
        Pod::UI.puts "Adding a custom script phase for Pod #{spec.name}: #{phase["name"] || 'No name specified.'}"

        # 支持传入相对于包根目录的路径
        if phase["path"]
          phase["script"] = File.read(File.expand_path(phase["path"], package[:root]))
          phase.delete("path")
        end

        # 支持将执行位置转换为 symbol
        phase["execution_position"] = phase["execution_position"]&.to_sym

        phase = Hash[phase.map { |k, v| [k.to_sym, v] }]
        script_phase phase
      end
    end

    found_pods.push spec
  end

  if found_pods.size > 0
    pods = found_pods.map { |p| p.name }.sort.to_sentence
    # 省略打印......
  end

  return {
    :reactNativePath => config[:react_native_path]
  }
end

此函数就是在处理node_module中下载的依赖,最核心的其实就是pod spec.name, :path => relative_path.to_path, :configurations => configurations这行代码,它等价于我们习惯的类似配置:

pod 'react-native-camera', :path => '../node_modules/react-native-camera', :configurations => ['Debug', 'Release']

环境配置

弄清楚了use_native_modules!自动链接,接下来再看看use_react_native! 做了什么,源码react-native/packages/react-native/scripts/react_native_pods.rb

# 设置所有 React Native 依赖的函数
# 
# 参数
# - path: React Native 安装路径。
# - fabric_enabled: 是否应启用 Fabric。
# - new_arch_enabled: [已弃用] 是否应启用新架构。
# - :production [已弃用] 依赖是否必须安装到 Debug 或 Release 构建目标。
# - hermes_enabled: 是否应启用 Hermes。
# - app_path: React Native 应用的路径。新架构需要。
# - config_file_dir: `package.json` 文件的目录,新架构需要。
def use_react_native! (
  path: "../node_modules/react-native",
  fabric_enabled: false,
  new_arch_enabled: NewArchitectureHelper.new_arch_enabled,
  production: false, # 已弃用
  hermes_enabled: true, # 已弃用。Hermes 是默认引擎,JSC 已移至社区支持
  app_path: '..',
  config_file_dir: '',
  privacy_file_aggregation_enabled: true
)
  # 1.初始化和环境变量设置

  error_if_try_to_use_jsc_from_core()
  warn_if_new_arch_disabled()

  hermes_enabled= true
  # 将 app_path 设置为环境变量,以便 podspecs 可以访问它
  ENV['APP_PATH'] = app_path
  ENV['REACT_NATIVE_PATH'] = path

  # 如果用户想跳过从 CocoaPods 运行 Codegen 步骤,我们将 RCT_SKIP_CODEGEN 设置为 true。
  # 这是我们从 CocoaPods 迁移过程中所需的
  ENV['RCT_SKIP_CODEGEN'] = ENV['RCT_SKIP_CODEGEN'] == '1' || ENV['RCT_IGNORE_PODS_DEPRECATION'] == '1' ? '1' : '0'

  ReactNativePodsUtils.check_minimum_required_xcode()

  # 当前目标定义由 CocoaPods 提供,它指的是
  # 调用了 `use_react_native!` 函数的目标。
  ReactNativePodsUtils.detect_use_frameworks(current_target_definition)

  # 2.清理和版本检测

  CodegenUtils.clean_up_build_folder(path, $CODEGEN_OUTPUT_DIR)

  # 我们也在第三方库中依赖此标志来正确安装依赖。
  # 如果使用标志启用新架构,最好依赖并启用此环境标志。
  relative_path_from_current = Pod::Config.instance.installation_root.relative_path_from(Pathname.pwd)
  react_native_version = NewArchitectureHelper.extract_react_native_version(File.join(relative_path_from_current, path))
  fabric_enabled = true

  ENV['RCT_FABRIC_ENABLED'] = "1"
  ENV['RCT_AGGREGATE_PRIVACY_FILES'] = privacy_file_aggregation_enabled ? "1" : "0"
  ENV["RCT_NEW_ARCH_ENABLED"] = "1"

  # 3.依赖配置(配置 React Native 核心库)

  prefix = path

  ReactNativePodsUtils.warn_if_not_on_arm64()

  # 更新 ReactNativeDependencies,以便我们可以轻松地在源码和预构建之间切换
  ReactNativeDependenciesUtils.setup_react_native_dependencies(prefix, react_native_version)

  # 更新 ReactNativeCoreUtils,以便我们可以轻松地在源码和预构建之间切换
  ReactNativeCoreUtils.setup_rncore(prefix, react_native_version)

  Pod::UI.puts "Configuring the target with the New Architecture\n"

  # 应包含在所有项目中的 Pods
  pod 'FBLazyVector', :path => "#{prefix}/Libraries/FBLazyVector"
  pod 'RCTRequired', :path => "#{prefix}/Libraries/Required"
  pod 'RCTTypeSafety', :path => "#{prefix}/Libraries/TypeSafety", :modular_headers => true
  pod 'React', :path => "#{prefix}/"
  if !ReactNativeCoreUtils.build_rncore_from_source()
    pod 'React-Core-prebuilt', :podspec => "#{prefix}/React-Core-prebuilt.podspec", :modular_headers => true
  end
  pod 'React-Core', :path => "#{prefix}/"
  pod 'React-CoreModules', :path => "#{prefix}/React/CoreModules"
  pod 'React-RCTRuntime', :path => "#{prefix}/React/Runtime"
  # 省略部分......
  pod 'React-jsi', :path => "#{prefix}/ReactCommon/jsi"
  pod 'RCTSwiftUI', :path => "#{prefix}/ReactApple/RCTSwiftUI"
  pod 'RCTSwiftUIWrapper', :path => "#{prefix}/ReactApple/RCTSwiftUIWrapper"

  if hermes_enabled
    setup_hermes!(:react_native_path => prefix)
  end

  pod 'React-jsiexecutor', :path => "#{prefix}/ReactCommon/jsiexecutor"
  # 省略部分......
  pod 'ReactCommon/turbomodule/core', :path => "#{prefix}/ReactCommon", :modular_headers => true
  pod 'React-NativeModulesApple', :path => "#{prefix}/ReactCommon/react/nativemodule/core/platform/ios", :modular_headers => true
  pod 'Yoga', :path => "#{prefix}/ReactCommon/yoga", :modular_headers => true
  setup_fabric!(:react_native_path => prefix)
  setup_bridgeless!(:react_native_path => prefix, :use_hermes => hermes_enabled)

  if ReactNativeDependenciesUtils.build_react_native_deps_from_source()
    pod 'DoubleConversion', :podspec => "#{prefix}/third-party-podspecs/DoubleConversion.podspec"
    pod 'glog', :podspec => "#{prefix}/third-party-podspecs/glog.podspec"
    pod 'boost', :podspec => "#{prefix}/third-party-podspecs/boost.podspec"
    pod 'fast_float', :podspec => "#{prefix}/third-party-podspecs/fast_float.podspec"
    pod 'fmt', :podspec => "#{prefix}/third-party-podspecs/fmt.podspec", :modular_headers => true
    pod 'RCT-Folly', :podspec => "#{prefix}/third-party-podspecs/RCT-Folly.podspec", :modular_headers => true
    pod 'SocketRocket', "~> #{Helpers::Constants::socket_rocket_config[:version]}", :modular_headers => true
  else
    # Install prebuilt React Native Core and React Native Dependencies
    ReactNativeCoreUtils.rncore_log("Using React Native Core and React Native Dependencies prebuilt versions.")
    pod 'ReactNativeDependencies', :podspec => "#{prefix}/third-party-podspecs/ReactNativeDependencies.podspec", :modular_headers => true

    if !ReactNativeCoreUtils.build_rncore_from_source()
      pod 'React-Core-prebuilt', :podspec => "#{prefix}/React-Core-prebuilt.podspec", :modular_headers => true
    end
  end

  pod 'ReactCodegen', :path => $CODEGEN_OUTPUT_DIR, :modular_headers => true
  pod 'ReactAppDependencyProvider', :path => $APP_DEPENDENCY_PROVIDER_OUTPUT_DIR, :modular_headers => true
  # 不需要,但 run_codegen 期望设置此值。
  folly_config = get_folly_config()
  # 运行 Codegen:扫描所有 TurboModule 和 Fabric 组件规范,生成 C++ 绑定代码
  run_codegen!(
    app_path,
    config_file_dir,
    :new_arch_enabled => NewArchitectureHelper.new_arch_enabled,
    :disable_codegen => ENV['DISABLE_CODEGEN'] == '1',
    :react_native_path => prefix,
    :fabric_enabled => fabric_enabled,
    :hermes_enabled => hermes_enabled,
    :codegen_output_dir => $CODEGEN_OUTPUT_DIR,
    :package_json_file => File.join(__dir__, "..", "package.json"),
    :folly_version => folly_config[:version]
  )

  pods_to_update = LocalPodspecPatch.pods_to_update(:react_native_path => prefix)
  if !pods_to_update.empty?
    if Pod::Lockfile.public_instance_methods.include?(:detect_changes_with_podfile)
      Pod::Lockfile.prepend(LocalPodspecPatch)
    else
      # 省略打印......
    end
  end
end

此函数太长,这里省略了大部分的依赖配置项。这里总结一下该函数做的事:

  1. 配置环境:设置环境变量、检查 Xcode 版本

  2. 添加 60+ 个 Pod 依赖:涵盖从核心到工具的所有模块

  3. 设置新架构:Fabric、TurboModule、Bridgeless

  4. 配置 Hermes 引擎

  5. 运行 Codegen:自动生成 C++ 绑定代码

  6. 处理预构建二进制:加速编译

总的说,这是 React Native iOS 项目的"一键配置"函数,它设置了新架构所需的所有依赖和工具链。

代码生成

继续分析run_codegen!函数,探索iOS端,是如何自动生成代码的。源码react-native/packages/react-native/scripts/cocoapods/codegen.rb

def run_codegen!(
  app_path,                                              # 应用根目录路径(必需)
  config_file_dir,                                       # 配置文件目录(必需)
  new_arch_enabled: true,                                # 是否启用新架构(默认 true,但当前未使用)
  disable_codegen: false,                                # 是否禁用 Codegen(默认 false)
  react_native_path: "../node_modules/react-native",    # React Native 源码路径
  fabric_enabled: false,                                 # 是否启用 Fabric(默认 false)
  hermes_enabled: true,                                  # 是否启用 Hermes(默认 true)
  codegen_output_dir: 'build/generated/ios',            # Codegen 输出目录
  config_key: 'codegenConfig',                          # package.json 中配置键名
  package_json_file: '~/app/package.json',              # package.json 文件路径(当前未使用)
  folly_version: Helpers::Constants.folly_config()[:version], # Folly 库版本
  codegen_utils: CodegenUtils.new()                     # CodegenUtils 实例(可注入用于测试)
  )

  if ENV["RCT_SKIP_CODEGEN"] == "1"
    return
  end

  codegen_utils.use_react_native_codegen_discovery!(
    disable_codegen,
    app_path,
    :react_native_path => react_native_path,
    :fabric_enabled => fabric_enabled,
    :hermes_enabled => hermes_enabled,
    :config_file_dir => config_file_dir,
    :codegen_output_dir => codegen_output_dir,
    :config_key => config_key,
    :folly_version => folly_version
  )
end

可以看到,实际上是委托给 CodegenUtils 执行代码生成。继续查看源码react-native/packages/react-native/scripts/cocoapods/codegen_utils.rb

   def use_react_native_codegen_discovery!(
      codegen_disabled,
      app_path,
      react_native_path: "../node_modules/react-native",
      fabric_enabled: false,
      hermes_enabled: true,
      config_file_dir: '',
      codegen_output_dir: 'build/generated/ios',
      config_key: 'codegenConfig',
      folly_version: Helpers::Constants.folly_config[:version],
      codegen_utils: CodegenUtils.new(),
      file_manager: File,
      logger: CodegenUtils::UI
      )
      return if codegen_disabled

      if CodegenUtils.react_codegen_discovery_done()
        logger.puts("Skipping use_react_native_codegen_discovery.")
        return
      end

      if !app_path
        logger.warn("Error: app_path is required for use_react_native_codegen_discovery.")
        logger.warn("If you are calling use_react_native_codegen_discovery! in your Podfile, please remove the call and pass `app_path` and/or `config_file_dir` to `use_react_native!`.")
        abort
      end

      relative_installation_root = Pod::Config.instance.installation_root.relative_path_from(Pathname.pwd)

      out = Pod::Executable.execute_command(
        'node',
        [
          "#{relative_installation_root}/#{react_native_path}/scripts/generate-codegen-artifacts.js",
          "-p", "#{app_path}",
          "-o", Pod::Config.instance.installation_root,
          "-t", "ios",
        ])
      Pod::UI.puts out;
      #  标记完成,防止重复执行
      CodegenUtils.set_react_codegen_discovery_done(true)
    end

此处实际上仍然是调用JS工具来生成代码,这里执行的命令,相当于:

node node_modules/react-native/scripts/generate-codegen-artifacts.js \
  -p /narwal/Your Project/helloworld \
  -o /narwal/Your Project/helloworld/ios \
  -t ios

继续跟踪react-native/packages/react-native/scripts/generate-codegen-artifacts.js

const executor = require('./codegen/generate-artifacts-executor');
// 省略......
executor.execute(argv.path, argv.targetPlatform, argv.outputPath, argv.source);

查看execute实现,源码react-native/packages/react-native/scripts/codegen/generate-artifacts-executor/index.js

/**
 * 此函数是代码生成器的入口点。它执行以下操作:
 * - 读取 package.json 文件
 * - 提取库信息
 * - 设置命令行界面以生成代码
 * - 生成代码
 *
 * @param projectRoot:包含应用程序源代码的目录,package.json 文件位于该目录下。 
 * @param baseOutputPath:代码生成器的基本输出路径。 
 * @param targetPlatform:目标平台。支持的值包括:“android”、“ios”、“all”。 
 * @param source:调用代码生成器的来源。支持的值包括:“app”、“library”。 
 * @throws 如果找不到 React Native 的配置文件。 
 * @throws 如果在文件中找不到代码生成器配置。 
 * @throws 如果找不到代码生成器的命令行工具。
 */
function execute(
  projectRoot /*: string */,
  targetPlatform /*: string */,
  optionalBaseOutputPath /*: ?string */,
  source /*: string */,
  runReactNativeCodegen /*: boolean */ = true,
) {
  try {
    codegenLog(`Analyzing ${path.join(projectRoot, 'package.json')}`);

    const supportedPlatforms = ['android', 'ios'];
    if (
      targetPlatform !== 'all' &&
      !supportedPlatforms.includes(targetPlatform)
    ) {
      throw new Error(
        `Invalid target platform: ${targetPlatform}. Supported values are: ${supportedPlatforms.join(
          ', ',
        )}, all`,
      );
    }
    // 1.读取应用的 package.json
    const pkgJson = readPkgJsonInDirectory(projectRoot);

    if (runReactNativeCodegen) {
      // 2.如果 Codegen CLI 未构建,先执行 yarn build
      buildCodegenIfNeeded();
    }

    const platforms =
      targetPlatform === 'all' ? supportedPlatforms : [targetPlatform];

    // NOTE: We cache the external libraries search (which may not run) across platforms to not change previous behaviour
    const externalLibrariesCache /*: { current?: ?Array<$FlowFixMe> } */ = {};

    for (const platform of platforms) {
      // NOTE: This needs to be computed per-platform since `platform` can alter the path via a `package.json:codegenConfig.outputDir[platform]` override
      const baseOutputPath = computeBaseOutputPath(
        projectRoot,
        optionalBaseOutputPath,
        pkgJson,
        platform,
      );
      const reactNativeConfig = readReactNativeConfig(
        projectRoot,
        baseOutputPath,
      );
      // 3.扫描所有依赖库,找出包含 codegenConfig 的库
      const codegenEnabledLibraries = findCodegenEnabledLibraries(
        pkgJson,
        projectRoot,
        baseOutputPath,
        reactNativeConfig,
        externalLibrariesCache,
      );
      if (codegenEnabledLibraries.length === 0) {
        codegenLog('No codegen-enabled libraries found.', true);
      }

      const disabledLibraries = findDisabledLibrariesByPlatform(
        reactNativeConfig,
        platform,
      );
      const libraries = codegenEnabledLibraries.filter(
        ({name}) => !disabledLibraries.includes(name),
      );

      const outputPath = computeOutputPath(
        projectRoot,
        baseOutputPath,
        pkgJson,
        platform,
      );

      const reactCodegenOutputPath =
        platform === 'android'
          ? outputPath
          : path.join(outputPath, 'ReactCodegen');

      if (runReactNativeCodegen) {
        // 4.为每个库生成 Schema JSON(描述 TurboModule/Fabric 接口)
        const schemaInfos = generateSchemaInfos(libraries);
        // 5.根据 Schema 生成 C++/ObjC++ 代码
        generateNativeCode(
          reactCodegenOutputPath,
          schemaInfos.filter(schemaInfo =>
            mustGenerateNativeCode(projectRoot, schemaInfo),
          ),
          pkgJsonIncludesGeneratedCode(pkgJson),
          platform,
        );
      }

      if (source === 'app' && platform !== 'android') {
        // 6.生成 Fabric 第三方组件注册代码
        // These components are only required by apps, not by libraries and are Apple specific.
        generateRCTThirdPartyComponents(libraries, reactCodegenOutputPath);
        // 7.生成 TurboModule 提供者代码
        generateRCTModuleProviders(
          projectRoot,
          pkgJson,
          libraries,
          reactCodegenOutputPath,
        );
        // 8.生成自定义 URL Scheme 处理器
        generateCustomURLHandlers(libraries, reactCodegenOutputPath);
        generateUnstableModulesRequiringMainQueueSetupProvider(
          libraries,
          reactCodegenOutputPath,
        );
        // 9.生成应用级依赖提供者
        generateAppDependencyProvider(
          path.join(outputPath, 'ReactAppDependencyProvider'),
        );
        // 10.生成 ReactCodegen.podspec
        generateReactCodegenPodspec(
          projectRoot,
          pkgJson,
          reactCodegenOutputPath,
          baseOutputPath,
        );
        generatePackageSwift(
          projectRoot,
          outputPath,
          findReactNativeRootPath(projectRoot),
        );
      }

      cleanupEmptyFilesAndFolders(outputPath);
    }
  } catch (err) {
    codegenLog(err);
    process.exitCode = 1;
  }

  codegenLog('Done.', true);
  return;
}

我已经为上面10个比较关键的步骤增加了注释,流程还是很清晰的。由于这篇文章主要是研究iOS端TurboModule,那么需要重点关注一下generateRCTModuleProvidersgenerateAppDependencyProvider两个函数的实现。

源码react-native/packages/react-native/scripts/codegen/generate-artifacts-executor/generateRCTModuleProviders.js

const MODULE_PROVIDERS_H_TEMPLATE_PATH = path.join(
  TEMPLATES_FOLDER_PATH,
  'RCTModuleProvidersH.template',
);

const MODULE_PROVIDERS_MM_TEMPLATE_PATH = path.join(
  TEMPLATES_FOLDER_PATH,
  'RCTModuleProvidersMM.template',
);

function generateRCTModuleProviders(
  projectRoot /*: string */,
  pkgJson /*: $FlowFixMe */,
  libraries /*: $ReadOnlyArray<$FlowFixMe> */,
  outputDir /*: string */,
) {
  // 1.创建输出目录
  fs.mkdirSync(outputDir, {recursive: true});
  // 2.生成头文件 RCTModuleProviders.h
  codegenLog('Generating RCTModulesProvider.h');
  const templateH = fs.readFileSync(MODULE_PROVIDERS_H_TEMPLATE_PATH, 'utf8');
  const finalPathH = path.join(outputDir, 'RCTModuleProviders.h');
  fs.writeFileSync(finalPathH, templateH);
  codegenLog(`Generated artifact: ${finalPathH}`);

  codegenLog('Generating RCTModuleProviders.mm');
  // 3.初始化一个模块收集容器
  let modulesInLibraries /*: {[string]: Array<$FlowFixMe>} */ = {};

  let app = pkgJson.codegenConfig
    ? {config: pkgJson.codegenConfig, libraryPath: projectRoot}
    : null;

  // 4.将应用自身的 TurboModule 加入处理列表
  const moduleLibraries = libraries
    .concat(app)
    .filter(Boolean)
    .filter(({config, libraryPath}) => {
      // 5.过滤出需要处理的模块库
      if (isReactNativeCoreLibrary(config.name) || config.type === 'components') {
        return false;
      }
      return true;
    });

  // 6.收集旧 API 配置(modulesProvider 字段)
  moduleLibraries.forEach(({config, libraryPath}) => {
    const libraryName = JSON.parse(
      fs.readFileSync(path.join(libraryPath, 'package.json'), 'utf8'),
    ).name;

    if (config.ios?.modulesProvider) {
      modulesInLibraries[libraryName] = Object.keys(
        config.ios?.modulesProvider,
      ).map(moduleName => {
        return {
          moduleName,
          className: config.ios?.modulesProvider[moduleName],
        };
      });
    }
  });

  // 7.收集新 API 配置(modules 字段)
  const iosAnnotations = parseiOSAnnotations(moduleLibraries);
  for (const [libraryName, {modules: moduleAnnotationMap}] of Object.entries(
    iosAnnotations,
  )) {
    for (const [moduleName, annotation] of Object.entries(
      moduleAnnotationMap,
    )) {
      if (annotation.className) {
        modulesInLibraries[libraryName] = modulesInLibraries[libraryName] || [];
        modulesInLibraries[libraryName].push({
          moduleName,
          className: annotation.className,
        });
      }
    }
  }

  // 8.生成 Objective-C 映射代码
  const modulesMapping = Object.keys(modulesInLibraries)
    .flatMap(library => {
      const modules = modulesInLibraries[library];
      return modules.map(({moduleName, className}) => {
        return `\t\t@"${moduleName}": @"${className}", // ${library}`;
      });
    })
    .join('\n');

  // 9.将映射代码注入模板并写入文件
  const templateMM = fs
    .readFileSync(MODULE_PROVIDERS_MM_TEMPLATE_PATH, 'utf8')
    .replace(/{moduleMapping}/, modulesMapping);
  const finalPathMM = path.join(outputDir, 'RCTModuleProviders.mm');
  fs.writeFileSync(finalPathMM, templateMM);
  codegenLog(`Generated artifact: ${finalPathMM}`);
}

现在我们来看一个生成的RCTModuleProviders实例,源码Your Project/ios/build/generated/ios/ReactCodegen/RCTModuleProviders.mm

@implementation RCTModuleProviders

+ (NSDictionary<NSString *, id<RCTModuleProvider>> *)moduleProviders
{
  static NSDictionary<NSString *, id<RCTModuleProvider>> *providers = nil;
  static dispatch_once_t onceToken;

  dispatch_once(&onceToken, ^{
    NSDictionary<NSString *, NSString *> * moduleMapping = @{
              @"RNCWebViewModule": @"RNCWebViewModule", // react-native-webview
    };

    NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:moduleMapping.count];

    for (NSString *key in moduleMapping) {
      NSString * moduleProviderName = moduleMapping[key];
      Class klass = NSClassFromString(moduleProviderName);
      if (!klass) {
        RCTLogError(@"Module provider %@ cannot be found in the runtime", moduleProviderName);
        continue;
      }

      id instance = [klass new];
      if (![instance respondsToSelector:@selector(getTurboModule:)]) {
        RCTLogError(@"Module provider %@ does not conform to RCTModuleProvider", moduleProviderName);
        continue;
      }

      [dict setObject:instance forKey:key];
    }

    providers = dict;
  });

  return providers;
}

这是一个懒加载 + 单例模式的实现。使用NSClassFromString通过字符串反射查找类,然后[klass new]实例化 Provider 并验证协议。

最后再来看generateAppDependencyProvider实现,源码react-native/packages/react-native/scripts/codegen/generate-artifacts-executor/generateAppDependencyProvider.js

function generateAppDependencyProvider(outputDir /*: string */) {
  fs.mkdirSync(outputDir, {recursive: true});
  codegenLog('Generating RCTAppDependencyProvider');

  const templateH = fs.readFileSync(
    APP_DEPENDENCY_PROVIDER_H_TEMPLATE_PATH,
    'utf8',
  );
  const finalPathH = path.join(outputDir, 'RCTAppDependencyProvider.h');
  fs.writeFileSync(finalPathH, templateH);
  codegenLog(`Generated artifact: ${finalPathH}`);

  const templateMM = fs.readFileSync(
    APP_DEPENDENCY_PROVIDER_MM_TEMPLATE_PATH,
    'utf8',
  );
  const finalPathMM = path.join(outputDir, 'RCTAppDependencyProvider.mm');
  fs.writeFileSync(finalPathMM, templateMM);
  codegenLog(`Generated artifact: ${finalPathMM}`);

  // Generate the podspec file
  const templatePodspec = fs
    .readFileSync(APP_DEPENDENCY_PROVIDER_PODSPEC_TEMPLATE_PATH, 'utf8')
    .replace(/{react-native-version}/, packageJson.version)
    .replace(/{react-native-licence}/, packageJson.license);
  const finalPathPodspec = path.join(
    outputDir,
    'ReactAppDependencyProvider.podspec',
  );
  fs.writeFileSync(finalPathPodspec, templatePodspec);
  codegenLog(`Generated podspec: ${finalPathPodspec}`);
}

此方法生成一个 统一的依赖提供者类(RCTAppDependencyProvider),它将之前生成的所有 Codegen 产物(TurboModule、Fabric 组件、URL 处理器等)聚合到一个统一接口中,供 React Native 运行时使用。

我们直接看生成之后的文件,源码Your Project/ios/build/generated/ios/ReactAppDependencyProvider/RCTAppDependencyProvider.mm

@implementation RCTAppDependencyProvider

- (nonnull NSArray<NSString *> *)URLRequestHandlerClassNames {
  return RCTModulesConformingToProtocolsProvider.URLRequestHandlerClassNames;
}

- (nonnull NSArray<NSString *> *)imageDataDecoderClassNames {
  return RCTModulesConformingToProtocolsProvider.imageDataDecoderClassNames;
}

- (nonnull NSArray<NSString *> *)imageURLLoaderClassNames {
  return RCTModulesConformingToProtocolsProvider.imageURLLoaderClassNames;
}

- (nonnull NSArray<NSString *> *)unstableModulesRequiringMainQueueSetup {
  return RCTUnstableModulesRequiringMainQueueSetupProvider.modules;
}

- (nonnull NSDictionary<NSString *,Class<RCTComponentViewProtocol>> *)thirdPartyFabricComponents {
  return RCTThirdPartyComponentsProvider.thirdPartyFabricComponents;
}

- (nonnull NSDictionary<NSString *, id<RCTModuleProvider>> *)moduleProviders {
  return RCTModuleProviders.moduleProviders;
}

@end

到此,基本上就闭环了。在本文开头,我们就分析了delegate.dependencyProvider = RCTAppDependencyProvider(),而在getModuleProvider方法实现中,self.dependencyProvider != nullptr) ? self.dependencyProvider.moduleProviders[providerName] : nullptr一行,正是从RCTModuleProviders.moduleProviders中查找模块。

❌