如何使用独立方法将 Expo 添加到原生应用

关于如何将 Expo 和 React Native 添加为本地库,并使用隔离方法将其集成到现有(棕地)本地应用中的指南。


在独立方法中,你的 React Native 代码与本地项目分开开发和维护。你将其打包为本地库,使用 Android 的 AAR 或 iOS 的 XCFramework,并像处理其他依赖一样将其集成到本地应用中。

🌐 In the isolated approach, your React Native code is developed and maintained separately from your native project. You package it as a native library, using an AAR for Android or XCFramework for iOS, and integrate it into your native app like any other dependency.

当你想要将 React Native 对现有原生构建流程的影响降到最低,或当你有原生和 React Native 开发的独立团队时,这种方法是理想的。使用这种方法,原生开发者不需要 Node.js、Yarn 或任何 React Native 构建工具,他们只需使用预构建的工件即可。

🌐 This approach is ideal when you want to minimize the impact of React Native on your existing native build process, or when you have separate teams for native and React Native development. Using this approach, native developers don't need Node.js, Yarn, or any React Native build tooling, and they can just consume pre-built artifacts.

信息 对于将 React Native 直接集成到本地项目中的替代方法,请参见 集成方法指南

先决条件

🌐 Prerequisites

要将 React Native 集成到你现有的应用中,你需要搭建一个 JavaScript 开发环境。这包括安装 Node.js 来运行 Expo CLI,以及安装 Yarn 来管理项目的 JavaScript 依赖。

🌐 To integrate React Native into your existing application, you'll need to set up a JavaScript development environment. This includes installing Node.js to run Expo CLI and Yarn to manage the project's JavaScript dependencies.

  • Node.js(LTS):用于执行 JavaScript 代码和 Expo CLI 的运行时环境。
  • Yarn:一个用于安装和管理 JavaScript 依赖的包管理器。

设置环境指南了解更多信息。

🌐 Learn more from the Set up environment guide.

设置一个 Expo 项目

🌐 Set up an Expo project

1

创建一个新的 Expo 项目

🌐 Create a new Expo project

运行以下命令以创建一个名为 my-project 的新目录,其中包含你的新 Expo 项目。虽然你可以将项目命名为任何名称,但本指南为了保持一致使用 my-project

🌐 Run the following command to create a new directory named my-project that contains your new Expo project. While you can name the project anything, this guide uses my-project for consistency.

Terminal
npx create-expo-app@latest my-project --template default@sdk-55

my-project 不需要存在于你现有的原生应用中,可以在单独的仓库或 monorepo 中创建。新项目包含一个示例 TypeScript 应用,以帮助你入门。

🌐 The my-project does not need to live inside your existing native app and can be created in a separate repository or a monorepo. The new project includes an example TypeScript application to help you get started.

2

安装 expo-brownfield

🌐 Install expo-brownfield

导航到你的新 Expo 项目并安装 expo-brownfield 库,该库提供将你的 React Native 代码构建为原生库并将其集成到现有原生应用中的工具。

🌐 Navigate to your new Expo project and install the expo-brownfield library, which provides the tools to build your React Native code as native libraries and integrate them into your existing native app.

Terminal
npx expo install expo-brownfield

3

调整配置插件(可选)

🌐 Adjust the config plugin (optional)

expo-brownfield 应该会自动在你的 app.json 中的 plugins 数组里添加一项,使用默认配置,这对于大多数项目来说已经足够。

app.json
{ "expo": { "plugins": ["expo-brownfield"] } }

默认值是从你的应用配置中派生的(例如,目标名称基于你的应用方案或标识符)。你也可以传递选项来自定义目标名称、包标识符和发布配置。

