EAS 更新的工作原理

EAS 更新工作原理的概念性概述。


EAS 更新是一项服务,允许你在开发下一个应用商店版本时,立即向用户提供小的错误修复和更新。将更新提供给构建版本涉及在构建版本和更新之间创建一个链接。

🌐 EAS Update is a service that allows you to deliver small bug fixes and updates to your users immediately as you work on your next app store release. Making an update available to builds involves creating a link between a build and an update.

要在构建和更新之间创建链接,我们必须确保更新可以在该构建上运行。我们还希望确保能够创建部署流程,以便在准备就绪时将某些更新发布到特定的构建上。

🌐 To create a link between a build and an update, we have to make sure the update can run on the build. We also want to make sure we can create a deployment process so that we can expose certain updates to certain builds when we're ready.

为了说明构建和更新如何交互,请看下图:

🌐 To illustrate how builds and updates interact, take a look at the following diagram:

构建可以被视为两层:内置在应用二进制文件中的本地层,以及可以与其他兼容更新互换的更新层。这种分离使我们能够向构建发布错误修复,只要包含错误修复的更新能够在构建内的本地层上运行。

🌐 Builds can be thought of as two layers: a native layer that's built into the app's binary, and an update layer, that is swappable with other compatible updates. This separation allows us to ship bug fixes to builds as long as the update with the bug fix can run on the native layer inside the build.

为了确保更新可以在构建上运行,我们必须设置各种属性,以确保我们的构建可以运行更新。这一过程从我们创建项目构建时就开始了。

🌐 To make sure the update can run on the build, we have to set a variety of properties so that we can be sure our builds can run our updates. This starts when we create a build of our project.

概念概述

🌐 Conceptual overview

分发构建

🌐 Distributing builds

当我们准备好创建我们的 Expo 项目的构建时,可以运行 eas build 来创建构建。在构建过程中,该过程会在构建中包含一些对于更新很重要的属性。它们是:

🌐 When we're ready to create a build of our Expo project, we can run eas build to create a build. During the build, the process will include some properties inside the build that are important for updates. They are:

  • 渠道: 渠道是我们可以为多个构建指定的名称,用于轻松识别它们。它在 eas.json 中定义。例如,我们可能有一个 Android 和 iOS 构建,它们的渠道名为“production”,而我们有另一对构建的渠道名为“staging”。然后,我们可以将“production”渠道的构建发布到公共应用商店,同时将“staging”渠道的构建保留在 Play 商店内部测试通道和 TestFlight 上。稍后当我们发布更新时,可以先让“staging”渠道的构建获取更新;在测试完更改后,再将更新提供给“production”渠道的构建。
  • 运行时版本: 运行时版本描述了由本地代码层定义的 JS 本地接口,该接口运行我们应用的更新层。它在项目的 应用配置 中定义。每当我们对本地代码进行更改,从而改变应用的 JS 本地接口时,就需要更新运行时版本。了解更多
  • 平台: 每个版本都有一个平台,例如 “Android” 或 “iOS”。

如果我们制作了两组构建,渠道分别命名为“staging”和“production”,我们可以将构建分发到四个不同的地方:

🌐 If we made two sets of builds with the channels named "staging" and "production", we could distribute builds to four different places:

此图只是一个示例,展示了你如何创建构建及命名其通道,以及你可以将这些构建放置在何处。最终由你决定使用哪些通道名称以及将这些构建放在何处。

🌐 This diagram is just an example of how you could create builds and name their channels, and where you could put those builds. Ultimately it's up to you which channel names you set and where you put those builds.

发布更新

🌐 Publishing an update

一旦我们创建了构建,我们可以通过发布更新来更改项目的更新层。例如,我们可以更改 App.js 中的一些文本,然后将该更改作为更新发布。

🌐 Once we've created builds, we can change the update layer of our project by publishing an update. For example, we could change some text inside App.js, then we could publish that change as an update.

要发布更新,我们可以运行 eas update --auto。此命令将在我们项目的 dist 目录中创建本地更新包。创建更新包后,它会将该包上传到 EAS 服务器,在一个名为 branch 的数据库对象中存储。一个分支有一个名称,并包含更新列表,其中最新的更新是该分支上的活动更新。我们可以把 EAS 分支想象成 Git 分支。就像 Git 分支包含提交列表一样,EAS 分支包含更新列表。

