ReactNative 源码分析2——Application初始化

6 阅读3分钟

基于RN0.77 源码

RN集成初始化最简代码大概是下面这样的,有两个比较重要类:

  • ReactNativeHost:它其实就是RN框架提供给外部可以自由定制化的一个实现类,在旧架构中就是存在的
  • ReactHost:这是新架构引入的,它其实也是依赖ReactNativeHost的
class MainApplication : Application(), ReactApplication {
  override val reactNativeHost: ReactNativeHost =
      object : DefaultReactNativeHost(this) {
        override fun getPackages(): List<ReactPackage> =
            PackageList(this).packages.apply  {
               add(MyReactNativePackage())
            }

override fun getJSMainModuleName(): String = "index"

override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG

override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
}

  override val reactHost: ReactHost
    get() = DefaultReactHost.getDefaultReactHost(applicationContext, reactNativeHost)

  override fun onCreate() {
    super.onCreate()
    SoLoader.init(this, OpenSourceMergedSoMapping)
    if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
      // If you opted-in for the New Architecture, we load the native entry point for this app.
        DefaultNewArchitectureEntryPoint.load()
    }
  }
}

ReactNativeHost

DefaultReactNativeHost是ReactNativeHost默认抽象实现类,ReactNativeHost提供了外部可扩展的函数

配置方法(可重写)

方法作用默认值
getUseDeveloperSupport()(抽象) 是否启用开发模式(Dev 菜单、热更新等)
getPackages()(抽象) 返回 Native Module 和 View Manager 的包列表
getJSMainModuleName()JS 入口模块名,决定 Metro 的 URL"index.android"
getJSBundleFile()自定义 bundle 文件路径(如从 SD 卡加载)null
getBundleAssetName()assets 中的 bundle 文件名"index.android.bundle"
getJSEngineResolutionAlgorithm()JS 引擎选择策略(Hermes / JSC)null(自动选择)
getRedBoxHandler()红屏错误处理器null
getJSExceptionHandler()JS 异常处理器null
getJavaScriptExecutorFactory()自定义 JS 执行器工厂null
getUIManagerProvider()UI 管理器提供者(新架构 Fabric 相关)返回 null
getReactPackageTurboModuleManagerDelegateBuilder()TurboModule 管理器(新架构)null
getLazyViewManagersEnabled()是否懒加载 ViewManagerFALSE
getShouldRequireActivity()是否要求必须有 ActivityTRUE
getSurfaceDelegateFactory()Surface 交互代理工厂返回 null
getDevSupportManagerFactory()自定义 Dev 支持管理器工厂null
getDevLoadingViewManager()开发加载进度视图管理器null
getPausedInDebuggerOverlayManager()调试器暂停覆盖层管理器null
getChoreographerProvider()自定义 Choreographer 提供者null

ReactNativeHost中mReactInstanceManager字段非常重要,它是ReactInstance实例管理器,一个ReactInstance表示一个React应用

private @Nullable ReactInstanceManager mReactInstanceManager;

protected ReactInstanceManager createReactInstanceManager() {
  ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_START);
  ReactInstanceManagerBuilder builder = getBaseReactInstanceManagerBuilder();
  ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_END);
  return builder.build();
}

mReactInstanceManager是通过createReactInstanceManager进行创建的,getBaseReactInstanceManagerBuilder会用到"配置方法"来创建ReactInstanceManager,这就是"配置方法"的作用;

后面我们分析启动流程时会讲到createReactInstanceManager是怎么被调用的,以及ReactInstanceManager的创建

ReactHost

再看看ReactHost初始化,DefaultReactHost是一个单例,这个单例让我在实际项目中开发遇到很有意思的一个现象,文末聊

override val reactHost: ReactHost
  get() = DefaultReactHost.getDefaultReactHost(applicationContext, reactNativeHost)
  
public fun getDefaultReactHost(
    context: Context,
    reactNativeHost: ReactNativeHost,
): ReactHost {
  require(reactNativeHost is DefaultReactNativeHost) {
 "You can call getDefaultReactHost only with instances of DefaultReactNativeHost"
}
return reactNativeHost.toReactHost(context)
}

getDefaultReactHost中实际上是调用的DefaultReactNativeHost.toReactHost,我们思考一下为什么这样?原因是新架构ReactHost初始化也需要用到“配置方法”,但因为历史原因“配置方法”都是在ReactNativeHost中的,所以这里“借用”了DefaultReactNativeHost获取到里面的“配置方法”

@UnstableReactNativeAPI
internal fun toReactHost(context: Context): ReactHost =
    DefaultReactHost.getDefaultReactHost(
        context,
        packages,
        jsMainModuleName,
        bundleAssetName ?: "index" ,
        jsBundleFile,
        isHermesEnabled ?: true,
        useDeveloperSupport,
    )

然后又回到DefaultReactHost中,构造返回ReactHostImpl

总结一下:

  • 旧架构:ReactNativeHost-->ReactInstanceManager

  • 新架构:ReactHostImpl

这里回到DefaultReactHost单例,可以看出RN的设计就是一个RN应用对应一个ReactHostImpl;

但是在我们的业务场景中有这样一个需求:多个RN应用彼此独立,也就是需要有多个ReactHostImpl,要想满足这样的需求就需要自定义ReactHost,而不能直接使用DefaultReactHost,因为它不支持创建多个

public fun getDefaultReactHost(
    context: Context,
    packageList: List<ReactPackage>,
    jsMainModulePath: String = "index" ,
    jsBundleAssetPath: String = "index" ,
    jsBundleFilePath: String? = null,
    isHermesEnabled: Boolean = true,
    useDevSupport: Boolean = ReactBuildConfig.DEBUG,
    cxxReactPackageProviders: List<(ReactContext) -> CxxReactPackage> = emptyList(),
    exceptionHandler: (Exception) -> Unit = { throw it } ,
): ReactHost {
  if (reactHost == null) {
        .....
  }
  return reactHost as ReactHost
}