从 "Expo 建设" 迁移

从 "Expo 建设"(经典版本)迁移到 EAS 版本的参考。


本页介绍了将 Expo 托管应用expo build(也称为经典版本)迁移到 EAS Build 时你应该了解的实际差异。如果这是你第一次使用 EAS Build,你可以将此页面用作 创建你的第一个版本 的配套页面。

¥This page covers practical differences you should know when migrating your Expo managed app from expo build (also known as classic builds) to EAS Build. If this is your first time using EAS Build, you can use this page as a companion to Create your first build.

EAS Build 的目标之一是尽可能轻松地从 expo build 迁移。例如,你的应用签名凭据将自动重新使用,Expo SDK 和你的 应用配置 (app.json) 配置将与以前一样工作。但是,两个构建过程之间的一些差异需要额外的配置或小的代码更改。

¥One of the goals of EAS Build is to make it as easy as possible to migrate from expo build. For example, your app signing credentials will be automatically re-used, and the Expo SDK and your app config (app.json) configuration will all work the same as before. However, some differences between the two build processes require additional configuration or small code changes.

了解经典版本和 EAS 版本之间的差异

¥Understand the differences between classic and EAS builds

使用 EAS Build 构建的应用与其他 CI 服务一样 — 整个项目安全上传到云端,然后由构建服务器下载,安装依赖并运行构建。

¥Apps built with EAS Build are like other CI services — the entire project is uploaded securely to the cloud, then downloaded by a build server, the dependencies are installed, and the build is run.

在经典构建中,应用的 JavaScript 是在开发计算机上构建的(当你在构建之前发布应用包时),但现在应用的 JavaScript 是在 EAS Build 构建器上构建的。构建应用所需的一切 必须包含在要上传的项目中

¥With classic builds, your app's JavaScript is built on your development machine (when you publish the app bundle before building), but now the app's JavaScript is built on an EAS Build builder. Everything required to build your app must be included in the project to be uploaded.

要了解有关 EAS Build 如何成功构建项目的更多信息,请参阅 安卓iOS 系统 构建流程。

¥To learn more about how EAS Build creates a successful build of your project, see Android and iOS build processes.

Git 中忽略的文件不会上传

¥Files ignored in Git are not uploaded

.gitignore 文件中忽略的任何文件或目录都不会上传。例如,当 Google Services(google-services.json 或 GoogleService-Info.plist)文件添加到 .gitignore 中时,它们将被忽略。对于像这样的文件或项目中成功构建所需的任何其他文件,你可以将其从 .gitignore 中删除并提交,或者 使用 Base64 进行编码并将其存储在 EAS Secrets 中,然后在构建时进行解码

¥Any file or directory that is ignored in the .gitignore file will not be uploaded. For example, when Google Services (google-services.json or GoogleService-Info.plist) files are added in .gitignore, they are ignored. For a file like this or any other in your project that is necessary for a successful build, you can either remove it from .gitignore and commit it or encode with base64 and store it in EAS Secrets, then decode at build time.

仅 package.json 中的库包含在应用中

¥Libraries only in package.json are included in the app

这通常会导致应用大小大幅减小。使用 EAS Build 构建的托管应用可以是 比使用 expo build 构建的相同应用小 10 倍

¥This often results in massive reductions in app size. Managed apps built with EAS Build can be 10x smaller than the same app built with expo build.

expo build 迁移时的权衡是,你在发布更新时需要小心,以避免发布不兼容的 JavaScript 包,因为构建包含一些无法通过更新更改的原生代码。但是,你可以设置并使用 运行时版本属性 来保证构建的原生代码和更新之间的兼容性,以避免这种权衡。

¥The tradeoff when migrating from expo build is that you need to be careful when publishing updates to avoid publishing an incompatible JavaScript bundle because the build contains some native code that cannot be changed with an update. However, you can set up and use runtime version property that guarantees compatibility between a build's native code and an update to avoid this tradeoff.

需要为 EAS 构建定义应用使用的环境变量

¥Environment variables used by your app need to be defined for EAS Build

如果你在 app.config.js 或应用源代码中使用环境变量(例如,使用 babel-plugin-inline-dotenv),则需要为构建配置文件或在密钥中定义这些变量,如 环境变量和秘密 中所述。

¥If you use environment variables in your app.config.js or in your app source code (for example, with babel-plugin-inline-dotenv), you need to define these variables for your build profiles or in secrets, as described in Environment variables and secrets.

SDK 48 及更低版本不支持 package.json 中的自定义 "main" 入口点

¥Custom "main" entry point in package.json is not supported for SDK 48 and below