🌐 To publish an update, we can run eas update --auto. This command will create a local update bundle inside the dist directory in our project. Once it's created an update bundle, it will upload that bundle to EAS servers, in a database object named a branch. A branch has a name and contains a list of updates, where the most recent update is the active update on the branch. We can think of EAS branches just like Git branches. Just as Git branches contain a list of commits, EAS branches contain a list of updates.

匹配更新和构建

🌐 Matching updates and builds

与构建一样,分支上的每次更新都包括目标运行时版本和目标平台。通过这些字段,我们可以确保更新能够在具有所谓 update policy 的构建上运行。EAS 的更新策略如下:

🌐 Like builds, every update on a branch includes a target runtime version and target platform. With these fields, we can make sure that an update will run on a build with something called an update policy. EAS' update policy is as follows:

  • 构建的平台和更新的目标平台必须完全匹配。
  • 构建的运行时版本和更新的目标运行时版本必须完全匹配。
  • 一个渠道可以连接到任何分支。默认情况下,渠道会连接到同名的分支。

让我们关注最后一点。每个构建都有一个通道,而作为开发者,我们可以将该通道链接到任何分支,这将使该通道上最近兼容的更新可在该分支上使用。为了简化这种链接,默认情况下我们会自动将通道链接到同名的分支。例如,如果我们创建了名为“production”的通道构建,我们可以将更新发布到名为“production”的分支,构建将从名为“production”的分支获取更新,即使我们没有手动链接任何内容。

🌐 Let's focus on that last point. Every build has a channel, and we, as developers, can link that channel to any branch, which will make its most recent compatible update available on the branch to the linked channel. To simplify this linking, by default we auto-link channels to branches of the same name. For instance, if we created builds with the channel named "production", we could publish updates to a branch named "production" and our builds would get the updates from the branch named "production", even though we did not manually link anything.

如果你的部署流程中有多个一致的 Git 和 EAS 分支,这种默认的关联方式效果很好。例如,我们可以有一个“生产”分支和一个“预发布”分支,它们都存在于 Git 和 EAS 上。配合 GitHub Action,我们可以设置为每次将提交推送到“预发布” Git 分支时,就发布到“预发布” EAS 更新分支,这样该更新就会应用到所有使用“预发布”通道的构建中。一旦我们在预发布构建上测试了更改,就可以将“预发布” Git 分支合并到“生产” Git 分支,这将会在“生产” EAS 更新分支上发布更新。最后,“生产” EAS 更新分支上的最新更新将应用到使用“生产”通道的构建中。

🌐 This default linking works great if you have a deployment process where you have multiple consistent Git and EAS branches. For instance, we could have a "production" branch and a "staging" branch, both on Git and on EAS. Paired with a GitHub Action, we could make it so that every time a commit is pushed to the "staging" Git branch, we publish to the "staging" EAS Update branch, which would make that update apply to all our builds with the "staging" channel. Once we tested changes on the staging builds, then we could merge the "staging" Git branch into the "production" Git branch, which would publish an update on the "production" EAS Update branch. Finally, the latest update on the "production" EAS Update branch would apply to builds with the "production" channel.

这个流程使得我们可以推送到 GitHub,然后查看我们的构建更新,而无需任何其他干预。

🌐 This flow makes it so that we can push to GitHub, then see our builds update without any other interventions.

虽然这种流程适用于许多开发者,但由于我们可以更改通道与分支之间的链接,因此还可以实现另一种流程。假设我们将分支命名为“version-1.0”、“version-2.0”和“version-3.0”。我们可以将“version-1.0” EAS Update 分支链接到“production”通道,从而使其可用于我们的“生产”构建。 我们还可以将“version-2.0” EAS Update 分支链接到“staging”通道,使其可供测试人员使用。最后,我们可以创建一个“version-3.0” EAS Update 分支,目前还不链接到任何构建,仅供开发者使用开发构建进行测试。

🌐 While this flow works for many developers, there's another flow we can accomplish since we have the ability to change the link between channels and branches. Imagine we name our branches like "version-1.0", "version-2.0", and "version-3.0". We could link the "version-1.0" EAS Update branch to the "production" channel, to make it available to our "production" builds. We could also link the "version-2.0" EAS Update branch to the "staging" channel to make it available to testers. Finally, we could make a "version-3.0" EAS Update branch that is not linked to any builds yet, that only developers are testing with a development build.

