首页指南参考教程

预建

了解 Expo CLI 在编译项目之前如何生成项目的原生代码。


在编译原生应用之前,必须生成原生源代码。Expo CLI 提供了一个名为 prebuild 的独特而强大的系统,它根据四个因素为你的项目生成原生代码:

¥Before a native app can be compiled, the native source code must be generated. Expo CLI provides a unique and powerful system called prebuild, which generates the native code for your project based on four factors:

  1. 应用配置 文件(app.json、app.config.js)。

    ¥The app config file (app.json, app.config.js).

  2. 传递给 npx expo prebuild 命令的参数。

    ¥Arguments passed to the npx expo prebuild command.

  3. 项目中安装的 expo 版本及其对应的 预构建模板

    ¥Version of expo that's installed in the project and its corresponding prebuild template.

  4. 自动链接,用于链接 package.json 中找到的 原生模块

    ¥Autolinking, for linking native modules found in the package.json.

用法

¥Usage

可以通过运行以下命令来使用预构建:

¥Prebuild can be used by running:

Terminal
npx expo prebuild

这将创建用于运行 React 代码的 android 和 ios 目录。如果你手动修改生成的目录,那么你下次运行 npx expo prebuild --clean 时可能会丢失所做的更改。相反,你应该创建 配置插件 — 在预构建期间对原生项目执行修改的函数。

¥This creates the android and ios directories for running your React code. If you modify the generated directories manually then you risk losing your changes the next time you run npx expo prebuild --clean. Instead, you should create config plugins — functions that perform modifications on native projects during prebuild.

由于 pitch 部分中列出的原因,我们强烈建议使用预构建,但系统是 完全可选,你可以随时停止使用它。

¥We highly recommend using prebuild for the reasons listed in the pitch section, but the system is fully optional and you can stop using it at any time.

与 EAS 构建一起使用

¥Usage with EAS Build

如果你的项目不包含 android 和 ios 目录,EAS Build 将在编译前运行 Prebuild 生成这些原生目录。这是使用 npx create-expo-app 创建的任何项目的默认行为。

¥If your project does not contain android and ios directories, EAS Build will run Prebuild to generate these native directories before compilation. This is the default behavior for any project created using npx create-expo-app.

对于具有 android 和 ios 目录的项目,EAS Build 默认情况下不会运行 Prebuild,以避免覆盖你对原生目录所做的任何更改。

¥For a project that has android and ios directories, EAS Build will not run Prebuild by default to avoid overwriting any changes you've made to the native directories.

如果你通过 本地编译(运行 npx expo prebuild、或 npx expo run:androidnpx expo run:ios)对应用进行故障排除,你仍然可以使用 Prebuild 和 EAS Build 在构建过程中生成新的原生目录。在这种情况下,将 android 和 ios 目录添加到 .gitignore 或 .easignore 文件中:

¥If you troubleshoot your app by compiling it locally (running npx expo prebuild, or npx expo run:android or npx expo run:ios), you can still use Prebuild with EAS Build to generate fresh native directories during the build process. In this scenario, add the android and ios directories to .gitignore or .easignore files:

.gitignore
+ android/
+ ios/

与 Expo CLI 运行命令一起使用

¥Usage with Expo CLI run commands

你可以通过运行以下命令在本地执行原生构建:

¥You can perform a native build locally by running:

Terminal
# Build your native Android project
npx expo run:android

# Build your native iOS project
npx expo run:ios

如果原生构建目录不存在,npx expo prebuild 将针对你希望运行的特定平台运行一次。在后续使用运行命令时,你将需要手动运行 npx expo prebuild 以确保原生代码与本地配置最新同步。

¥If native build directories are not present npx expo prebuild will be run one time for the specific platform you wish to run. On subsequent uses of the run commands, you will need to manually run npx expo prebuild to ensure the native code is freshly synchronized with your local configuration.

平台支持

¥Platform support

