EAS Update 的工作原理
编辑页面
EAS Update 工作原理的概念性概览。
For the complete documentation index, see llms.txt. Use this Use this file to discover all available pages.
EAS Update 是一项服务,允许你在准备下一次应用商店发布时,立即向用户推送小型 bug 修复和更新。要让更新可供某些构建使用,需要在构建和更新之间建立链接。
为了创建构建和更新之间的链接,我们必须确保该更新可以在该构建上运行。我们还希望确保能够创建一个部署流程,以便在准备就绪时将某些更新暴露给某些构建。
为了说明构建和更新如何交互,请看下面的图:
构建可以被看作由两层组成:一层是内置到应用二进制文件中的原生层,另一层是可与其他兼容更新互换的更新层。这种分离使我们能够向构建发布 bug 修复,只要包含该 bug 修复的更新可以在构建内的原生层上运行即可。
为了确保更新可以在构建上运行,我们必须设置各种属性,以便确保我们的构建能够运行我们的更新。这从我们创建项目的构建时开始。
概念概览
分发构建
当我们准备创建 Expo 项目的构建时,可以运行 eas build 来创建构建。在构建过程中,系统会在构建中包含一些对更新很重要的属性。它们是:
- Channel: 渠道是我们可以赋予多个构建的一个名称,用于轻松识别它们。它在
eas.json中定义。例如,我们可能有一个 Android 构建和一个 iOS 构建都使用名为 "production" 的渠道,同时还有另一对构建使用名为 "staging" 的渠道。然后,我们可以将使用 "production" 渠道的构建分发到公开应用商店,而将 "staging" 构建保留在 Play Store Internal Track 和 TestFlight 上。 之后,当我们发布更新时,可以先让 "staging" 渠道的构建获得该更新;等我们测试完更改后,再让 "production" 渠道的构建获得该更新。 - Runtime version: 运行时版本描述的是由原生代码层定义的 JS-native 接口,该原生代码层负责运行我们应用的更新层。它在项目的 app config 中定义。每当我们对原生代码做出会改变应用 JS-native 接口的更改时,就需要更新运行时版本。了解更多。
- Platform: 每个构建都有一个平台,例如 "Android" 或 "iOS"。
如果我们使用名为 "staging" 和 "production" 的渠道创建两组构建,那么我们可以把构建分发到四个不同的位置:
这个图只是一个示例,展示你可以如何创建构建并命名它们的渠道,以及可以把这些构建放到哪里。最终,渠道名称如何设置、这些构建放到哪里,取决于你自己。
发布更新
一旦我们创建了构建,就可以通过发布更新来更改项目的更新层。比如,我们可以修改 App.js 中的一些文本,然后把这个更改作为更新发布出去。
要发布更新,我们可以运行 eas update --auto。这个命令会在项目的 dist 目录中创建一个本地更新包。一旦更新包创建完成,它就会把这个包上传到 EAS 服务器,并存入一个名为 branch 的数据库对象中。一个 branch 有一个名称,并包含一个更新列表,其中最新的更新是该 branch 上的活动更新。我们可以把 EAS branch 想象成 Git branch。就像 Git branch 包含一组提交一样,EAS branch 包含一组更新。
匹配更新和构建
和构建一样,branch 上的每个更新都包含目标运行时版本和目标平台。借助这些字段,我们可以通过一种称为 update policy 的机制,确保某个更新能够在构建上运行。EAS 的更新策略如下:
- 构建的平台和更新的目标平台必须完全匹配。
- 构建的运行时版本和更新的目标运行时版本必须完全匹配。
- 一个渠道可以链接到任意 branch。默认情况下,渠道会链接到同名的 branch。
重点看最后一点。每个构建都有一个渠道,而我们作为开发者,可以把这个渠道链接到任意 branch,这样该 branch 上最新且兼容的更新就会对该链接渠道可用。 为了简化这种链接,默认情况下我们会自动将渠道链接到同名的 branch。例如,如果我们创建了渠道名为 "production" 的构建,我们可以把更新发布到名为 "production" 的 branch,而我们的构建就会从名为 "production" 的 branch 获取更新,尽管我们并没有手动链接任何内容。
如果你有一个部署流程,其中存在多个一致的 Git 和 EAS branch,那么这种默认链接方式就非常适用。 例如,我们可以同时在 Git 和 EAS 上都有一个 "production" branch 和一个 "staging" branch。结合 GitHub Action,我们可以做到每当有 commit 推送到 "staging" Git branch 时,就将其发布到 "staging" EAS Update branch,这样该更新就会应用到所有使用 "staging" 渠道的构建上。 当我们在 staging 构建上测试完更改后,就可以把 "staging" Git branch 合并到 "production" Git branch,这会在 "production" EAS Update branch 上发布一个更新。最终,"production" EAS Update branch 上的最新更新就会应用到使用 "production" 渠道的构建上。
这个流程使我们可以先推送到 GitHub,然后在没有其他干预的情况下看到我们的构建自动更新。
虽然这个流程对许多开发者都有效,但由于我们可以更改渠道和 branch 之间的链接,因此还能实现另一种流程。假设我们将 branch 命名为 "version-1.0"、"version-2.0" 和 "version-3.0"。我们可以将 "version-1.0" EAS Update branch 链接到 "production" 渠道,使其对我们的 "production" 构建可用。 我们还可以将 "version-2.0" EAS Update branch 链接到 "staging" 渠道,使其对测试人员可用。最后,我们可以创建一个 "version-3.0" EAS Update branch,它目前还没有链接到任何构建,只有开发者正在使用一个开发构建进行测试。
一旦测试人员确认 "version-2.0" EAS Update branch 上的更新已准备好投入生产,我们就可以更新 "production" 渠道,使其链接到 "version-2.0" branch。为此,我们可以运行:
- eas channel:edit production --branch version-2.0在这种状态下,我们就可以开始测试 "version-3.0" EAS Update branch 了。与上一步类似,我们可以使用以下命令将 "staging" 渠道链接到 "version-3.0" EAS Update branch:
- eas channel:edit staging --branch version-3.0实践概览
现在我们已经熟悉了 EAS Update 的核心概念,下面来讲讲这个过程是如何发生的。
当一个包含 expo-updates 的 Expo 项目被构建时,所包含的原生 Android 和 iOS 代码负责管理、获取、解析和验证更新。
库在检查更新以及下载更新时,这些行为都是可配置的。默认情况下,库会在打开时检查更新。如果发现比当前正在运行的更新更高版本的更新,它会下载并运行较新的更新。如果库没有找到更新版本,则会运行已下载的最新更新;如果没有任何已下载更新,则回退到构建时嵌入到应用中的更新。
expo-updates 会分两个阶段下载更新。首先,它会下载最新的更新 manifest,其中包含更新的信息,包括运行该更新所需的资源列表(图片、JavaScript bundle、字体文件等)。
其次,库会下载 manifest 中指定的、此前从未下载过的资源。例如,如果某个更新包含一张新图片,那么库会先下载这张新图片资源,然后再运行该更新。为了帮助最终用户快速且可靠地获得更新,更新应尽可能保持小体积。
如果库能够在 fallbackToCacheTimeout 设置之前下载完 manifest(第 1 阶段)和所有必需资源(第 2 阶段),那么新更新会在启动时立即运行。如果库无法在 fallbackToCacheTimeout 时间内获取 manifest 和资源,它会继续在后台下载新更新,并在下次启动时运行它。
总结
借助 EAS Update,我们可以快速向用户推送小型、关键的 bug 修复,并为用户提供尽可能好的体验。这通过构建的运行时版本、平台和渠道来实现。借助这三个约束,我们可以让更新对特定的一组构建可用。这使我们能够在进入生产环境之前,在部署流程中先测试更改。 根据我们如何设置部署流程,我们可以优化速度,也可以将部署优化得尽可能安全、尽可能没有 bug。部署方式非常多样,几乎可以匹配你偏好的任何发布流程。