最近接到一个需求:把现有的 React Native 模块嵌入到公司的原生 Android 项目中。听起来是个常规操作,但实际踩了不少坑------从 Gradle 版本冲突、So 库加载失败,到 RN 与原生页面的生命周期管理、热更新方案选型,每一步都有"惊喜"。这篇文章记录完整的过程和解决方案,希望能帮到有同样需求的同学。
一、项目背景与目标
1.1 现有项目情况
我们公司的主 App 是一个纯原生 Android 项目,已经迭代了 5 年+:
- Gradle: 8.0 + AGP 8.1
- minSdk : 24,targetSdk: 34
- 架构: MVP + 组件化,包含 20+ 业务模块
- 包体积: 约 80MB(已做资源混淆和代码精简)
1.2 需求目标
产品团队希望快速上线一个新业务模块,评估后决定用 RN 开发:
- 目标 1: 在现有原生项目中嵌入 RN,不改造主工程架构
- 目标 2: RN 页面与原生页面无缝跳转,用户体验一致
- 目标 3: 支持 CodePush 热更新,减少发版频率
- 目标 4: 控制包体积增量,尽量 < 5MB
1.3 技术选型
| 方案 | 优点 | 缺点 | 结论 |
|---|---|---|---|
| RN 源码集成 | 完全可控,可定制 | 配置复杂,维护成本高 | ✅ 选择 |
| RN 预编译 AAR | 接入简单 | 版本锁定,难以定制 | ❌ 放弃 |
| Flutter 模块 | 性能好 | 学习成本高,生态迁移大 | ❌ 放弃 |
二、环境搭建与集成
2.1 创建 RN 模块
bash
# 创建 RN 项目
npx react-native@latest init RNBusinessModule --version 0.73.0
cd RNBusinessModule
# 验证 RN 项目能独立运行
npx react-native run-android
2.2 改造为 Android Library
RN 默认创建的是 Application 项目,需要改造为 Library:
修改 android/app/build.gradle:
gradle
// 原来是 application
// apply plugin: 'com.android.application'
// 改为 library
apply plugin: 'com.android.library'
android {
namespace 'com.rnbusinessmodule'
defaultConfig {
// 移除 applicationId
// applicationId "com.rnbusinessmodule"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
}
// 关键:移除 applicationVariants 相关配置
// 因为 library 没有 applicationVariants
}
修改 android/settings.gradle:
gradle
rootProject.name = 'RNBusinessModule'
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle")
applyNativeModulesSettingsGradle(settings)
include ':app'
2.3 主工程引入 RN Module
主工程 settings.gradle:
gradle
include ':app'
// 引入 RN 模块
include ':rn-business-module'
project(':rn-business-module').projectDir = new File(rootDir, '../RNBusinessModule/android/app')
// 引入 RN 依赖的 native 模块
apply from: file("../RNBusinessModule/node_modules/@react-native-community/cli-platform-android/native_modules.gradle")
applyNativeModulesSettingsGradle(settings)
主工程 app/build.gradle:
gradle
dependencies {
implementation project(':rn-business-module')
// RN 核心依赖
implementation "com.facebook.react:react-native:0.73.0"
// Hermes 引擎(可选,但推荐)
implementation "com.facebook.react:hermes-android:0.73.0"
}
三、踩坑记录与解决方案
坑 1:Gradle 版本冲突 ⚠️
现象:
> Could not resolve all dependencies for configuration ':app:debugRuntimeClasspath'.
> Could not find com.facebook.react:react-native:0.73.0.
原因 :
RN 0.73 默认使用 Gradle 8.3,而我们主工程是 Gradle 8.0,AGP 版本也不一致。RN 的 react-native-gradle-plugin 对 Gradle 版本有严格要求。
解决方案:
步骤 1:统一 Gradle 版本
主工程 gradle/wrapper/gradle-wrapper.properties:
properties
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
步骤 2:统一 AGP 版本
主工程根目录 build.gradle:
gradle
buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:8.1.0'
}
}
步骤 3:配置 RN 的 Maven 仓库
主工程根目录 build.gradle:
gradle
allprojects {
repositories {
google()
mavenCentral()
// 关键:添加 RN 的 Maven 仓库
maven { url "${rootDir}/../RNBusinessModule/node_modules/react-native/android" }
maven { url "${rootDir}/../RNBusinessModule/node_modules/jsc-android/dist" }
}
}
步骤 4:在 RN 模块中锁定 Gradle 版本
RNBusinessModule/android/gradle/wrapper/gradle-wrapper.properties:
properties
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
坑 2:So 库加载失败 ⚠️⚠️
现象 :
打开 RN 页面时崩溃:
java.lang.UnsatisfiedLinkError: couldn't find DSO to load: libhermes.so
原因 :
RN 0.73 默认使用 Hermes 引擎,但 So 库没有正确打包到 APK 中。或者主工程的 abiFilters 与 RN 的 So 库不匹配。
解决方案:
步骤 1:确认 Hermes 配置
RNBusinessModule/android/app/build.gradle:
gradle
project.ext.react = [
enableHermes: true // 启用 Hermes
]
apply from: "../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"
applyNativeModulesAppBuildGradle(project)
步骤 2:主工程配置 abiFilters
主工程 app/build.gradle:
gradle
android {
defaultConfig {
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
}
}
packagingOptions {
pickFirst '**/libc++_shared.so'
pickFirst '**/libjsc.so'
pickFirst '**/libhermes.so'
}
}
步骤 3:检查 So 库是否打包
bash
# 解压 APK 检查
unzip app-debug.apk -d apk_out
ls apk_out/lib/arm64-v8a/ | grep hermes
# 应该能看到 libhermes.so
步骤 4:如果还是加载失败,手动指定 So 库路径
kotlin
class MainApplication : Application() {
override fun onCreate() {
super.onCreate()
// 手动加载 So 库(兜底方案)
try {
System.loadLibrary("hermes")
} catch (e: UnsatisfiedLinkError) {
// 尝试从 APK 内加载
ReLinker.loadLibrary(this, "hermes")
}
SoLoader.init(this, OpenSourceMergedSoMapping)
}
}
坑 3:Metro 打包资源找不到 ⚠️
现象 :
RN 页面白屏,Logcat 显示:
E/ReactNativeJS: Error: Unable to resolve module `./src/App` from `index.js`
原因 :
RN 模块作为 Library 集成时,Metro bundler 的入口和路径解析与独立运行时不一致。
解决方案:
步骤 1:确认 index.js 入口正确
RNBusinessModule/index.js:
javascript
import {AppRegistry} from 'react-native';
import App from './src/App';
import {name as appName} from './app.json';
AppRegistry.registerComponent(appName, () => App);
步骤 2:配置 Metro 的 asset 路径
RNBusinessModule/metro.config.js:
javascript
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
const config = {
// 关键:配置 watchFolders,让 Metro 能正确监听文件变化
watchFolders: [
__dirname,
// 如果需要引用主工程的资源,可以在这里添加路径
],
resolver: {
// 配置额外的 node_modules 查找路径
nodeModulesPaths: [
__dirname + '/node_modules',
],
},
// 关键:配置 server 的 host 和 port
server: {
host: '0.0.0.0',
port: 8081,
},
};
module.exports = mergeConfig(getDefaultConfig(__dirname), config);
步骤 3:主工程启动 Metro server
bash
cd RNBusinessModule
npx react-native start --port 8081
步骤 4:打包离线 bundle(Release 模式)
bash
cd RNBusinessModule
npx react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res/
坑 4:RN 与原生页面生命周期冲突 ⚠️⚠️⚠️
现象:
- 从原生页面跳转到 RN 页面,返回后原生页面的状态异常
- RN 页面的
useEffect清理函数没有正确执行 - 快速切换页面时,RN 页面出现内存泄漏
原因 :
RN 的 ReactRootView 和 ReactInstanceManager 的生命周期与 Android 的 Activity/Fragment 生命周期不完全对齐。
解决方案:
封装 RN 容器 Activity:
kotlin
class RNContainerActivity : AppCompatActivity(), DefaultHardwareBackBtnHandler {
private lateinit var reactRootView: ReactRootView
private lateinit var reactInstanceManager: ReactInstanceManager
companion object {
private const val EXTRA_MODULE_NAME = "module_name"
private const val EXTRA_INITIAL_PROPS = "initial_props"
fun start(context: Context, moduleName: String, initialProps: Bundle? = null) {
val intent = Intent(context, RNContainerActivity::class.java).apply {
putExtra(EXTRA_MODULE_NAME, moduleName)
putExtra(EXTRA_INITIAL_PROPS, initialProps)
}
context.startActivity(intent)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 关键:使用单例 ReactInstanceManager,避免重复创建
reactInstanceManager = RNInstanceManagerHolder.getInstance(applicationContext)
reactRootView = ReactRootView(this).apply {
startReactApplication(
reactInstanceManager,
intent.getStringExtra(EXTRA_MODULE_NAME) ?: "RNBusinessModule",
intent.getBundleExtra(EXTRA_INITIAL_PROPS)
)
}
setContentView(reactRootView)
}
override fun onPause() {
super.onPause()
reactInstanceManager.onHostPause(this)
}
override fun onResume() {
super.onResume()
reactInstanceManager.onHostResume(this, this)
}
override fun onDestroy() {
super.onDestroy()
// 关键:正确清理 ReactRootView
reactRootView.unmountReactApplication()
reactInstanceManager.onHostDestroy(this)
}
override fun invokeDefaultOnBackPressed() {
super.onBackPressed()
}
override fun onBackPressed() {
if (reactInstanceManager.hasStartedCreatingInitialContext()) {
reactInstanceManager.onBackPressed()
} else {
super.onBackPressed()
}
}
}
单例 ReactInstanceManager:
kotlin
object RNInstanceManagerHolder {
@Volatile
private var instance: ReactInstanceManager? = null
fun getInstance(context: Context): ReactInstanceManager {
return instance ?: synchronized(this) {
instance ?: createReactInstanceManager(context.applicationContext).also {
instance = it
}
}
}
private fun createReactInstanceManager(context: Context): ReactInstanceManager {
return ReactInstanceManager.builder()
.setApplication(context as Application)
.setCurrentActivity(null)
.setBundleAssetName("index.android.bundle")
.setJSMainModulePath("index")
.addPackage(MainReactPackage())
.addPackages(getPackages())
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.BEFORE_CREATE)
.build()
}
private fun getPackages(): List<ReactPackage> {
return listOf(
MainReactPackage(),
// 添加自定义 Native Modules
RNBusinessPackage()
)
}
}
关键注意点:
- ReactInstanceManager 必须单例:重复创建会导致内存泄漏和 JS 引擎崩溃
- onDestroy 中必须 unmount:否则 ReactRootView 持有引用,Activity 无法回收
- onBackPressed 要透传:让 RN 的导航库(如 React Navigation)能处理返回逻辑
坑 5:原生与 RN 通信数据类型不匹配 ⚠️
现象 :
原生向 RN 传递参数时,RN 端收到的数据类型异常,或者中文乱码。
原因 :
RN 的 WritableMap/ReadableMap 与 Kotlin/Java 的数据类型映射有坑,尤其是 Long 类型和中文编码。
解决方案:
原生端发送数据:
kotlin
class RNBusinessPackage : ReactPackage {
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
return listOf(BusinessNativeModule(reactContext))
}
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
return emptyList()
}
}
class BusinessNativeModule(reactContext: ReactApplicationContext) :
ReactContextBaseJavaModule(reactContext) {
override fun getName() = "BusinessNativeModule"
@ReactMethod
fun getUserInfo(promise: Promise) {
try {
val userInfo = Arguments.createMap().apply {
// ✅ 正确:使用 Double 代替 Long(RN 的 Number 是 Double)
putDouble("userId", 123456789012345.toDouble())
// ✅ 正确:使用 putString 传递中文
putString("userName", "张三")
// ✅ 正确:嵌套对象用 WritableMap
val addressMap = Arguments.createMap().apply {
putString("city", "北京")
putString("detail", "朝阳区xxx")
}
putMap("address", addressMap)
// ✅ 正确:数组用 WritableArray
val tagsArray = Arguments.createArray().apply {
pushString("Android")
pushString("React Native")
}
putArray("tags", tagsArray)
}
promise.resolve(userInfo)
} catch (e: Exception) {
promise.reject("ERROR", e.message)
}
}
@ReactMethod
fun navigateToNative(pageName: String, params: ReadableMap?) {
// 处理 RN 调用原生页面跳转
val activity = currentActivity ?: return
when (pageName) {
"UserProfile" -> {
val userId = params?.getDouble("userId")?.toLong() ?: 0L
UserProfileActivity.start(activity, userId)
}
else -> {
// 未知页面处理
}
}
}
}
RN 端接收数据:
javascript
import {NativeModules} from 'react-native';
const {BusinessNativeModule} = NativeModules;
// 获取用户信息
async function fetchUserInfo() {
try {
const userInfo = await BusinessNativeModule.getUserInfo();
// ⚠️ 注意:Long 类型传过来是 Double,需要转回整数
const userId = BigInt(userInfo.userId); // 或 Math.floor(userInfo.userId)
console.log('用户名:', userInfo.userName); // 张三
console.log('城市:', userInfo.address.city); // 北京
console.log('标签:', userInfo.tags); // ["Android", "React Native"]
return userInfo;
} catch (error) {
console.error('获取用户信息失败:', error);
}
}
// 调用原生页面跳转
function goToUserProfile(userId) {
BusinessNativeModule.navigateToNative('UserProfile', {
userId: Number(userId), // 确保传 Number 类型
});
}
坑 6:包体积暴增 ⚠️⚠️
现象 :
集成 RN 后,APK 体积从 80MB 涨到 95MB,增量 15MB,远超预期的 5MB。
原因分析:
| 来源 | 大小 | 说明 |
|---|---|---|
| RN 框架 So 库 | ~8MB | libreactnative.so, libhermes.so 等 |
| JS Bundle | ~3MB | 未压缩的 bundle |
| 资源文件 | ~2MB | RN 引用的图片、字体等 |
| 依赖库 | ~2MB | okhttp, okio, fbjni 等 |
优化方案:
优化 1:启用 Hermes 并压缩 Bundle
bash
# 打包时启用 Hermes 字节码(比 JSC 更小更快)
npx react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res/ --hermes true # 启用 Hermes
优化 2:So 库按 ABI 分包
主工程 app/build.gradle:
gradle
android {
splits {
abi {
enable true
reset()
include 'armeabi-v7a', 'arm64-v8a'
universalApk false // 不打包通用 APK
}
}
}
上传 Google Play 时按 ABI 分 APK,用户只下载对应架构的 So 库。
优化 3:移除未使用的 Native Modules
RNBusinessModule/react-native.config.js:
javascript
module.exports = {
dependencies: {
// 如果不需要以下模块,可以禁用
'@react-native-community/netinfo': {
platforms: {
android: null, // 禁用,使用原生网络库
},
},
},
};
优化 4:图片资源优化
javascript
// 使用 react-native-fast-image 替代默认 Image
import FastImage from 'react-native-fast-image';
<FastImage
source={{
uri: 'https://example.com/image.jpg',
priority: FastImage.priority.normal,
cache: FastImage.cacheControl.immutable,
}}
style={{width: 200, height: 200}}
resizeMode={FastImage.resizeMode.cover}
/>
优化 5:启用 ProGuard/R8
RNBusinessModule/android/app/build.gradle:
gradle
android {
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
// RN 需要的 ProGuard 规则
consumerProguardFiles 'proguard-rules.pro'
}
}
}
proguard
# React Native
-keep class com.facebook.react.** { *; }
-keep class com.facebook.hermes.** { *; }
-dontwarn com.facebook.react.**
# 自定义 Native Modules
-keep class com.yourpackage.** { *; }
优化效果:
| 优化项 | 优化前 | 优化后 | 收益 |
|---|---|---|---|
| So 库(arm64) | 8MB | 4.5MB | Hermes + ABI 分包 |
| JS Bundle | 3MB | 1.2MB | Hermes 字节码 + 压缩 |
| 资源文件 | 2MB | 0.8MB | 图片优化 |
| 总增量 | 15MB | 4.2MB | ✅ 达标 |
坑 7:热更新方案选型 ⚠️⚠️⚠️
需求 :
RN 业务需要支持热更新,减少发版频率。
方案对比:
| 方案 | 优点 | 缺点 | 结论 |
|---|---|---|---|
| CodePush | 微软官方,成熟稳定 | 2024 年已停止维护 | ❌ 放弃 |
| expo-updates | Expo 生态,功能全 | 需要迁移到 Expo | ❌ 放弃 |
| react-native-update | 社区维护,国内可用 | 需要自建服务端 | ✅ 选择 |
| 自研方案 | 完全可控 | 开发维护成本高 | ❌ 放弃 |
最终选择 :react-native-update(原 react-native-pushy)
集成步骤:
- 安装依赖:
bash
cd RNBusinessModule
npm install react-native-update
npx react-native link react-native-update # RN < 0.60
# 或自动 link(RN >= 0.60)
- 配置更新检查:
javascript
// src/utils/UpdateManager.js
import {checkUpdate, downloadUpdate, switchVersion} from 'react-native-update';
const UPDATE_URL = 'https://your-update-server.com/api/check';
export async function checkForUpdate() {
try {
const info = await checkUpdate(UPDATE_URL);
if (info.expired) {
// 强制更新:打开应用商店
Alert.alert(
'发现新版本',
'请前往应用商店下载最新版本',
[
{text: '前往更新', onPress: () => Linking.openURL(info.downloadUrl)},
],
{cancelable: false}
);
} else if (info.upToDate) {
// 已是最新
console.log('当前已是最新版本');
} else {
// 有热更新包
Alert.alert(
'发现更新',
`是否下载更新包?
更新内容:${info.description}`,
[
{text: '稍后', style: 'cancel'},
{
text: '立即更新',
onPress: async () => {
const hash = await downloadUpdate(info);
Alert.alert(
'更新已下载',
'是否立即重启应用更新?',
[
{text: '下次启动', style: 'cancel'},
{text: '立即重启', onPress: () => switchVersion(hash)},
]
);
},
},
]
);
}
} catch (error) {
console.error('检查更新失败:', error);
}
}
- 原生端配置:
kotlin
class UpdateNativeModule(reactContext: ReactApplicationContext) :
ReactContextBaseJavaModule(reactContext) {
override fun getName() = "UpdateNativeModule"
@ReactMethod
fun getCurrentVersion(promise: Promise) {
try {
val packageInfo = reactContext.packageManager
.getPackageInfo(reactContext.packageName, 0)
promise.resolve(packageInfo.versionCode.toDouble())
} catch (e: Exception) {
promise.reject("ERROR", e.message)
}
}
@ReactMethod
fun restartApp() {
val intent = reactContext.packageManager
.getLaunchIntentForPackage(reactContext.packageName)
intent?.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
reactContext.currentActivity?.finish()
reactContext.startActivity(intent)
}
}
四、架构设计:原生与 RN 的边界划分
4.1 模块职责划分
| 层级 | 原生负责 | RN 负责 | 通信方式 |
|---|---|---|---|
| 基础能力 | 网络请求、存储、权限、推送 | 业务逻辑、UI 渲染 | Native Module |
| 导航 | 原生页面栈管理 | RN 内部导航 | DeepLink / Bridge |
| 数据共享 | 用户状态、全局配置 | 业务数据、页面状态 | MMKV / EventBus |
| 埋点 | 页面曝光、点击事件 | 业务事件 | Native Module |
4.2 通信架构图
┌─────────────────────────────────────────────────────────────┐
│ 原生 Android 层 │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │
│ │ Activity │ │ Fragment │ │ Native Modules │ │
│ │ (页面容器) │ │ (RN 容器) │ │ (Bridge 接口) │ │
│ └──────┬───────┘ └──────┬───────┘ └──────────┬─────────┘ │
│ │ │ │ │
│ ┌──────▼──────────────────▼──────────────────────▼─────────┐ │
│ │ ReactInstanceManager (单例) │ │
│ │ ┌─────────────────────────────────┐ │ │
│ │ │ JS Thread │ │ │
│ │ │ ┌─────────────────────────┐ │ │ │
│ │ │ │ Metro Bundler │ │ │ │
│ │ │ │ (Dev) / Offline Bundle │ │ │ │
│ │ │ └─────────────────────────┘ │ │ │
│ │ └─────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ React Native 层 │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │
│ │ React Nav │ │ 业务组件 │ │ Native Module │ │
│ │ (路由管理) │ │ (UI + 逻辑) │ │ (调用原生能力) │ │
│ └──────────────┘ └──────────────┘ └──────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
4.3 关键设计决策
决策 1:RN 页面用 Activity 还是 Fragment 容器?
| 方案 | 优点 | 缺点 | 结论 |
|---|---|---|---|
| Activity | 生命周期简单,独立性强 | 每次创建新 Activity,内存开销大 | ❌ |
| Fragment | 复用容器,内存友好 | 生命周期复杂,与 RN 对齐困难 | ❌ |
| 单 Activity + 动态 ReactRootView | 兼顾性能和灵活性 | 需要手动管理生命周期 | ✅ |
决策 2:RN Bundle 是内置还是远程下载?
| 方案 | 优点 | 缺点 | 结论 |
|---|---|---|---|
| 内置 | 首屏快,无网络依赖 | 无法热更新,包体积大 | ✅ 基础包 |
| 远程下载 | 包体积小,更新灵活 | 首屏慢,需处理下载失败 | ✅ 增量包 |
最终方案:内置基础包 + 热更新增量包。首次启动用内置包,后台静默下载更新包,下次启动生效。
五、上线后的监控与维护
5.1 性能监控
集成 PerfettoKit 监控 RN 页面的性能:
kotlin
// 在 RN 容器 Activity 中集成
class RNContainerActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 开启 RN 页面性能检测
PerfettoKit.enableAutoDetect(AutoSceneDetector.Config(
detectLaunch = true,
detectScroll = true
))
// ... 初始化 RN
}
}
5.2 崩溃监控
javascript
// RN 端全局错误捕获
import {ErrorUtils} from 'react-native';
const originalHandler = ErrorUtils.getGlobalHandler();
ErrorUtils.setGlobalHandler((error, isFatal) => {
// 上报到原生崩溃监控
NativeModules.CrashReporter.reportError({
message: error.message,
stack: error.stack,
isFatal: isFatal,
page: currentPage,
});
if (originalHandler) {
originalHandler(error, isFatal);
}
});
5.3 关键指标看板
| 指标 | 目标值 | 监控方式 |
|---|---|---|
| RN 页面首屏时间 | < 1.5s | 自定义埋点 |
| 页面掉帧率 | < 3% | PerfettoKit |
| JS 异常率 | < 0.1% | 崩溃监控 |
| 热更新成功率 | > 99% | 服务端统计 |
| 包体积增量 | < 5MB | CI 构建监控 |
六、总结与建议
6.1 核心经验
- Gradle 版本统一是第一步:RN 对 Gradle/AGP 版本敏感,建议先统一再集成
- ReactInstanceManager 必须单例:这是最容易踩的内存泄漏坑
- So 库问题要早验证:在集成初期就确认所有 ABI 的 So 库都能正常加载
- 包体积要持续监控:每加一个依赖都要评估体积影响
- 热更新方案要尽早确定:影响架构设计和发布流程
6.2 适用场景判断
| 场景 | 建议 |
|---|---|
| 新业务快速上线 | ✅ 适合用 RN |
| 复杂交互页面(如地图、视频编辑) | ❌ 建议原生 |
| 对性能要求极高的页面(如首页) | ❌ 建议原生 |
| 需要频繁迭代的内容型页面 | ✅ 适合用 RN |
| 已有成熟原生组件需要复用 | ⚠️ 评估接入成本 |
6.3 后续规划
- RN 新版本升级:当前 0.73,计划跟进 0.74+ 的新架构(Bridgeless + TurboModules)
- 性能优化:探索 RN 的 Fabric 渲染器,提升列表滑动性能
- 跨平台扩展:评估 iOS 端集成 RN 的可行性
如果你在 RN 嵌入原生项目的过程中遇到了其他问题,欢迎在评论区交流。也欢迎关注我们的开源项目:
👉 PerfettoKit (Android 性能诊断 SDK):https://github.com/869225586/PerfettoKit
本文基于实际项目经验整理,RN 版本为 0.73.0,不同版本可能存在差异。