基于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地址:https://gitee.com/liu_520/multi-bundle-programs

相关推荐
梦6503 小时前
Vue 组件 vs React 组件深度对比
javascript·vue.js·react.js
全栈前端老曹5 小时前
【ReactNative】页面跳转与参数传递 - navigate、push 方法详解
前端·javascript·react native·react.js·页面跳转·移动端开发·页面导航
_Kayo_6 小时前
React上绑定全局方法
前端·javascript·react.js
踏浪无痕8 小时前
JobFlow:固定分片如何解决分布式扫描的边界抖动
后端·面试·架构
职业码农NO.18 小时前
系统架构设计中的 15 个关键取舍
设计模式·架构·系统架构·ddd·架构师·设计规范·领域驱动
踏浪无痕8 小时前
JobFlow调度的难题:超时、补偿与漏调
后端·面试·架构
今晚月亮有点圆10 小时前
RAG 系统实战指南:检索、生成与工程落地
架构
武子康10 小时前
Java-213 RocketMQ(MetaQ)演进与核心架构:NameServer/Broker/Producer/Consumer 工作机制
大数据·分布式·架构·消息队列·系统架构·rocketmq·java-rocketmq