一旦测试人员确认“version-2.0” EAS 更新分支上的更新已准备好投入生产,我们就可以更新“production”通道,使其与“version-2.0”分支关联。为此,我们可以运行:

🌐 Once testers verify that the update on the "version-2.0" EAS Update branch is ready for production, we can update the "production" channel so that it's linked to the "version-2.0" branch. To accomplish this, we could run:

Terminal
eas channel:edit production --branch version-2.0

在这个状态之后,我们将准备好开始测试“version-3.0” EAS 更新分支。与上一步类似,我们可以使用以下命令将“staging”通道链接到“version-3.0” EAS 更新分支:

🌐 After this state, we'd be ready to start testing the "version-3.0" EAS Update branch. Similarly to the last step, we could link the "staging" channel to the "version-3.0" EAS Update branch with this command:

Terminal
eas channel:edit staging --branch version-3.0

实用概述

🌐 Practical overview

现在我们已经熟悉了 EAS 更新的核心概念,我们来谈谈这个过程是如何发生的。

🌐 Now that we're familiar with the core concepts of EAS Update, let's talk about how this process occurs.

当构建包含 expo-updates 的 Expo 项目时,所包含的原生 Android 和 iOS 代码负责管理、获取、解析和验证更新。

🌐 When an Expo project that includes expo-updates is built the included native Android and iOS code is responsible for managing, fetching, parsing, and validating updates.

当库检查更新或下载更新时,它们是可配置的。默认情况下,当库被打开时会检查更新。如果发现比当前运行版本更新的版本,它将下载并运行该更新。如果库没有找到更新的版本,它将运行已下载的最新更新,如果没有下载过任何更新,则会回退到构建时嵌入在应用中的更新版本。

🌐 When the library checks for updates and when it downloads them, they are configurable. By default, the library will check for an update when it is opened. If an update newer than the currently running update is found, it will download and run the newer update. If the library does not find a newer update, it will instead run the newest downloaded update, falling back to the update that was embedded inside the app at build time if none have been downloaded.

expo-updates 以两个阶段下载更新。首先,它下载最新的更新 清单(manifest),其中包含有关更新的信息,包括运行更新所需的资源列表(图片、JavaScript 包、字体文件等)。 其次,该库会下载清单中指定但之前更新中尚未下载的资源。例如,如果一个更新包含一个新图片,该库将在运行更新之前先下载该新图片资源。为了帮助终端用户快速且可靠地获取更新,更新文件应尽量保持小体积。

如果库能够在 fallbackToCacheTimeout 设置之前下载清单(阶段 1)和所有所需资源(阶段 2),那么新更新将在启动时立即运行。如果库无法在 fallbackToCacheTimeout 内获取清单和资源,它将继续在后台下载新更新,并将在下次启动时运行。

🌐 If the library is able to download the manifest (phase 1) and all the required assets (phase 2) before the fallbackToCacheTimeout setting, then the new update will run immediately upon launch. If the library is not able to fetch the manifest and assets within fallbackToCacheTimeout, it will continue to download the new update in the background and will run it upon the next launch.

包起来

🌐 Wrap up

通过 EAS 更新,我们可以快速向用户提供小型、关键的错误修复,并为用户提供最佳体验。这是通过构建的运行时版本、平台和渠道来设置的。通过这三个限制条件,我们可以使更新可用于特定的一组构建。这使我们能够在部署过程进入生产环境之前测试我们的更改。 根据我们如何设置部署过程,我们可以优化速度。我们还可以优化部署,使其尽可能安全且无错误。部署的可能性非常广泛,几乎可以匹配你喜欢的任何发布流程。

🌐 With EAS Update, we can quickly deliver small, critical bug fixes to our users and give users the best experience possible. This is set up with a build's runtime version, platform, and channel. With these three constraints, we can make an update available to a specific group of builds. This allows us to test our changes before going to production within a deployment process. Depending on how we set up our deployment process, we can optimize for speed. We can also optimize our deployments to be as safe and bug-free as possible. The deployment possibilities are vast and can match nearly any release process you prefer.