如何使用隔离方法将 Expo 添加到原生应用
编辑页面
一份关于将 Expo 和 React Native 作为原生库添加,并使用隔离方法将其集成到现有(brownfield)原生应用中的指南。
For the complete documentation index, see llms.txt. Use this file to discover all available pages.
在隔离式方案中,你的 React Native 代码是独立于原生项目进行开发和维护的。你将其打包为原生库,Android 使用 AAR,iOS 使用 XCFramework,并像其他依赖一样将其集成到原生应用中。
当你希望尽量减少 React Native 对现有原生构建流程的影响,或者原生开发与 React Native 开发由不同团队负责时,这种方案最为理想。使用这种方案后,原生开发者不需要 Node.js、Yarn 或任何 React Native 构建工具链,他们只需使用已经构建好的产物即可。
信息 如果你想了解另一种将 React Native 直接集成到原生项目中的方案,请参阅 集成式方案指南。
2 requirements
2 requirements
更多信息请参阅 环境搭建指南。
设置 Expo 项目
1
2
3
调整配置插件(可选)
expo-brownfield 应会自动使用默认配置在你的 app.json 中的 plugins 数组里添加一项,这对于大多数项目来说已经足够。
{ "expo": { "plugins": ["expo-brownfield"] } }
默认值会根据你的应用配置推导而来(例如,目标名称会基于应用的 scheme 或 slug)。你也可以传入选项来自定义目标名称、包标识符和发布配置。
自定义 expo-brownfield 配置
{ "expo": { "plugins": [ [ "expo-brownfield", { "ios": { "targetName": "MyBrownfield", "bundleIdentifier": "com.example.mybrownfield" }, "android": { "libraryName": "mybrownfield", "group": "com.example", "package": "com.example.mybrownfield", "version": "1.0.0" } } ] ] } }
有关所有可用选项的详细信息,请参阅 expo-brownfield API 参考。
将 Expo 项目导出为原生库
完成 Expo 项目设置后,使用 expo-brownfield CLI 将你的 React Native 代码构建为 Android 的 AAR 和 iOS 的 XCFramework。
在你的 Expo 项目目录中运行:
- npx expo-brownfield build:android这会构建 AAR 并将其发布到 Maven 仓库。默认情况下,它会发布到你的本地 Maven 仓库(~/.m2),但也可以配置为发布到远程仓库。
生成的产物名称将由你的配置插件设置决定,在这个例子中是 com.username.myproject:brownfield:1.0.0。
有关构建选项的更多详情,请参阅 API 参考,例如仅构建 debug 或 release、指定自定义输出目录等。
在你的 Expo 项目目录中运行:
- npx expo-brownfield build:ios这会构建 XCFramework 产物:为设备和模拟器架构分别编译 framework 目标,将它们打包为 XCFramework,并复制 Hermes 引擎 framework。
构建过程完成后,输出会放在 ./artifacts 目录中,并包含:
- {TargetName}.xcframework - 你的 Expo 项目作为原生库
- hermesvm.xcframework - Hermes JavaScript 引擎
有关构建选项的更多详情,请参阅 expo-brownfield API 参考,例如仅构建 debug 或 release、指定自定义输出目录等。
将产物作为 Swift 包发布
传入 --package [name] 标志,可以将构建输出打包为一个独立的 Swift 包,而不是分别生成 .xcframework 目录。然后,你可以在 Xcode 中将其作为本地依赖添加到宿主应用,而不是手动将 framework 拖入项目。
- npx expo-brownfield build:ios --release --package MyAppPackage该标志接受一个可选名称。如果省略,包默认命名为 {TargetName}Artifacts。生成的目录是一个完整的 Swift 包,其结构如下:
artifactsMyAppPackagePackage.swiftxcframeworksMyAppPackage.xcframeworkhermesvm.xcframeworkReact.xcframeworkReactNativeDependencies.xcframework调试原生目标
如果你需要调试 Expo 项目目标的原生代码,可以运行 npx expo prebuild 来生成带有 brownfield 库目标的原生项目,位于 android 和 ios 目录中。
- npx expo prebuild上述命令会生成以下内容:
- Android:一个单独的库模块,包含
ReactNativeHostManager、BrownfieldActivity、ReactNativeFragment、ReactNativeViewFactory和BrownfieldMessaging。 - iOS:一个单独的 Xcode framework 目标,包含
ReactNativeHostManager、ReactNativeViewController、ReactNativeView(SwiftUI)、BrownfieldMessaging和ReactNativeDelegate。
集成到你的原生应用中
在构建好产物后,你现在可以将它们集成到现有原生应用中。具体步骤将取决于你的项目结构和构建系统,但整体流程包括将预构建产物作为依赖添加进去,并初始化 React Native host。
1
添加 Maven 依赖
首先将依赖添加到你的应用 build.gradle.kts 中。group、artifact 名称和版本应与你的配置插件设置一致:
dependencies { implementation("com.username.myproject:brownfield:1.0.0") }
如果该库是发布到本地 Maven,请确保在仓库配置中添加 mavenLocal():
dependencyResolutionManagement { repositories { google() mavenCentral() mavenLocal() } }
2
显示 React Native 屏幕
创建一个继承自 BrownfieldActivity 的 activity,并使用 showReactNativeFragment() 扩展方法:
import android.os.Bundle import com.example.brownfield.BrownfieldActivity import com.example.brownfield.showReactNativeFragment class ExpoActivity : BrownfieldActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) showReactNativeFragment() } }
在你的 AndroidManifest.xml 中添加该 activity,并使用一个非 ActionBar 主题:
<activity android:name=".ExpoActivity" android:theme="@style/Theme.AppCompat.Light.NoActionBar" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode" />
然后在应用中的任意位置启动它:
startActivity(Intent(this, ExpoActivity::class.java))
BrownfieldActivity 继承自 AppCompatActivity,并负责将配置变化转发给 Expo 模块。showReactNativeFragment() 扩展方法也会自动配置原生返回按钮处理。
1
将产物添加到你的项目中
集成步骤取决于你构建的是 XCFramework 还是 Swift 包。
将两个 XCFramework 文件({TargetName}.xcframework 和 hermesvm.xcframework)拖入 Xcode 项目导航器。在弹出的对话框中:
- 勾选 Copy items if needed
- 将它们添加到你的 app target
然后,在你的 target 的 General 选项卡中,找到 Frameworks, Libraries, and Embedded Content,确保这两个 framework 都设置为 Embed & Sign。
当 build:ios 生成 Swift 包时(例如 ./artifacts/MyAppPackage-release),在 Xcode 中将其作为本地依赖添加到宿主应用,并选择该包目录。Xcode 会通过聚合库产品自动链接捆绑的 .xcframework 文件。
若要同时支持 --debug 和 --release,请让宿主应用针对每种构建配置指向相应的包。
2
初始化 React Native
在应用生命周期的早期调用 ReactNativeHostManager.shared.initialize()。一个合适的位置是你的 AppDelegate:
import UIKit import MyAppBrownfield // 将其替换为你的 target 名称 @main class AppDelegate: UIResponder, UIApplicationDelegate { func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { ReactNativeHostManager.shared.initialize() return true } }
3
展示 React Native 视图
import UIKit import MyAppBrownfield class ViewController: UIViewController { @IBAction func openReactNative(_ sender: Any) { let rnViewController = ReactNativeViewController(moduleName: "main") navigationController?.pushViewController(rnViewController, animated: true) } }
ReactNativeViewController 也接受可选的 initialProps 和 launchOptions 参数:
let rnViewController = ReactNativeViewController( moduleName: "main", initialProps: ["userId": "123"], launchOptions: [:] )
import SwiftUI import MyAppBrownfield struct ContentView: View { @State private var showReactNative = false var body: some View { Button("打开 React Native") { showReactNative = true } .fullScreenCover(isPresented: $showReactNative) { ReactNativeView(moduleName: "main") } } }
测试你的集成
你已经完成了将 React Native 集成到应用中的所有基础步骤。现在是时候测试一下了。具体流程取决于你运行的是 debug 还是 release 构建。
开发(debug 构建)
现在在 React Native 目录中运行以下命令,以启动 Metro bundler
- npx expo start然后,从 Android Studio 或 Xcode 构建并运行原生应用。当你进入 React Native 屏幕时,它会从 Metro 开发服务器加载,并支持热重载。
生产(release 构建)
在 release 构建中,JavaScript bundle 会嵌入到产物(AAR 或 XCFramework)中,因此不需要 Metro 服务器。以 Release 配置构建原生应用,并确认 React Native 屏幕能够正确加载。
下一步
为 Expo 模块配置应用生命周期监听器,以实现更深度的集成。
探索用于通信、导航等功能的完整 JavaScript API。