基于ReactApplication的原生Android应用如何加载多React Native Bundle?
核心思路
由于ReactApplication接口要求返回单一ReactNativeHost,但我们可以通过为每个Bundle创建独立的ReactNativeHost实例,并让自定义ReactActivity根据需求选择对应的Host,实现多Bundle的隔离加载。同时保持对react-navigation的兼容,因为ReactActivity的生命周期依然能满足导航需求。
实现步骤
1. 在Application中管理多个ReactNativeHost
在自定义Application中,为每个Bundle创建独立的ReactNativeHost,并通过Map存储以便后续获取:
class MyCoolApplication : Application(), ReactApplication { private val reactHostMap = mutableMapOf<String, ReactNativeHost>() override fun onCreate() { super.onCreate() // 初始化两个Bundle对应的Host reactHostMap["mycoolapp1.bundle"] = createReactHost("mycoolapp1.bundle") reactHostMap["mycoolapp2.bundle"] = createReactHost("mycoolapp2.bundle") } private fun createReactHost(bundleName: String): ReactNativeHost { return object : DefaultReactNativeHost(this) { override fun getBundleAssetName(): String? = bundleName override fun getJSMainModuleName(): String = "index" override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG override fun getPackages(): List<ReactPackage> { return PackageList(this).packages.apply { // 在此添加自定义RN原生包,所有Bundle共享的包只需添加一次 } } } } // 对外提供获取指定Bundle对应Host的方法 fun getReactHostForBundle(bundleName: String): ReactNativeHost? = reactHostMap[bundleName] // 实现ReactApplication接口的默认Host返回(可选,用任意一个Bundle的Host即可) override fun getReactNativeHost(): ReactNativeHost = reactHostMap["mycoolapp1.bundle"]!! }
2. 自定义ReactActivity以支持动态选择Host
创建自定义ReactActivity,重写getReactNativeHost和getMainComponentName方法,根据启动时传递的Bundle参数选择对应的Host和RN组件名:
class CustomRNActivity : ReactActivity() { companion object { const val EXTRA_BUNDLE_NAME = "bundle_name" const val EXTRA_COMPONENT_NAME = "component_name" } override fun getReactNativeHost(): ReactNativeHost { val bundleName = intent.getStringExtra(EXTRA_BUNDLE_NAME) ?: "mycoolapp1.bundle" return (application as MyCoolApplication).getReactHostForBundle(bundleName)!! } override fun getMainComponentName(): String? { // 可以直接通过Intent传递组件名,或根据Bundle名称映射 return intent.getStringExtra(EXTRA_COMPONENT_NAME) ?: when(val bundleName = intent.getStringExtra(EXTRA_BUNDLE_NAME)) { "mycoolapp1.bundle" -> "MyCoolApp1" "mycoolapp2.bundle" -> "MyCoolApp2" else -> "MyCoolApp1" } } }
3. 启动对应Bundle的RN页面
在原生Android页面中,通过Intent传递Bundle名称和组件名,启动自定义的CustomRNActivity:
// 加载第一个RN Bundle startActivity(Intent(this, CustomRNActivity::class.java).apply { putExtra(CustomRNActivity.EXTRA_BUNDLE_NAME, "mycoolapp1.bundle") putExtra(CustomRNActivity.EXTRA_COMPONENT_NAME, "MyCoolApp1") }) // 加载第二个RN Bundle startActivity(Intent(this, CustomRNActivity::class.java).apply { putExtra(CustomRNActivity.EXTRA_BUNDLE_NAME, "mycoolapp2.bundle") putExtra(CustomRNActivity.EXTRA_COMPONENT_NAME, "MyCoolApp2") })
4. 打包RN Bundle(注意事项)
为每个RN项目打包时,指定不同的Bundle文件名,避免冲突:
# 打包第一个RN应用 react-native bundle --platform android --dev false --entry-file index.js --bundle-output ../android/app/src/main/assets/mycoolapp1.bundle --assets-dest ../android/app/src/main/res/react1 # 打包第二个RN应用 react-native bundle --platform android --dev false --entry-file index.js --bundle-output ../android/app/src/main/assets/mycoolapp2.bundle --assets-dest ../android/app/src/main/res/react2
若两个RN应用的资源(图片、字符串等)存在命名冲突,需将资源打包到不同的res子目录(如上述的
react1、react2),并在Android项目中配置资源目录:
在app/build.gradle中添加:sourceSets { main { res.srcDirs += 'src/main/res/react1' res.srcDirs += 'src/main/res/react2' } }
关键优势
- 每个Bundle拥有独立的
ReactInstanceManager,JS环境完全隔离,避免状态污染 - 保持对
react-navigation的兼容,ReactActivity的生命周期能满足RN导航的需求 - 原生模块可通过共享Package列表实现复用,减少冗余代码
内容的提问来源于stack exchange,提问作者Mando
相关产品推荐
相关产品推荐