🌐 The defaults are derived from your app config (for example, target names are based on your app's scheme or slug). You can also pass options to customize the target names, bundle identifiers, and publishing configuration.

自定义 expo-brownfield 配置
app.json
{ "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 参考

🌐 See the expo-brownfield API reference for details on all available options.

将你的 Expo 项目导出为本地库

🌐 Export your Expo project as a native library

一旦你设置好你的 Expo 项目,使用 expo-brownfield CLI 将你的 React Native 代码构建为 Android 的 AAR 和 iOS 的 XCFrameworks。

🌐 Once you have your Expo project set up, use the expo-brownfield CLI to build your React Native code as AARs for Android and XCFrameworks for iOS.

在你的 Expo 项目目录中,运行:

🌐 From your Expo project directory, run:

Terminal
npx expo-brownfield build:android

这将构建 AAR 并将其发布到 Maven 仓库。默认情况下,它会发布到你的本地 Maven 仓库(~/.m2),但也可以配置为发布到远程仓库。生成的构件名称将由你的配置插件设置决定,在本例中为 com.username.myproject:brownfield:1.0.0

🌐 This will build the AAR and publish it to a Maven repository. By default, it publishes to your local Maven repository (~/.m2), but it can also be configured to publish to a remote repository. The produced artifact name will be determined by your config plugin settings, in this case com.username.myproject:brownfield:1.0.0.

有关构建选项的更多详细信息,例如仅构建调试或发布版本、指定自定义输出目录等,请参阅API参考

🌐 See the API reference for more details on build options, such as building only debug or release, specifying a custom output directory, and more.

在你的 Expo 项目目录中,运行:

🌐 From your Expo project directory, run:

Terminal
npx expo-brownfield build:ios

这将构建 XCFramework 工件:为设备和模拟器架构编译框架目标,将它们打包到 XCFramework 中,并复制 Hermes 引擎框架。

🌐 This will build the XCFramework artifacts: compile the framework target for both device and simulator architectures, package them into XCFrameworks, and copy the Hermes engine framework.

当构建过程完成后,输出将放置在 ./artifacts 目录中,并包含:

🌐 When the build process is completed, the output is placed in the ./artifacts directory and contains:

  • {TargetName}.xcframework - 你的Expo项目作为原生库
  • hermesvm.xcframework - Hermes JavaScript 引擎

有关构建选项的更多详细信息,例如仅构建调试或发布版本、指定自定义输出目录等,请参见 expo-brownfield API 参考

🌐 See the expo-brownfield API reference for more details on build options, such as building only debug or release, specifying a custom output directory, and more.

调试本地目标

如果你需要调试 Expo 项目目标的本地代码,你可以运行 npx expo prebuild 来生成包含棕地库目标的本地项目,位于 androidios 目录中。

🌐 If you need to debug native code of the Expo project targets, you can run npx expo prebuild to generate the native projects with the brownfield library targets, inside the android and ios` directories.

Terminal
npx expo prebuild

上述命令生成以下内容:

🌐 The above command generates the following:

  • Android:一个单独的库模块,包含 ReactNativeHostManagerBrownfieldActivityReactNativeFragmentReactNativeViewFactoryBrownfieldMessaging
  • iOS:一个单独的 Xcode 框架目标,包含 ReactNativeHostManagerReactNativeViewControllerReactNativeView(SwiftUI)、BrownfieldMessagingReactNativeDelegate

集成到你的原生应用中

🌐 Integrate into your native app

在构建好这些工件后,你现在可以将它们集成到你现有的原生应用中。具体步骤将取决于你的项目结构和构建系统,但总体流程包括将预构建的工件作为依赖添加,并初始化 React Native 主机。

🌐 With the artifacts built, you can now integrate them into your existing native app. The exact steps will depend on your project structure and build system, but the general process involves adding the pre-built artifacts as dependencies and initializing the React Native host.

1

添加 Maven 依赖

🌐 Add the Maven dependency

首先将依赖添加到你应用的 build.gradle.kts 中。组、工件名称和版本应与你的配置插件设置匹配:

🌐 Start by adding the dependency to your app's build.gradle.kts. The group, artifact name, and version should match your config plugin settings:

app/build.gradle.kts
dependencies { implementation("com.username.myproject:brownfield:1.0.0") }

如果库已经发布到本地 Maven,请确保在你的仓库配置中添加 mavenLocal()

🌐 If the library was published to local Maven, make sure to add mavenLocal() to your repository configuration:

settings.gradle.kts
dependencyResolutionManagement { repositories { google() mavenCentral() mavenLocal() } }

2

显示一个 React Native 界面

🌐 Show a React Native screen

创建一个继承 BrownfieldActivity 的活动,并使用 showReactNativeFragment() 扩展:

🌐 Create an activity that extends BrownfieldActivity and use the showReactNativeFragment() extension:

ExpoActivity.kt
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 中,并使用非 ActionBar 主题:

🌐 Add the activity to your AndroidManifest.xml with a non-ActionBar theme:

AndroidManifest.xml
<activity android:name=".ExpoActivity" android:theme="@style/Theme.AppCompat.Light.NoActionBar" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode" />

然后从你应用中的任何地方启动它:

🌐 Then launch it from anywhere in your app:

startActivity(Intent(this, ExpoActivity::class.java))

BrownfieldActivity 继承自 AppCompatActivity 并处理将配置更改转发到 Expo 模块。showReactNativeFragment() 扩展还会自动设置本地返回按钮处理。

1

将 XCFrameworks 添加到你的项目中

🌐 Add XCFrameworks to your project

将两个 XCFramework 文件({TargetName}.xcframeworkhermesvm.xcframework)拖入你的 Xcode 项目导航器。在出现的对话框中:

🌐 Drag both XCFramework files ({TargetName}.xcframework and hermesvm.xcframework) into your Xcode project navigator. In the dialog that appears:

  • 检查 如有必要,复制项目
  • 将它们添加到你的应用目标

然后,在你的目标的 General 选项卡下的 Frameworks, Libraries, and Embedded Content 中,确保两个框架都设置为 Embed & Sign

🌐 Then, in your target's General tab under Frameworks, Libraries, and Embedded Content, ensure both frameworks are set to Embed & Sign.

2

初始化 React Native

🌐 Initialize React Native

在应用的生命周期早期调用 ReactNativeHostManager.shared.initialize()。一个合适的地方是你的 AppDelegate

🌐 Call ReactNativeHostManager.shared.initialize() early in your app's lifecycle. A good place is your AppDelegate:

AppDelegate.swift
import UIKit import MyAppBrownfield // Replace with your target name @main class AppDelegate: UIResponder, UIApplicationDelegate { func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { ReactNativeHostManager.shared.initialize() return true } }

3

展示一个 React Native 视图

🌐 Present a React Native view

ViewController.swift
import UIKit import MyAppBrownfield class ViewController: UIViewController { @IBAction func openReactNative(_ sender: Any) { let rnViewController = ReactNativeViewController(moduleName: "main") navigationController?.pushViewController(rnViewController, animated: true) } }

ReactNativeViewController 还接受可选的 initialPropslaunchOptions 参数:

🌐 The ReactNativeViewController also accepts optional initialProps and launchOptions parameters:

let rnViewController = ReactNativeViewController( moduleName: "main", initialProps: ["userId": "123"], launchOptions: [:] )
ContentView.swift
import SwiftUI import MyAppBrownfield struct ContentView: View { @State private var showReactNative = false var body: some View { Button("Open React Native") { showReactNative = true } .fullScreenCover(isPresented: $showReactNative) { ReactNativeView(moduleName: "main") } } }

测试你的集成

🌐 Test your integration

你已经完成了将 React Native 集成到你的应用中的所有基本步骤。现在是测试它的时候了。具体过程将取决于你运行的是调试版本还是发布版本。

🌐 You have completed all the basic steps to integrate React Native with your application. Now it's time to test it out. The exact process will depend on whether you're running a debug or release build.

开发(调试版)

🌐 Development (debug builds)

现在在 React Native 目录中运行以下命令以启动 Metro 打包器

🌐 Now run the following command in the React Native directory to start the Metro bundler

Terminal
npx expo start

然后,从 Android Studio 或 Xcode 构建并运行本地应用。当你导航到 React Native 界面时,它将从 Metro 开发服务器加载,并支持热重载。

🌐 Then, build and run the native app from Android Studio or Xcode. When you navigate to the React Native screen, it will load from the Metro dev server with hot reloading support.

生产(发布版本)

🌐 Production (release builds)

在发布版本中,JavaScript 包会嵌入到制品(AAR 或 XCFramework)中,因此不需要 Metro 服务器。以 Release 配置构建原生应用,并验证 React Native 界面是否正确加载。

🌐 In release builds, the JavaScript bundle is embedded in the artifact (AAR or XCFramework), so the Metro server is not needed. Build the native app in Release configuration and verify the React Native screen loads correctly.

下一步

🌐 Next steps

生命周期监听器

配置应用生命周期监听器,以实现与 Expo 模块的更深层集成。

expo-brownfield API 参考

探索用于通信、导航等功能的完整 JavaScript API。