如果你是在做 React Native App 的工程化优化,这几个其实应该放在一起考虑:
包体积瘦身 → 打包优化 → 离线包 → 热更新 → 灰度/回滚 → CI/CD
我建议按下面这套思路设计。
1. RN 包体积瘦身
先把体积拆成 4 部分看:
| 部分 | 优化重点 |
|---|---|
| JS Bundle | Metro、Hermes、依赖裁剪 |
| Android Native | ABI、R8、资源压缩 |
| iOS Native | Framework、资源、符号文件 |
| 图片/字体/资源 | WebP/AVIF、压缩、按需加载 |
Android 优先做:
- 开启 Hermes
release开启 R8 / ProGuard- 开启资源压缩
- 使用 ABI Split
- 删除无用 native module
- 检查
lib/*.so大小 - 图片不要直接把原图塞进 APK/AAB
- 移除无用字体
- 尽量使用 AAB,而不是 APK
尤其是 ABI:
bash
splits {
abi {
enable true
reset()
include "armeabi-v7a", "arm64-v8a"
universalApk false
}
}
如果你的用户主要是现代 Android 手机,可以进一步评估是否只保留 arm64-v8a。
2. JS Bundle 优化
这个通常是 RN 项目最容易被忽略的地方。
首先检查:
css
npx react-native bundle \
--platform android \
--dev false \
--entry-file index.js \
--bundle-output android/index.android.bundle
然后分析 Bundle。
重点检查:
lodashmoment- 大型 UI 库
- 图表库
- 富文本编辑器
- Markdown
- 编辑器
- 大型 JSON
- 重型 SDK
例如:
javascript
import _ from 'lodash'
尽量改成:
javascript
import debounce from 'lodash/debounce'
日期库也要特别注意。
如果项目里还有:
javascript
import moment from 'moment'
通常值得评估替换方案。
3. Hermes
如果你的 RN 版本支持,Hermes 基本应该作为默认方案。
它的意义不只是包体积:
JS Bundle
↓
Hermes bytecode
↓
启动
相比传统 JS 引擎,可以改善:
- 首屏启动
- JS 执行
- 内存
- Bundle 加载
但是要注意:
不要简单认为「开启 Hermes = 包一定变小」。
最终 APK/AAB 要通过 analyze APK / Android Studio APK Analyzer 实际比较。
4. 离线包和热更新要分开理解
这是 RN 项目里非常关键的一点。
传统 RN:
css
App
├── Native Code
├── RN Runtime
└── JS Bundle
正常情况下:
markdown
安装 App
↓
内置 JS Bundle
↓
启动
如果做离线包:
markdown
安装 App
↓
内置基础 JS Bundle
↓
下载新 Bundle
↓
本地保存
↓
下一次启动使用新 Bundle
所以所谓「热更新」,本质上通常是:
更新 JS / Assets,而不是更新 Native Code。
5. 推荐的离线包架构
我更推荐:
arduino
CDN
│
▼
┌──────────────┐
│ OTA Server │
└──────┬───────┘
│
version / hash
│
▼
┌─────────────────────────────────┐
│ RN App │
│ │
│ Native │
│ │ │
│ ├── Bundle Manager │
│ │ │ │
│ │ ├── current │
│ │ ├── backup │
│ │ └── downloaded │
│ │ │
│ └── RN Runtime │
└─────────────────────────────────┘
本地目录类似:
sql
bundles/
├── 1.0.0/
│ ├── index.android.bundle
│ └── assets/
│
├── 1.0.1/
│ ├── index.android.bundle
│ └── assets/
│
└── current
不要直接覆盖当前 Bundle。
应该:
bash
下载
↓
校验 hash
↓
校验签名
↓
解压
↓
完整性检查
↓
标记 pending
↓
下次启动
↓
启动成功
↓
commit
6. 一定要做「失败回滚」
这是热更新系统最重要的能力之一。
例如:
markdown
当前版本
1.0.0
下载 OTA
1.0.1
第一次启动
↓
Crash
↓
发现启动失败
↓
自动回滚
↓
1.0.0
推荐维护:
currentVersion
previousVersion
pendingVersion
启动流程:
sql
App Start
│
▼
pendingVersion?
/ \
yes no
│ │
▼ ▼
启动新包 current
│
┌────┴────┐
│ │
success crash
│ │
▼ ▼
commit rollback
7. 热更新千万不要只做「下载 JS」
生产环境至少需要:
Manifest
json
{
"version": "1.0.1",
"minNativeVersion": "2.3.0",
"bundleUrl": "...",
"sha256": "...",
"size": 12345678,
"mandatory": false
}
然后 App 判断:
markdown
Native Version
↓
是否满足 minNativeVersion
↓
YES
↓
下载 Bundle
↓
SHA256 校验
↓
安装
这能避免一个非常严重的问题:
ini
Native = 1.0.0
OTA Bundle = 2.0.0
如果 JS 调用了 Native 新 API:
scss
NativeModules.xxx.newMethod()
而旧 Native 根本没有这个方法:
JS Crash
所以:
OTA Bundle 必须和 Native 能力建立兼容矩阵。
8. Native / JS 版本兼容
推荐设计成:
markdown
Native Capability Version
│
▼
Bundle Manifest
│
┌─────┴─────┐
│ │
compatible incompatible
│ │
▼ ▼
install reject
例如:
json
{
"bundleVersion": "2026.08.24.001",
"nativeMinVersion": "3.2.0",
"nativeMaxVersion": "3.x"
}
或者更进一步:
json
{
"requiredCapabilities": [
"camera.v2",
"payment.v3",
"storage.v2"
]
}
这样比简单比较 App 版本更可靠。
9. 「热更新」推荐不要真正热切换
我建议:
不要:
App 运行中
↓
下载 JS
↓
直接替换当前 JS
而是:
markdown
运行旧 Bundle
↓
后台下载新 Bundle
↓
校验
↓
安装
↓
标记 pending
↓
下一次启动使用
也就是:
后台更新 + 下次启动生效
稳定性会高很多。
如果业务确实需要立即生效,也建议只对非常小的 JS 模块做动态加载,而不是替换整个 RN Runtime。
10. 线上灰度
OTA 一定要有灰度能力。
例如:
erlang
Bundle 1.0.1
│
├── 1% 用户
│
├── 10%
│
├── 30%
│
└── 100%
服务端根据:
userId
deviceId
country
platform
appVersion
nativeVersion
决定是否返回 OTA。
例如:
json
{
"enabled": true,
"rollout": 10,
"bundle": "1.0.1"
}
如果 Crash/ANR 上升:
发现异常
↓
关闭 OTA
↓
停止发放
↓
回滚
11. 包体积和 OTA 最好结合起来
这是我比较推荐的最终架构:
markdown
┌─────────────┐
│ CDN │
└──────┬──────┘
│
OTA Manifest
│
▼
┌───────────────────────────────────┐
│ App │
│ │
│ Native ────────┐ │
│ │ │
│ Hermes Runtime │ │
│ │ │
│ Bundle Manager │ │
│ │ │ │
│ ▼ │ │
│ Local Bundles │ │
│ │ │
└─────────────────┼────────────────┘
│
▼
RN JS Bundle
App 首次安装:
Native + Hermes + 基础 Bundle
后续:
OTA
↓
增量/完整 Bundle
↓
本地缓存
↓
下一次启动使用
这样可以把:
「首次安装包体积」
和
「业务代码更新速度」
解耦。
12. 如果你是新项目,我建议这一套
架构
css
React Native
├── Hermes
├── Metro
├── Code Splitting / Lazy Loading
├── Bundle Analyzer
├── Android R8
├── Resource Shrinking
├── ABI Split
└── OTA Bundle Manager
OTA
markdown
Git
│
▼
CI/CD
│
▼
Metro Bundle
│
▼
Hermes Bundle
│
▼
SHA256 + Sign
│
▼
CDN
│
▼
OTA Manifest
│
▼
RN Application
安全机制
sql
Manifest
↓
Signature Verify
↓
SHA256 Verify
↓
Version Verify
↓
Native Compatibility
↓
Install
↓
Launch
↓
Health Check
↓
Commit / Rollback
最后一个很重要的问题
如果你的项目是准备真正上生产的 RN OTA,我不建议直接自己写一套「下载 JS → 替换 Bundle」就上线。
需要特别考虑 App Store / Google Play 对代码更新政策、JS Bundle 签名、防篡改、回滚、灰度、Native/JS 兼容性。另外,不同 RN 版本对 Hermes、Codegen、New Architecture、Metro Bundle 的处理也不同。
如果你告诉我你现在用的是 React Native 版本(比如 0.73 / 0.76 / 0.81)、Android/iOS 是否都要、是否 New Architecture、目前包体积多少 MB ,我可以直接给你设计一套可落地的 RN「包体积瘦身 + 离线包 + OTA 热更新」技术方案,包括目录结构、Metro 配置、Android/iOS 原生代码、OTA Server API、Manifest、签名、灰度和自动回滚流程。