RN 0.72.5 版本迁移升级实战避坑全记录

7 阅读3分钟

目录

  1. 背景
  2. 版本变更一览
  3. 详细修改清单
  4. 问题与解决方案
  5. 技术决策:PackageList 方案选择
  6. CI/Jenkins 适配指南
  7. 附录

一、背景

1.1 升级动机

React Native 0.70.0 发布于 2022 年 9 月,已进入维护末期。0.72.5 作为 0.72 系列的稳定版本,带来:

  • Hermes 引擎 成为默认 JS 引擎,启动速度与内存占用显著优化
  • 新架构(Fabric / TurboModules) 基础能力完善,为后续迁移铺垫
  • Gradle 7.x + AGP 7.x 原生支持,移除旧版构建兼容代码
  • 关键 Bug 修复 与社区生态适配

1.2 升级原则

原则说明
最小化变更仅升级 RN 核心及其紧耦合依赖,不动业务代码
保持构建工具版本Gradle 7.5.1 / AGP 7.4.2 / Kotlin 1.8.20 不变
前后兼容Android 原生侧 API 平滑过渡,JS 侧业务逻辑不改动
稳定优先优先确保编译通过 + 运行时无闪退,再考虑性能优化

二、版本变更一览

2.1 直接变更

组件升级前升级后变更原因
react-native0.70.00.72.5主版本升级
react18.1.018.2.0RN 0.72.5 最低要求 React 18.2
compileSdk3133RN 0.72 要求
targetSdk3133跟随 compileSdk
buildTools31.0.033.0.0跟随 compileSdk
async-storage1.16.31.21.0修复 RN 0.72 peer dependency 不兼容

2.2 保持不变

组件版本原因
Gradle7.5.1AGP 7.4.2 支持,无需升级
AGP7.4.2RN 0.72 要求 ≥ 7.3.1,当前已满足
Kotlin1.8.20稳定版本,无兼容性问题
Java11项目标准,保持不变
minSdk23不变

2.3 关键架构变化

RN 0.70.0                          RN 0.72.5
─────────────────────────          ─────────────────────────
JS 引擎:JSC (JavaScriptCore)      JS 引擎:Hermes(默认)
Android 产物:react-native AAR     Android 产物:react-android + hermes-android
Autolink:native_modules.gradle    Autolink:com.facebook.react 插件 + native_modules.gradle
Maven 来源:node_modules 本地       Maven 来源:Maven Central 远程
MainReactPackage:存在             MainReactPackage:保留(AAR 中仍存在)

三、详细修改清单

3.1 构建配置(5 个文件)

package.json

{
  "dependencies": {
-   "react": "18.1.0",
+   "react": "18.2.0",
-   "react-native": "0.70.0",
+   "react-native": "0.72.5",
-   "@react-native-async-storage/async-storage": "1.16.3",
+   "@react-native-async-storage/async-storage": "1.21.0"
  },
  "overrides": {
-   "react-native": "0.70.0"
+   "react-native": "0.72.5"
  }
}

执行 yarn install 安装依赖。

gradle/libs.versions.toml

[versions]
- compileSdk = "31"
+ compileSdk = "33"
- targetSdk = "31"
+ targetSdk = "33"
- buildTools = "31.0.0"
+ buildTools = "33.0.0"
- react-native = "0.70.0"
+ react-native = "0.72.5"

[libraries]
# 核心变更:artifact 从 react-native 拆分为 react-android + hermes-android
- react-native = { module = "com.facebook.react:react-native", version.ref = "react-native" }
+ react-android = { module = "com.facebook.react:react-android", version.ref = "react-native" }
+ hermes-android = { module = "com.facebook.react:hermes-android", version.ref = "react-native" }

app/build.gradle.kts

依赖引用替换:

  /** ReactNative相关依赖内容 **/
- implementation(libs.react.native)
- implementation(libs.android.jsc)      // JSC 已由 Hermes 替代
+ implementation(libs.react.android)
+ implementation(libs.hermes.android)

NDK 版本和 packaging 配置(Hermes 适配):

android {
+   ndkVersion = "23.1.7779620"          // Hermes 预编译库要求的 NDK 版本

    packagingOptions {
+       jniLibs {
+           useLegacyPackaging = true     // 兼容 AGP 7.x 原生库打包
+       }
        pickFirsts.addAll(listOf(
-           "lib/arm64-v8a/libc++_shared.so",
-           "lib/armeabi-v7a/libc++_shared.so",
-           "lib/x86/libc++_shared.so",
-           "lib/x86_64/libc++_shared.so"
+           "**/libc++_shared.so",       // 通配符覆盖所有架构
+           "**/libjsc.so",              // Hermes 相关 so 冲突处理
+           "**/libfbjni.so",
+           "**/libreactnativejni.so",
+           "**/libfolly_runtime.so",
+           "**/libglog.so",
+           "**/libhermes.so"
        ))
    }
}

settings.gradle.kts

  dependencyResolutionManagement {
-     repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+     repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)  // 允许 RN 插件添加仓库
      repositories {
-         // RN 0.70 本地 maven 仓库(0.72 AAR 已不在本地,从 Maven Central 远程获取)
-         maven { url = uri("${rootProject.projectDir}/node_modules/react-native/android") }
      }
  }