如果你的应用使用 SDK 48 或更低版本并且依赖于自定义 "main" 入口点,请将其从 package.json 中删除。然后,在项目的根目录下创建 index.js 并使用 registerRootComponent 注册你的根组件。

¥If your app uses SDK 48 or below and depends on a custom "main" entry point, remove it from package.json. Then, create index.js at the root of your project and use registerRootComponent to register your root component.

例如,如果你的应用的根组件位于 src/App.tsx 中,则 index.js 应如下所示:

¥For example, if your app's root component lives in src/App.tsx, the index.js should look like the following:

index.js
import { registerRootComponent } from 'expo';
import App from './src/App';

registerRootComponent(App);

注意:对于 SDK 49 及更高版本,请参阅 如何重命名主应用文件

¥Note: For SDK 49 and above, see how to rename the main app file.

不支持 --config 标志

¥The --config flag is not supported

如果你使用 expo build:[ios|android] --config app.production.json 切换项目使用的应用配置文件,则必须迁移到替代方案,因为 EAS Build 不支持此操作。欲了解更多信息,请参阅 从 Expo CLI 中迁移出 --config 标志

¥If you are using expo build:[ios|android] --config app.production.json to switch app configuration files used by your project, you'll have to migrate to an alternative since this is not supported in EAS Build. For more information, see Migrating away from the --config flag in Expo CLI.

需要额外配置才能访问私有 npm 包

¥Additional configuration is required to access private npm packages

有关如何在 EAS Build 上安全存储 NPM_TOKEN 的更多信息,请参阅 使用私有 npm 包

¥For more information on how to securely store NPM_TOKEN on EAS Build, see Using private npm packages.

源代码中引用的所有资源均已打包

¥All assets referenced in source code are bundled

对于经典版本,assetBundlePatterns 有两个用途:

¥With classic builds, assetBundlePatterns serves two purposes:

  1. 与给定模式匹配的资源在构建时打包在二进制文件中。

    ¥Assets that match the given patterns are bundled in the binary at build time.

  2. 与给定模式匹配的资源决定了 "atomic" 更新包的内容。在认为更新准备好启动之前,需要下载与 assetBundlePatterns 匹配的所有文件。

    ¥Assets that match the given patterns determine the contents of an "atomic" update bundle. All files matching assetBundlePatterns need to be downloaded before an update is considered ready to launch.

只有第二个目的适用于 EAS Build 系统。应用源代码中引用的所有资源都会在构建时打包到应用二进制文件中,与默认的 React Native 应用相同 - assetBundlePatterns 不用于确定要在二进制文件中打包哪些资源。它仅用于更新包。

¥Only the second purpose applies to the EAS Build system. All assets referenced in your app source code are bundled into your app binary at build time, the same as in a default React Native app — assetBundlePatterns is not used to determine what assets to bundle in the binary. It's only used for update bundles.

Constants.manifest 已弃用

¥Constants.manifest is deprecated

如果你使用 Constants.manifest 访问字段,则应切换到 Constants.expoConfig 以从 expo-constants 库访问它们。

¥If you are using Constants.manifest to access fields, you should switch to Constants.expoConfig to access them from the expo-constants library.

应用配置(app.json/app.config.js)

¥App config (app.json/app.config.js)

userInterfaceStyle 取决于正在安装的 expo-system-ui

¥userInterfaceStyle depends on expo-system-ui being installed

在 Android 上,只有安装了 expo-system-ui,才能在 app.json 中选择带有 userInterfaceStyle(或 android.userInterfaceStyle)的原生外观模式。这是因为 expo-system-ui 启用了基于 app.json 原生锁定界面。

¥On Android, selecting a native appearance mode with userInterfaceStyle (or android.userInterfaceStyle) in the app.json will only work if expo-system-ui is installed. This is because expo-system-ui enables locking the interface natively based on the app.json.

运行以下命令安装 expo-system-ui 库:

¥Run the following command to install the expo-system-ui library:

Terminal
npx expo install expo-system-ui

androidNavigationBar 取决于正在安装的 expo-navigation-bar

¥androidNavigationBar depends on expo-navigation-bar being installed

在 Android 上,只有在项目中安装了 expo-navigation-bar 时,才能在 app.json 中选择与 androidNavigationBar.visible 的导航栏交互行为。

¥On Android, selecting the navigation bar interaction behavior with androidNavigationBar.visible in the app.json will only work if expo-navigation-bar is installed in the project.

另外,由于底层 Android API 已被弃用,因此请考虑迁移此属性。有关详细信息,请参阅 迁移指南

¥Also, consider migrating away from this property as the underlying Android APIs are deprecated. For more information, see the migration guide.

运行以下命令安装 expo-navigation-bar 库:

