基于React Native 0.83.1 新架构下的拆包方案

React Native 0.83.1 新架构(New Architecture) 下的拆包方案


React Native 0.83.1 新架构拆包实战:基于 ReactHost 与单 Runtime 的动态加载方案

随着 React Native 进入 0.80+ 时代,新架构(Fabric & TurboModules)已成为主流。传统的基于 ReactInstanceManager 和 Bridge 的拆包方式已逐步过时。本文将介绍在 RN 0.83.1 版本下,如何利用 ReactHostJSIHermes Runtime 实现高性能的模块化拆包与动态加载。


一、 为什么旧的拆包方案失效了?

在新架构中,底层通信机制从传统的 JSON Bridge 转向了基于 C++ 的 JSI (JavaScript Interface)

特性 Legacy 架构 (旧) 新架构 (Fabric + TurboModules)
JS 执行环境 Bridge + CatalystInstance JSI + Hermes Runtime
Bundle 入口 ReactInstanceManager ReactHost / JSExecutorFactory
Native 管理器 ReactActivity / ReactRootView ReactHost / ReactInstance
JS 模块 API 全局注入模块 (Global Bridge) TurboModule + Codegen
支持情况 已过时 (Deprecated) 官方推荐

!WARNING

从 RN 0.72 起 Fabric 默认启用,RN 0.80 之后已完全移除传统 Bridge 的 Fallback 机制。JSBundleLoader 等旧类在高性能新架构下已无法直接使用。


二、 方案选择:多 Runtime vs 单 Runtime

在 0.83.1 版本下,实现多模块化主要有两种思路:

  1. 多 ReactHost 实例化(隔离方案): 每个业务模块独立打包,包含独立的基础库。优点是隔离性强,缺点是内存占用极高,无法共享基础库。
  2. 单 Hermes Runtime 动态加载(推荐方案):
    • 基础包 (Base Bundle): 包含 RN 框架、NativeModules、公共库及导航容器。
    • 业务包 (Business Bundle): 仅包含业务代码,共用基础包的运行时。
    • 优势: 内存占用低、共用上下文、符合 Fabric 渲染链路。

本文采用方案 2 进行深度实践。


三、 核心原理

  1. 按需加载: 启动阶段只加载 index.base.bundle
  2. 动态注册: 业务 Bundle 被加载时,通过 JSI 调用底层 C++ Runtime 的 evaluateJavaScript 执行 JS 代码,将业务页面注册到基础包的导航器(如 React Navigation)中。
  3. 路由占位: 基础包预留"壳页面"(BizShell),当导航跳转至业务模块时,若 Bundle 未加载则触发 Native 动态加载流程。

四、 具体实现步骤

1. React Native 层实现

1.1 入口文件拆分
  • index.base.js (基础包):

    javascript 复制代码
    import { AppRegistry } from 'react-native';
    import App from './src/App';
    import { name as appName } from './app.json';
    
    AppRegistry.registerComponent(appName, () => App);
  • index.buz1.js (业务包):

    javascript 复制代码
    import { registerBiz } from './src/navigation/DynamicRegistry';
    import Buz1Navigator from './src/biz1/Navigator';
    
    // 动态注册业务路由
    registerBiz('buz1', Buz1Navigator);
1.2 路由占位逻辑

src/navigation/DynamicNavigator.tsx 中,使用 BizShell 作为业务占位符:

tsx 复制代码
<Stack.Navigator initialRouteName={props.biz || 'NotFound'}>
  <Stack.Screen name="NotFound" component={NotFound} />
  
  {/* 业务占位:有多少个拆分包,就配置多少个 Screen */}
  <Stack.Screen 
    key={'buz1'} 
    name={'buz1'} 
    component={BizShell} 
    options={{ headerShown: false }} 
  />
  <Stack.Screen 
    key={'buz2'} 
    name={'buz2'} 
    component={BizShell} 
    options={{ headerShown: false }} 
  />
</Stack.Navigator>

提示: 核心路由跳转与 Bundle 加载状态维护均在 BizShell.tsx 中处理。