setup_rn_release.sh

- RN_VERSION_GRADLE=$(grep -oP "com.facebook.react:react-native:\K[0-9.]+" ...)
+ RN_VERSION_GRADLE=$(grep -oP "com.facebook.react:react-android:\K[0-9.]+" ...)

3.2 Java / Kotlin 源码(6 个文件)

ModelApplication.java — RN 初始化适配

- import com.facebook.react.shell.MainReactPackage;    // RN 0.71+ 类已废弃
- import com.reactnativecommunity.asyncstorage.AsyncStoragePackage;
- import com.swmansion.gesturehandler.react.RNGestureHandlerPackage;
- import com.th3rdwave.safeareacontext.SafeAreaContextPackage;
- import com.BV.LinearGradient.LinearGradientPackage;
- import com.swmansion.rnscreens.RNScreensPackage;
+ import com.facebook.react.PackageList;               // 统一管理社区包注册

  @Override
  protected List<ReactPackage> getPackages() {
-     List<ReactPackage> packages = new ArrayList<>();
-     packages.add(new MainReactPackage());
-     packages.add(new CustomActionPackage());
-     packages.add(new RNGestureHandlerPackage());
-     packages.add(new AsyncStoragePackage());
-     packages.add(new SafeAreaContextPackage());
-     packages.add(new LinearGradientPackage());
-     packages.add(new RNScreensPackage());
-     return packages;
+     return new PackageList(this).getPackages();      // + CustomActionPackage 在 PackageList 内部
  }

ExamPKMateActivity.kt / SmallVideoPlayerActivity.kt — SDK 33 API 变更

- override fun onAnimationEnd(animation: Animator?)   // SDK 33 签名从可空改为非空
+ override fun onAnimationEnd(animation: Animator)
- override fun onAnimationStart(animation: Animator?)
+ override fun onAnimationStart(animation: Animator)

InforDetailActivity.java / ChatWebActivity.java — 废弃 API 移除

- webSettings.setAppCacheEnabled(false);              // SDK 33 已删除 AppCache API

MainHomeFragmentRN.kt / MomentsFragment.java / MyNewFragmentRN.kt — ReactFragment 构建器适配

  ReactFragment.Builder()
      .setComponentName("...")
      .setLaunchOptions(getLaunchOptions("..."))
+     .setFabricEnabled(false)                        // RN 0.72 默认 null → Bundle.putBoolean() 时 NPE
      .build()

3.3 新增文件(2 个)

app/src/main/java/com/facebook/react/PackageList.java

手工创建的静态 PackageList,等价于 RN CLI autolink 自动生成的内容。
包含 MainReactPackage + 6 个社区包。当新增/删除 RN 社区包时需同步更新。

app/src/main/jniLibs/arm64-v8a/libc++_shared.so

react-android:0.72.5 AAR 中提取的 C++ STL 运行时(NDK 23 编译)。
解决 Hermes 启动时 __emutls_get_address 符号缺失导致的闪退。


四、问题与解决方案

本次升级共遇到 8 个问题,按出现顺序记录如下:

