基于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() | 是否懒加载 ViewManager | FALSE |
| getShouldRequireActivity() | 是否要求必须有 Activity | TRUE |
| 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
}