Prebuild 目前支持 Android 和 iOS。不需要 Web 支持,因为没有为 Web 生成的原生项目 - 它运行的应用始终是你的 Web 浏览器。你可以使用 --platform 标志为各个平台构建:

¥Prebuild currently supports Android and iOS. Web support is not required because there is no native project to generate for the web — the app it runs in is always your web browser. You can build for individual platforms by using the --platform flag:

Terminal
npx expo prebuild --platform ios

依赖

¥Dependencies

预构建的第一步是从模板初始化新的原生项目。每个 Expo SDK 版本都有一个模板,每个 Expo SDK 版本对应 React 和 React Native 的特定版本。仅当项目中的 React 和 React Native 版本不相同时,它们才会更新为 template package.json 中 dependencies 字段中使用的版本。

¥The first step in prebuild is to initialize new native projects from a template. There is a template for each Expo SDK version, and each Expo SDK version corresponds to a specific version of React and React Native. The React and React Native versions in your project will be updated to the versions used in the dependencies field in the template package.json, only, if they are not already the same.

你可以使用 --skip-dependency-update 标志跳过更改 npm 软件包版本:

¥You can skip changing npm package versions with the --skip-dependency-update flag:

Terminal
npx expo prebuild --skip-dependency-update react-native,react

包管理器

¥Package managers

dependencies 更改时,预构建将使用项目中当前使用的包管理器重新安装包(这是从锁定文件推断的)。你可以通过提供以下之一来强制使用特定的包管理器:--npm--yarn--pnpm

¥When the dependencies are changed, prebuild will reinstall packages using the package manager that is currently used in the project (this is inferred from the lockfile). You can force a specific package manager by providing one of: --npm, --yarn, --pnpm.

通过传递 --no-install 命令可以跳过所有安装,这对于快速测试生成很有用。

¥All installations can be skipped by passing the --no-install command, which is useful for testing generation quickly.

清理

¥Clean

--clean 标志将在生成之前删除任何现有的原生目录。

¥The --clean flag will delete any existing native directories before generating.

当你在不带 --clean 标志的情况下重新运行 npx expo prebuild 时,它会将更改叠加到现有文件之上。这比从头开始重新生成要快,但在某些情况下可能不会产生相同的结果。例如,并非所有配置插件都是幂等的 - 当你的项目使用大量 "危险修饰语" 来执行更改(例如向应用代码添加正则表达式更改)时,这有时会导致意外行为。这就是为什么使用 --clean 标志是使用预构建命令的最安全方法,并且在大多数情况下通常建议这样做。

¥When you re-run npx expo prebuild without the --clean flag, it layers the changes on top of your existing files. This is faster than re-generating from scratch, but it may not produce the same results in some cases. For example, not all config plugins are idempotent — when your project utilizes a lot of "dangerous modifiers" for performing changes like adding regex changes to application code, this can sometimes lead to unexpected behavior. This is why using the --clean flag is the safest way to use the prebuild command and it is generally recommended in most cases.

由于该标志的破坏性,当使用 --clean 标志时,系统会警告你保持干净的 git 状态。该提示是可选的,在 CI 中遇到时会跳过。

¥Due to the destructive nature of the flag, you'll be warned to have a clean git status when the --clean flag is used. This prompt is optional and will be skipped when encountered in CI.

如果你愿意,可以通过启用环境变量 EXPO_NO_GIT_STATUS=1 来禁用检查。

¥If you'd like, you can disable the check by enabling the environment variable EXPO_NO_GIT_STATUS=1.

该提示的目的是鼓励托管工作流用户将 android 和 ios 目录添加到项目的 .gitignore 中,确保项目始终处于托管状态。但是,这可能会使自定义配置插件更难开发,因此我们没有引入任何机制来强制执行此行为。

¥The purpose of the prompt is to encourage managed workflow users to add the android and ios directories to the project's .gitignore, ensuring that the project is always managed. However, this can make custom config plugins harder to develop so we haven't introduced any mechanism to enforce this behavior.