#问题阶段根因解决方案
1react-native-gradle-plugin 找不到配置classpath 缺版本号 → Maven 解析失败暂时性尝试(见 #4),最终移除插件依赖
2FAIL_ON_PROJECT_REPOS 仓库冲突配置RN 0.72 插件动态添加 maven 仓库FAIL_ON_PROJECT_REPOSPREFER_SETTINGS
3react {} DSL 编译错误配置Kotlin DSL 中 Property.set()= 赋值改为 root.set(file(...))
4PackageList 类找不到编译RN Gradle 插件 autolink 与 Kotlin DSL 不兼容核心决策:手工维护静态 PackageList.java
5setAppCacheEnabled() 编译错误编译SDK 33 删除 WebSettings AppCache API移除相关调用(已废弃,无实际作用)
6Animator?Animator 签名不匹配编译SDK 33 AnimatorListener 接口 @NonNull 注解变更参数类型改为非空
7ReactFragment.Builder NPE 闪退运行时mFabricEnabled 默认 nullBundle.putBoolean() 拆箱异常3 处调用点添加 .setFabricEnabled(false)
8__emutls_get_address 符号缺失运行时旧版 libc++_shared.so 不含 NDK 23 EmuTLS 符号react-android AAR 提取正确版本到 jniLibs

关键问题详解

问题 4:PackageList 无法自动生成

这是整个升级过程中最核心的技术决策点。三个同类项目的对比:

JianSheMobileAwesome72(官方 Demo)accmobile
RN 版本0.70.00.72.50.72.5
Gradle DSLGroovy .gradleGroovy .gradleKotlin .gradle.kts
Autolink 方式native_modules.gradle插件 + native_modules.gradle静态文件
ext 函数调用原生支持原生支持跨语言桥接不可行

native_modules.gradle(540 行 Groovy)通过 ext 闭包暴露 applyNativeModulesSettingsGradleapplyNativeModulesAppBuildGradle 两个扩展函数。Kotlin DSL 无法直接消费 Groovy 闭包,交叉编译边界导致自动生成链路断裂。

决策:手工维护 PackageList.java

  • 优势:编译稳定,无 Gradle 插件依赖,版本明确
  • 代价:增删社区包时需手动更新(低频操作)
  • 参考:官方 Demo 同样使用 MainReactPackage(AAR 中确认存在)

问题 8:libc++_shared.so 符号缺失

错误调用链:
System.loadLibrary("hermes")
  → dlopen("libhermes.so")
    → libhermes.so 依赖 libfolly_runtime.so
      → libfolly_runtime.so 依赖 __emutls_get_address
        → 在旧版 libc++_shared.so 中找不到 → UnsatisfiedLinkError

react-android:0.72.5 AAR 自带 NDK 23 编译的 libc++_shared.so(含 __emutls_get_address),但项目中 ijkplayer、marsxlog 等旧版原生库也提供同名文件。pickFirsts 策略不确定选择哪个版本。

决策:从 AAR 提取正确版本到 jniLibs/

本地 jniLibs 目录的优先级高于 AAR 内嵌文件,确保始终加载正确版本。


五、技术决策:PackageList 方案选择

5.1 方案对比

方案 A:RN Gradle 插件方案 B:native_modules.gradle方案 C:静态 PackageList(采用)
Gradle 插件依赖需要不需要不需要
自动发现新包支持支持需手动维护
Kotlin DSL 兼容部分兼容不兼容完全兼容
编译稳定性中等
适用场景标准 RN 项目Groovy DSL 项目任意结构

5.2 采选理由

  1. 项目特性:accmobile 是 Android 原生项目集成 RN(非 react-native init 生成),无标准 android/ 子目录结构。com.facebook.react Gradle 插件的路径推导依赖标准结构。
  2. 构建语言:Kotlin DSL 与 native_modules.gradle(Groovy)的 ext 机制存在跨语言屏障。
  3. 维护成本:社区包增删频率低(年均 < 5 次),手动更新成本远低于自动化基础设施建设的投入。
  4. 长期规划:后续继续评估 RN 新架构(Fabric/TurboModules),届时可重新引入 Gradle 插件。

六、CI/Jenkins 适配指南

6.1 必需环境变更

检查项变更前变更后验证命令
Android SDK Platform3133sdkmanager --list | grep "platforms;android-33"
Android Build Tools31.0.033.0.0sdkmanager --list | grep "build-tools;33.0.0"
NDK未要求23.1.7779620(可自动下载)AGP 自动处理
Node.js≥ 14≥ 14(不变)node -v

NDK 自动下载:若 CI 未预装 NDK 23.1,AGP 7.4.2 将自动下载(约 1GB),需确保 CI 有外网访问能力且磁盘 ≥ 5GB 剩余空间。

6.2 已知兼容性项

状态影响
setup_rn_release.sh 版本检测输出 unknown仅警告,不阻塞
npm install --legacy-peer-deps正常RN 0.72 部分 peer dep 不严格
PackageList.java静态文件已纳入 Git,CI 直接可用
libc++_shared.so静态文件已纳入 Git,CI 直接可用
Gradle 7.5.1 / AGP 7.4.2不变无需调整 CI 环境

6.3 CI 构建建议

# 1. 确保 SDK 33 已安装
yes | $ANDROID_HOME/tools/bin/sdkmanager "platforms;android-33" "build-tools;33.0.0"

# 2. 安装 Node 依赖
npm install --legacy-peer-deps

# 3. 打包 JS bundle
npm run bundle-android

# 4. 执行 Gradle 构建
./gradlew assembleRelease

七、附录

A. 修改文件汇总

修改 (11 files):
├── package.json                          # RN / React / async-storage 版本升级
├── gradle/libs.versions.toml             # SDK / RN 版本 + 依赖 artifact
├── build.gradle.kts                      # (无变更)
├── settings.gradle.kts                   # 仓库模式 + 移除本地 maven
├── app/build.gradle.kts                  # 依赖引用 / NDK / packaging
├── app/src/main/java/.../
│   ├── ModelApplication.java             # PackageList 替代手动注册
│   ├── ExamPKMateActivity.kt             # Animator 签名适配
│   ├── SmallVideoPlayerActivity.kt       # Animator 签名适配
│   ├── InforDetailActivity.java          # 移除 setAppCacheEnabled
│   ├── ChatWebActivity.java              # 移除 setAppCacheEnabled
│   ├── MainHomeFragmentRN.kt             # ReactFragment 构建器适配
│   ├── MomentsFragment.java              # ReactFragment 构建器适配
│   └── MyNewFragmentRN.kt               # ReactFragment 构建器适配
└── setup_rn_release.sh                   # 版本检测正则更新

新增 (2 files):
├── app/src/main/java/com/facebook/react/PackageList.java
└── app/src/main/jniLibs/arm64-v8a/libc++_shared.so

B. 关键数据

指标数值
修改文件数13
新增文件数2
解决编译/运行时问题数8
总耗时~4 小时
业务代码改动0(纯适配性修改)

C. 参考资料