¥Run the following command to install the expo-navigation-bar library:

Terminal
npx expo install expo-navigation-bar

splash 取决于正在安装的 expo-splash-screen

¥splash depends on expo-splash-screen being installed

在 Android 上,仅当项目中安装了 expo-splash-screen 时,在 app.json 中使用 splash(或 android.splash)配置 resizeMode 或启动画面的定位才有效。

¥On Android, configuring the resizeMode or positioning of the splash screen with splash (or android.splash) in the app.json will only work if expo-splash-screen is installed in the project.

运行以下命令安装 expo-splash-screen 库:

¥Run the following command to install the expo-splash-screen library:

Terminal
npx expo install expo-splash-screen

backgroundColor 取决于正在安装的 expo-system-ui

¥backgroundColor depends on expo-system-ui being installed

在 iOS 上,只有在安装了 expo-system-ui 的情况下,才能在 app.json 中使用 ios.backgroundColor 选择根背景颜色(对于原生模态和翻转方向)。这是因为 expo-system-ui 包含用于基于 app.json 原生设置颜色的代码。

¥On iOS, selecting the root background color (for native modals and flipping orientations) with ios.backgroundColor in the app.json will only work if expo-system-ui is installed. This is because expo-system-ui includes code for setting the color natively based on the app.json.

运行以下命令安装 expo-system-ui 库:

¥Run the following command to install the expo-system-ui library:

Terminal
npx expo install expo-system-ui

更新

¥Updates

如果你从 expo build 迁移并使用 expo publish 更新你的应用,则你正在使用 经典更新。迁移到 EAS Build 后,你还可以利用我们全新和改进的更新服务 EAS 更新。有关如何将项目迁移到 EAS 更新的详细信息,请参阅 从经典更新迁移到 EAS 更新

¥If you are migrating from expo build and using expo publish to update your app, you are using Classic Updates. Once you migrate to EAS Build, you can also take advantage of our new-and-improved updates service, EAS Update. For in-depth information on how to migrate your project to EAS Update, see Migrating from Classic updates to EAS Update.

构建前不再自动发布

¥No more automatic publishing before building

对于经典构建,默认行为是在运行构建之前自动发布带有经典更新的应用作为更新。这产生了一些意想不到的后果。例如,有时开发者会运行构建,并惊讶地发现他们现有的应用已更新作为副作用。

¥With classic builds, the default behavior was to automatically publish your app with Classic Updates as an update before running a build. This had some unintended consequences. For example, sometimes developers would run a build and be surprised to learn that their existing app was updated as a side effect.

对于 EAS Build,经典更新的 expo publish 命令不会作为构建过程的一部分运行。相反,JavaScript 包是在构建时在 EAS Build 上本地生成的,并直接嵌入到应用中。

¥With EAS Build, the Classic Update's expo publish command is not run as part of the build process. Instead, the JavaScript bundle is generated locally on EAS Build at build time and directly embedded in the app.

由于我们不再在构建时发布,因此 app.json 中的 postPublish 钩子将不会在构建时执行。如果你使用 Sentry,请将 sentry-expo 库更新到最新版本,并按照 使用 Sentry 中更新的说明进行操作。如果你有其他自定义 postPublish 钩子,则可以遵循 sentry-expo 中使用的相同方法来支持 postPublish 钩子类型的行为。

¥Since we no longer publish at build time, postPublish hooks in app.json will not be executed on the build. If you use Sentry, update the sentry-expo library to the latest version and follow the updated instructions in Using Sentry. If you have other custom postPublish hooks, you can follow the same approach used in sentry-expo to support postPublish hook type of behavior.

Constants.manifest 不包含更新相关字段

¥Constants.manifest does not include update related fields

由于我们不再在构建之前发布应用,因此在应用下载更新之前,没有可用的更新清单。通常,这意味着首次启动应用时,你将没有某些可用字段。

¥Since we no longer publish the app before builds, no update manifest is available until the app downloads an update. Usually, this means that for the first launch of the app, you won't have some fields available.

如果你使用的是 Constants.manifest.channel,则应从 expo-updates 库切换到 Updates.releaseChannel(用于经典更新)或 Updates.channel(用于 EAS 更新)。

¥If you are using Constants.manifest.channel, you should switch to Updates.releaseChannel (for Classic Updates) or Updates.channel (for EAS Update) from the expo-updates library.

在生成的独立应用中,Constants.appOwnership 将是 null

¥Constants.appOwnership will be null in the resulting standalone app

EAS Build 生成的应用中不再存在 Constants.appOwnership 字段。如果你之前使用类似于 const isStandaloneApp = Constants.appOwnership === "standalone" 的环境进行测试,请切换到使用 Constants.executionEnvironment