在某些情况下,开发者可能希望经常在工作流程之间进行交换。例如,你可能希望在 Xcode 和 Android Studio 中本地构建自定义功能,然后将该功能移至本地配置插件中。

¥There are cases where developers may want to swap between workflows often. For example, you may want to build custom functionality natively in Xcode and Android Studio, and then move that functionality into local config plugins.

模板

¥Templates

你可以通过构建 配置插件 自定义原生文件夹的生成方式,同时保留在托管工作流程中。许多配置插件已经存在,可以进行大量修改。你可以 查看一些流行插件的列表 了解更多信息。

¥You can customize how the native folders are generated while remaining in the managed workflow by building config plugins. Many config plugins already exist for lots of modifications. You can see a list of some popular plugins for more information.

预构建会在使用配置插件修改模板文件之前生成模板文件。模板文件基于 Expo SDK 版本,来自 npm 包 expo-template-bare-minimum。你可以通过将 --template /path/to/template.tgz 传递给 npx expo prebuild 命令来更改使用的模板。通常不建议这样做,因为 @expo/prebuild-config 中的基本修饰符对模板文件做出了一些未记录的假设,因此维护自定义模板可能很棘手。

¥Prebuild generates template files before modifying them with config plugins. The template files are based on the Expo SDK version and come from the npm package expo-template-bare-minimum. You can change the template used by passing --template /path/to/template.tgz to the npx expo prebuild command. This is not generally recommended because the base modifiers in @expo/prebuild-config make some undocumented assumptions about the template files, so it may be tricky to maintain your custom template.

注意:在所有包都是从私有注册表下载并且 npm 公共注册表访问被阻止的网络环境中,必须将本地可用的模板传递给预构建命令。了解有关使用默认模板的本地版本的详细信息

¥Note: In network environments where all packages are downloaded from a private registry and npm public registry access is blocked, a locally-available template must be passed to the prebuild command. Learn more about using a local version of the default template.

副作用

¥Side effects

除了生成 android 和 ios 目录之外,npx expo prebuild 还执行一些副作用。消除这些副作用的工作正在进行中 - 理想情况下,运行 npx expo prebuild 将生成 Android 和 iOS 项目,并且项目的其余部分保持不变。

¥npx expo prebuild performs several side effects outside of generating the android and ios directories. Work is in progress to eliminate these side effects — ideally, running npx expo prebuild would generate the Android and iOS projects and leave the rest of the project untouched.

prebuild 除了生成 native 文件夹外,还做了以下修改:

¥In addition to generating the native folders, prebuild also makes the following modifications:

  • 修改 package.json 中的 scripts 字段。

    ¥Modifies the scripts field in the package.json.

  • 修改 package.json 中的 dependencies 字段。

    ¥Modifies the dependencies field in the package.json.

  • 对于 SDK 48 及更低版本,删除 package.json 中的 main 字段。

    ¥For SDK 48 and below, removes the main field in the package.json.

  • 对于 SDK 48 及更低版本,生成一个 index.js 文件(如果不存在)。

    ¥For SDK 48 and below, generates an index.js file (if it doesn't exist).

  • 对于 SDK 48 及更低版本,会生成 Metro.config.js 文件(如果不存在)。

    ¥For SDK 48 and below generates a metro.config.js file (if it doesn't exist).

scripts 字段的方便更改是改变开发者在预构建之前/之后处理应用的方式的唯一副作用。所有其他更改都可以保留并提交给 git,以最大限度地减少运行预构建时的差异。

¥The convenience change to the scripts field is the only side effect that alters how a developer works on their app before/after prebuild. All other changes can be left in place and committed to git to minimize the diff when running prebuild.

可选

¥Optionality

预构建是完全可选的,它可以与 Expo 提供的所有工具和服务完美配合。我们创建了名称裸工作流程来指代不使用 npx expo prebuild 的项目 - 开发者直接更改其原生项目的项目,而不是像预构建那样根据需要不断生成它们。

¥Prebuilding is completely optional and it works great with all tools and services offered by Expo. We created the designation bare workflow to refer to projects that do not use npx expo prebuild — projects where developers make direct changes to their native projects, rather than continuously generating them on demand as with prebuild.

Expo 提供的所有内容(包括 EAS、Expo CLI 和 Expo SDK 中的库)都是为了完全支持裸工作流程而构建的,因为这是支持使用 npx expo prebuild 的项目的最低要求。唯一的例外是 Expo 应用,它可以加载裸工作流项目,但前提是它们的结构可以为 Expo Go 运行时中不存在的原生代码提供 JavaScript 后备。

¥Everything offered by Expo including EAS, Expo CLI, and the libraries in the Expo SDK are built to fully support the bare workflow as this is a minimum requirement for supporting projects using npx expo prebuild. The only exception is the Expo Go app, which can load bare workflow projects, but only if they are structured to provide JavaScript fallbacks for native code that does not exist in the Expo Go runtime.

投入

¥Pitch

单个原生项目本身的维护、扩展和发展都很复杂。在跨平台应用中,你有多个原生项目,你必须维护这些项目并保持最新的操作系统版本,以避免在任何第三方依赖中落后太多。我们创建了可选的 Expo Prebuild 系统来简化此过程。以下是我们在 React Native 背景下发现的原生开发的一些问题,以及我们认为 Expo Prebuild 解决这些问题的一些相应原因。

¥A single native project on its own is complicated to maintain, scale, and grow. In a cross-platform app, you have multiple native projects that you must maintain and keep up to date with the latest operating system releases to avoid falling too far behind in any third-party dependencies. We created the optional Expo Prebuild system to streamline this process. Below are a few issues we've identified with native development in the context of React Native and some corresponding reasons we believe Expo Prebuild solves these issues.

Prebuild 可用于任何 React Native 项目。欲了解更多信息,请参阅 采用预构建

¥Prebuild can be used in any React Native project. For more information, see Adopt prebuild.

明智的升级

¥Sensible upgrades

构建原生代码需要基本熟悉原生平台的默认工具,这导致学习曲线相当困难。在跨平台中,这条曲线乘以你希望开发的平台数量。如果你需要在特定于平台的原生代码中单独实现许多功能,那么跨平台工具无法解决此问题。

¥Building native code requires a basic familiarity with that native platform's default tooling leading to a fairly difficult learning curve. In cross-platform, this curve is multiplied by the number of platforms you wish to develop for. Cross-platform tooling doesn't solve this issue if you need to drop down and implement many features individually in platform-specific native code.

当你引导原生应用时,你无需理解即可开始使用大量代码和配置。但你现在拥有它。最终,你将想要升级你的原生应用,现在你需要熟悉所有初始代码的工作原理才能安全地升级它。这是极具挑战性的,用户经常要么错误地升级他们的应用,遗漏关键的更改,要么他们会引导一个新的应用并将所有源代码复制到新应用中。

¥When you bootstrap a native app, there is a bunch of code and configuration that you don't need to understand to get started. But you now own it. Eventually, you will want to upgrade your native application and now you'll need to be familiar with how all of the initial code works to safely upgrade it. This is extremely challenging and users often either upgrade their app incorrectly, missing crucial changes, or they'll bootstrap a new app and copy all of their source code into the new application.

使用 Prebuild 升级更接近于升级纯 JavaScript 应用。更改 package.json 中的版本并重新生成原生项目。

¥With Prebuild upgrading is much closer to upgrading a pure JavaScript application. Bump the versions in your package.json and regenerate the native project.

跨平台配置

¥Cross-platform configuration

应用图标、名称、启动画面等跨平台配置必须在原生代码中手动实现。这些在不同平台上的实现方式通常非常不同。

¥Cross-platform configurations such as the app icon, name, splash screen, and so on must be implemented manually in native code. These are often implemented very differently across platforms.

使用 Prebuild,跨平台配置是在配置插件级别处理的,开发者只需设置一个值(如 "icon": "./icon.png")即可处理所有图标生成。

¥With Prebuild cross-platform configurations are handled at the config plugin level, and the developer only needs to set a single value like "icon": "./icon.png" to have all icon generation taken care of.

依赖副作用

¥Dependency side effects

许多复杂的原生包需要除安装和 autolinking 之外的其他设置。例如,相机库需要将权限设置添加到 AndroidManifest.xml(适用于 Android)和 Info.plist(适用于 iOS)。这个额外的设置可以被认为是包的配置副作用。将所需的副作用代码粘贴到项目的原生文件中可能会导致严重的原生编译错误,而且它也是你现在拥有和维护的代码。

¥Many complex native packages require additional setup beyond installing and autolinking. For example, a camera library requires permission settings to be added to AndroidManifest.xml for Android and Info.plist for iOS. This additional setup can be considered a configuration side effect of a package. Pasting the required side effect code into your project's native files can lead to difficult native compilation errors, and it's also code that you now own and maintain.

通过预构建库,作者比任何人都更了解如何配置他们的库,他们可以创建一个名为 配置插件 的可测试和版本化脚本,以自动为其库添加所需的配置副作用。这意味着库副作用可以更具表现力、更强大、更稳定。对于原生代码副作用,我们还提供了默认 预构建模板 中标配的 AppDelegate 订阅者Android 生命周期监听器

¥With Prebuild library authors, who know how to configure their library better than anyone, can create a testable and versioned script called a config plugin, to automate adding the required configuration side effects for their library. This means library side effects can be more expressive, powerful, and stable. For native code side effects, we also provide AppDelegate Subscribers and Android Lifecycle Listeners which come standard in the default prebuild template.

孤立代码

¥Orphaned code

当你卸载软件包时,你必须确保删除了使该软件包正常工作所需的所有副作用。如果你遗漏了任何内容,就会导致你无法追溯到任何特定包的孤立代码,这些代码会不断累积并使你的项目更难以理解和维护。

¥When you uninstall a package you have to be certain you removed all of the side effects required to make that package work. If you miss anything, it leads to orphaned code that you cannot trace back to any particular package, this code builds up and makes your project harder to understand and maintain.

使用 Prebuild 的唯一副作用是项目的 Expo 配置 (app.json) 中的 配置插件,当卸载相应的节点模块时,它会抛出错误,这意味着孤立的配置会减少很多。

¥With Prebuild the only side effect is the config plugin in a project's Expo config (app.json), which will throw an error when the corresponding node module has been uninstalled, meaning a lot less orphaned configuration.

反投入

¥Anti-pitch

以下是 Expo 预建可能不适合特定项目的一些原因。

¥Here are some reasons Expo Prebuilding might not be the right fit for a particular project.

React Native 版本控制

¥React Native versioning

npx expo prebuild 根据项目已安装的 expo 版本生成原生代码,因此具有 SDK 50 (expo@50.0.0) 的项目将生成 react-native@0.73 应用。

¥npx expo prebuild generates native code based on the version of expo a project has installed, so a project with SDK 50 (expo@50.0.0) would generate a react-native@0.73 app.

Expo 大约每个季度都会发布一个新版本,而 react-native 并不遵循基于日历的发布时间表。这意味着有时你无法将 npx expo prebuild 与最新版本的 React Native 一起使用。如果你愿意尝试,可以通过使用自定义 预构建模板 来规避此问题。你还可以通过从最新版本的 React Native 中挑选所需的任何更改到分支并在项目中使用来缓解这种情况。

¥Expo releases a new version approximately every quarter, and react-native does not follow a calendar-based release schedule. This means there are times when you cannot use npx expo prebuild with the latest release of React Native. This could potentially be circumvented by using a custom prebuild template if you are willing to experiment. You can also mitigate this by cherry-picking any changes you need from the latest version of React Native into a fork and using that in your project.

平台兼容性

¥Platform compatibility

Prebuild 只能用于 Expo SDK 支持的原生平台。暂时指的是 Android 和 iOS。Web 除外,它不需要 npx expo prebuild,因为它使用浏览器而不是自定义原生运行时。

¥Prebuild can only be used for native platforms that are supported by the Expo SDK. This means Android and iOS for the time being. Except for web, which doesn't require npx expo prebuild since it uses the browser instead of a custom native runtime.

将来,我们希望支持更多平台,例如 react-native-macosreact-native-windows,但这不是目前的优先事项。

¥In the future, we would like to support additional platforms, such as react-native-macos and react-native-windows, but this is not currently a priority.

如果你的目标是其他平台,你仍然可以为你的 android 和 ios 项目使用预构建 - 任何额外的平台都必须同时手动配置。

¥If you are targeting additional platforms, you can still use prebuild for your android, and ios projects — any extra platforms will have to be configured manually in the meantime.

直接进行更改比模块化和自动化更快

¥Making changes directly is quicker than modularizing and automating

所有原生更改都必须添加原生模块(使用 React Native 的内置原生模块 API 或 Expo Modules API)和配置插件。这意味着,如果你想快速将原生文件添加到项目中进行实验,那么你最好运行预构建并手动添加文件,然后使用 monorepo.1 重新进入系统。我们计划通过向 Expo 自动链接 添加功能来加快此过程,该功能可在原生文件夹之外查找项目原生文件并在构建之前链接它们。

¥All native changes must be added with native modules (using React Native's built-in Native Module APIs or the Expo Modules API) and config plugins. This means if you want to quickly add a native file to your project to experiment, then you may be better off running prebuild and adding the file manually, then working your way back into the system with a monorepo. We plan to speed this process up by adding functionality to Expo Autolinking that finds project native files outside of the native folders and links them before building.

如果你想修改配置,例如 gradle.properties 文件,你必须编写一个插件(example)。这可以通过帮助插件库轻松实现自动化,但是,如果你需要经常这样做,速度会慢一些。

¥If you want to modify the configuration, such as the gradle.properties file, you'll have to write a plugin (example). This can be easily automated with helper plugin libraries, however, it is a bit slower if you need to do it often.

社区中的配置插件支持

¥Config plugin support in the community

并非所有软件包都支持 Expo Prebuilding。如果你发现某个库在安装后需要额外设置并且还没有配置插件,我们建议你打开拉取请求或问题,以便维护者了解该功能请求。

¥Not all packages support Expo Prebuilding yet. If you find a library that requires extra setup after installation and doesn't yet have a config plugin, we recommend opening a pull request or an issue so that the maintainer is aware of the feature request.

许多软件包(例如 react-native-blurhash)除了 autolinking 处理的内容之外不需要任何额外的原生配置,因此不需要配置插件。

¥Many packages, such as react-native-blurhash, don't require any additional native configuration beyond what is handled by autolinking and so no config plugin is required.

其他软件包,例如 react-native-ble-plx,确实需要额外的设置,因此需要一个配置插件与 npx expo prebuild 一起使用(在这种情况下,有一个名为 @config-plugins/react-native-ble-plx 的外部插件)。

¥Other packages, such as react-native-ble-plx, do require additional setup and therefore require a config plugin to be used with npx expo prebuild (in this case there's an external plugin called @config-plugins/react-native-ble-plx).

另外,我们还有 树外配置插件 的存储库,它为尚未采用该系统的流行软件包提供插件。可以将其想象为 TypeScript 的 DefinitelyTyped。我们更喜欢软件包提供自己的配置插件,但如果他们尚未采用该系统,社区可以使用存储库中列出的软件包。

¥Alternatively, we also have a repo for out-of-tree config plugins which provides plugins for popular packages that haven't adopted the system yet. Think of this like DefinitelyTyped for TypeScript. We prefer packages ship their own config plugin, but if they haven't adopted the system yet, the community can use the packages listed in the repo.

Expo 中文网 - 粤ICP备13048890号