2. Android 端核心代码

2.1 初始化 ReactHost

MainApplication 中手动启动 ReactHost 并监听初始化状态。

kotlin 复制代码
private fun initializeReactHost() {
    val host = reactHost
    host.start() // 启动新架构 Host

    host.addReactInstanceEventListener(object : ReactInstanceEventListener {
        override fun onReactContextInitialized(reactContext: ReactContext) {
            // 将 Context 传给动态加载器
            DynamicLoader.setContext(reactContext)
            try {
                // 执行 JSI 绑定或其他初始化
                DynamicLoader.install()
                SplashActivity.instance?.hideLoading()
            } catch (e: Exception) {
                Log.e("MainApplication", "DynamicLoader 失败:${e.message}")
            }
            host.removeReactInstanceEventListener(this)
        }
    })
}
2.2 动态加载 Bundle (NativeDynamicLoader.kt)

通过 JNI 获取 C++ Runtime 句柄并执行 JavaScript。

kotlin 复制代码
fun loadBundle(bundlePath: String) {
    val jsiPtr = context.javaScriptContextHolder.get()
    // 通过 JNI 调用 C++ 层的 evaluateJavaScript
    // 逻辑:判断 bundlePath 是否已加载 -> 未加载则读取文件并执行
    nativeEvaluateJavaScript(jsiPtr, bundlePath)
}

3. iOS 端核心代码

3.1 抽象 RNRuntimeManager

在 Swift 中管理 reactNativeFactoryreactNativeDelegate,通过 rootViewFactory 创建视图。

3.2 动态加载 (RTNDynamicLoader)

在新架构下,不再使用过时的 bridge.executeSourceCode

swift 复制代码
// JSBundleLoader.swift 核心逻辑
if let runtimeExecutor = rootViewFactory.reactHost.surfacePresenter?.runtimeExecutor {
    // 拿到 RuntimeExecutor 后,在 JS 线程执行业务代码
    runtimeExecutor.execute { runtime in
        // 使用 C++ JSI 或内部 API 执行业务 Bundle 代码
        loadBusinessBundle(path: bundlePath, in: runtime)
    }
}

五、 总结与优势

基于 RN 0.83.1 的这套拆包方案,完全摆脱了对 Legacy Bridge 的依赖:

  1. 极速加载: 利用 Hermes 字节码预编译,业务包加载近乎无感。
  2. 灵活分发: 业务 Bundle 可独立更新,无需重新安装 App。
  3. 架构对齐: 深度集成 ReactHostRuntimeExecutor,完美兼容 Fabric 渲染引擎,是目前新架构下的最优实践。

发布建议:

  • 标签: React Native, Android, iOS, 拆包, 新架构, Hermes.
  • 摘要: 针对 React Native 0.83.1 最新版本,详细讲解如何在 Fabric 架构下实现单 Runtime 的业务拆包与动态加载。

项目git地址:gitee.com/liu_520/mul...

相关推荐
沙漠8 小时前
ReactNative总结系列二 --- 小工具&小技巧md
react native
humcomm16 小时前
FinClip vs React Native:两大跨平台方案的深度对比
javascript·react native·react.js
水云桐程序员16 小时前
Flutter与React Native的对比分析
flutter·react native·react.js
墨狂之逸才3 天前
React Native 状态管理大比拼:Event Bus 还是 Context?小白一看就懂!
react native
爱滑雪的码农3 天前
React Native 完整开发全流程(从零到上线)
javascript·react native·react.js
沐言人生3 天前
ReactNative 源码分析12——Native View创建流程onBatchComplete
android·react native
沐言人生5 天前
ReactNative 源码分析11——Native View创建流程setChildren和manageChildren
android·react native
沐言人生6 天前
ReactNative 源码分析10——Native View创建流程createView
android·react native
坏小虎6 天前
【聊天列表组件选型建议】FlashList、FlatList、LegendList三种列表组件
javascript·react native·react.js
sealaugh327 天前
react native(学习笔记第五课) 英语打卡微应用(4)- frontend的列表展示
笔记·学习·react native