¥The Constants.appOwnership field no longer exists in apps produced by EAS Build. If you were previously testing the environment with something similar to const isStandaloneApp = Constants.appOwnership === "standalone", switch to use Constants.executionEnvironment.

大仓可能需要额外的设置

¥Monorepos may require additional setup

经典构建不知道你的存储库设置。你可以使用 monorepo 或 birepo 或 trirepo,服务完全无关紧要。只要你可以发布打包包,就足够了。

¥Classic builds had no knowledge of your repository setup. You could use a monorepo or birepo or trirepo, the service was entirely indifferent. As long as you could publish a bundle, that's all that was needed.

EAS Build 需要能够安装所有项目依赖以在构建器内设置开发环境。在某些情况下,这将需要一些额外的配置。有关详细信息,请参阅 如何使用 monorepo 设置 EAS Build与 Monorepos 合作

¥EAS Build needs to be able to install all of your project dependencies to set up the development environment inside a builder. In some cases, that will require some additional configuration. For more information, see How to set up EAS Build with a monorepo and Working with Monorepos.

各种各样的

¥Miscellaneous

EAS 构建不支持 expo-branch

¥expo-branch is not supported on EAS Build

从你的应用中删除 expo-branch 以使用 EAS Build 进行构建。你可以使用官方的 react-native-branch@config-plugins/react-native-branch

¥Remove expo-branch from your app to build with EAS Build. You can use the official react-native-branch with @config-plugins/react-native-branch.

如果你使用 AWS Amplify,则需要 amazon-cognito-identity-js

¥amazon-cognito-identity-js is required if you use AWS Amplify

在使用 expo build 构建的项目中,每个应用中都包含 AWS Amplify 所需的原生原语。EAS Build 中并非如此,你必须安装 amazon-cognito-identity-js 才能链接 AWS Amplify 库所依赖的原生模块。

¥In projects built with expo build the native primitives required by AWS Amplify are included in every app. This is not the case in EAS Build, and you must install amazon-cognito-identity-js to link the native module depended on by AWS Amplify libraries.

默认不支持动画 WebP

¥Animated WebP is not supported by default

大多数应用不使用此格式,并且对其支持会导致最终应用大小增加约 3.4 MB,因此默认情况下会忽略它。你可以通过使用自定义 配置插件expo.webp.animated=false 切换到 expo.webp.animated=true 来更新 android/gradle.properties 来启用它。有关如何实现配置插件的更多信息,来自社区的 看这个例子

¥Most apps do not use this format and support for it adds around 3.4 MB to the final app size, so it is omitted by default. You can enable it by switching expo.webp.animated=false to expo.webp.animated=true using a custom Config plugin to update android/gradle.properties. For more information on how to implement the config plugin, see this example from the community.

Metro.config.js 必须从 expo/metro-config 导出整个默认配置

¥metro.config.js must export the entire default config from expo/metro-config

expo/metro-config@expo/metro-config 的版本化重新导出。

¥expo/metro-config is a versioned re-export of @expo/metro-config.

以前,使用经典构建时,你的 Metro.config.js 可能类似于:

¥Previously, with classic builds, your metro.config.js might have looked something like:

metro.config.js
const { getDefaultConfig } = require('expo/metro-config');

const defaultConfig = getDefaultConfig(__dirname);

module.exports = {
  resolver: {
    assetExts: [...defaultConfig.resolver.assetExts, 'db'],
  },
};

在上面的示例中,你仅导出部分默认配置。但是,EAS Build 需要完整的配置。为此,你必须直接修改 defaultConfig,然后返回结果对象,如下所示:

¥In the example above, you're only exporting part of the default config. However, EAS Build requires the full config. To do that, you have to modify defaultConfig directly, and then return the resulting object as shown below:

metro.config.js
const { getDefaultConfig } = require('expo/metro-config');

const defaultConfig = getDefaultConfig(__dirname);

defaultConfig.resolver.assetExts.push('db');

module.exports = defaultConfig;

如果你没有正确设置 Metro.config.js 文件,你的资源可能无法在发布版本中加载。欲了解更多信息,请参阅 定制 Metro

¥If you don't set up your metro.config.js file properly, your assets could fail to load in release builds. For more information, see Customizing Metro.

解决构建错误和崩溃问题

¥Troubleshooting build errors and crashes

欲了解更多信息,请参阅 排除运行时和构建错误以及崩溃

¥For more information, see troubleshooting runtime and build errors, and crashes.

迁移时遇到困难?加入我们的 Discord and Forums 上的 #eas 通道并让我们知道。
Expo 中文网 - 粤ICP备13048890号