了解不同的运行时版本策略以及它们如何适合你的项目。
运行时版本是保证构建的原生代码和更新之间的兼容性的属性。当项目被制作成构建时,构建将包含一些无法通过更新更改的原生代码。因此,更新必须与构建的原生代码兼容才能在构建上运行。
¥Runtime versions are a property that guarantees compatibility between a build's native code and an update. When a project is made into a build, the build will contain some native code that cannot be changed with an update. Therefore, an update must be compatible with a build's native code to run on the build.
为了说明构建和更新如何交互,请看下图:
¥To illustrate how builds and updates interact, take a look at the following diagram:
构建可以被认为是两层:内置于应用二进制文件中的原生层和可与其他兼容更新交换的更新层。这种分离允许我们将错误修复发送到构建,只要错误修复的更新可以在构建内的原生层上运行。"runtimeVersion"
属性使我们能够保证更新与特定构建的原生代码兼容。
¥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. The "runtimeVersion"
property allows us to guarantee that an update is compatible with a specific build's native code.
由于更新必须与构建的原生代码兼容,因此每次更新原生代码时,我们都需要在发布更新之前进行新的构建。一些开发者仅在升级到新的 Expo SDK 时更新原生代码,而其他开发者可能会在构建之间或以其他时间间隔升级原生代码。以下是对可能适合你的项目的不同情况和配置的说明。
¥Since updates must be compatible with a build's native code, any time native code is updated, we're required to make a new build before publishing an update. Some developers only update native code when upgrading to a new Expo SDK, while others may upgrade native code between builds or at other intervals. Below is an explanation of different situations and configurations that may suite your project.
"runtimeVersion"
¥Setting "runtimeVersion"
为了在构建和更新之间更轻松地管理 "runtimeVersion"
属性,我们创建了运行时版本策略,该策略将根据应用配置 (app.json/app.config.js) 内的其他字段自动更新。如果这些策略与项目的开发流程不匹配,还可以选择手动设置 "runtimeVersion"
。
¥To make managing the "runtimeVersion"
property easier between builds and updates, we've created runtime version policies that will update automatically based on other fields inside the app config (app.json/app.config.js). If these policies do not match the development flow of a project, there's also an option to set the "runtimeVersion"
manually.
"appVersion"
运行时版本策略¥"appVersion"
runtime version policy
"appVersion"
运行时是为具有自定义原生代码的项目提供的,这些代码可能会在构建之间发生变化。默认情况下,运行 eas update:configure
后运行时版本策略设置为 "appVersion"
:
¥The "appVersion"
runtime is provided for projects with custom native code that may change between builds. By default, the runtime version policy is set to "appVersion"
after running eas update:configure
:
{
"expo": {
"runtimeVersion": {
"policy": "appVersion"
}
}
}
对于其应用配置中包含以下内容的项目:
¥For a project that has the following in its app config:
{
"expo": {
"runtimeVersion": {
"policy": "appVersion"
},
"version": "1.0.0",
"ios": {
"buildNumber": "1"
},
"android": {
"versionCode": 1
}
}
}
"appVersion"
策略会将运行时版本设置为项目当前的 "version"
属性。在本例中,Android 和 iOS 构建以及任何更新的运行时版本都是 "1.0.0"
。
¥The "appVersion"
policy will set the runtime version to the project's current "version"
property. The runtime version for the Android and iOS builds and any updates would be in this case "1.0.0"
.
此策略非常适合包含自定义原生代码并在每次公开发布后更新 "version"
字段的项目。要提交应用,应用商店需要为每个提交的版本提供更新的原生版本号,如果你想确保用户设备上安装的每个版本都具有不同的运行时版本,则此策略会很方便。
¥This policy is great for projects that contain custom native code and that update the "version"
field after every public release. To submit an app, the app stores require an updated native version number for each submitted build, which makes this policy convenient if you want to be sure that every version installed on user devices has a different runtime version.
使用此策略时,你需要在每次公开发布时手动更新应用配置中的 "version"
字段,但对于 Play Store 的内部测试轨道和 App Store 的 TestFlight 上传,你可以依赖 eas.json 中的 "autoIncrement"
选项到 为你管理版本。
¥When using this policy, you need to manually update "version"
field in app config every time there is a public release, but for Play Store's Internal Test Track and the App Store's TestFlight uploads, you can rely on "autoIncrement"
option in eas.json to manage versions for you.
"nativeVersion"
运行时版本策略¥"nativeVersion"
runtime version policy
我们为具有可能在构建之间发生变化的自定义原生代码的项目提供 "nativeVersion"
运行时版本策略:
¥We provide the "nativeVersion"
runtime version policy for projects that have custom native code that may change between builds:
{
"expo": {
"runtimeVersion": {
"policy": "nativeVersion"
}
}
}
"nativeVersion"
策略会将运行时版本设置为项目当前的 "version"
和 "buildNumber"
(iOS) 或 "versionCode"
(Android) 属性。对于其应用配置中包含以下内容的项目:
¥The "nativeVersion"
policy will set the runtime version to the project's current "version"
and "buildNumber"
(iOS) or "versionCode"
(Android) properties. For a project that has the following in its app config:
{
"expo": {
"runtimeVersion": {
"policy": "nativeVersion"
},
"version": "1.0.0",
"ios": {
"buildNumber": "1"
},
"android": {
"versionCode": 1
}
}
}
Android 和 iOS 版本以及任何更新的运行时版本将是 "[version]([buildNumber|versionCode])"
的组合,在本例中为 "1.0.0(1)"
。
¥The runtime version for the Android and iOS builds and any updates would be the combination of "[version]([buildNumber|versionCode])"
, which in this case would be "1.0.0(1)"
.
此策略非常适合包含自定义原生代码并为每个版本更新原生版本号(iOS 为 "buildNumber"
,Android 为 "versionCode"
)的项目。要提交应用,应用商店需要为每个提交的版本提供更新的原生版本号,如果你想确保上传到 Play 商店的内部测试轨道和应用商店的 TestFlight 分发工具的每个应用都具有一个更新的原生版本号,则此策略会很方便 不同的 runtimeVersion
。
¥This policy is great for projects that contain custom native code and that update the native version numbers ("buildNumber"
for iOS and "versionCode"
for Android) for each build. To submit an app, the app stores require an updated native version number for each submitted build, which makes this policy convenient if you want to be sure that every app uploaded to the Play Store's Internal Test Track and the App Store's TestFlight distribution tools has a different runtimeVersion
.
重要的是要知道此策略确实要求开发者在每个构建之间手动管理原生版本号。
¥It's important to know that this policy does require the developer to manage the native version numbers manually between each build.
此外,如果你在 Android 和 iOS 之间选择不同的原生版本,你最终将得到具有单独运行时版本的构建和更新。当你发布更新时,EAS CLI 将检测到需要两个更新,并且它将创建两个具有所需运行时版本的更新并单独发布它们。
¥Also, if you select a different native version between Android and iOS, you'll end up with builds and updates with separate runtime versions. When you publish an update, EAS CLI will detect that two updates are needed, and it will create two updates with the required runtime versions and publish them separately.
"fingerprint"
运行时版本策略¥"fingerprint"
runtime version policy
截至 SDK 51,fingerprint
运行时策略仍处于测试阶段,尚未稳定。使用可能会导致意外的 EAS Update 行为。
我们为 Expo 项目提供 "fingerprint"
运行时版本策略,可自动为你计算运行时版本,包括通过 SDK 升级或添加自定义原生代码等更改。
¥We provide the "fingerprint"
runtime version policy for Expo projects that automatically calculates the runtime version for you, including through changes like SDK upgrades or adding custom native code.
{
"expo": {
"runtimeVersion": {
"policy": "fingerprint"
}
}
}
此策略适用于具有和不具有自定义原生代码的项目。它的工作原理是使用 @expo/fingerprint
包在构建和更新期间计算项目的哈希值,以确定构建更新兼容性(也称为运行时)。
¥This policy works for both projects with and without custom native code. It works by using the @expo/fingerprint
package to calculate the hash of your project during builds and updates to determine build-update compatibility (also known as the runtime).
"fingerprintExperimental"
运行时版本策略¥"fingerprintExperimental"
runtime version policy
fingerprintExperimental
已弃用,从 SDK 51 开始已删除。
我们为具有可能在构建之间发生变化的自定义原生代码的项目提供 "fingerprintExperimental"
运行时版本策略:
¥We provide the "fingerprintExperimental"
runtime version policy for a project that has custom native code that may change between builds:
{
"expo": {
"runtimeVersion": {
"policy": "fingerprintExperimental"
}
}
}
此策略非常适合包含需要安全更新而没有原生冲突的自定义原生代码的项目。与 "nativeVersion"
策略不同,"fingerprintExperimental"
选项会自动扫描项目的原生依赖以相应地更新 "runtimeVersion"
。
¥This policy is well-suited for projects incorporating custom native code that require safe updates without native conflicts. Unlike the "nativeVersion"
policy, the "fingerprintExperimental"
option automatically scans your project's native dependencies to update the "runtimeVersion"
accordingly.
启用指纹识别可能会延长构建时间,因为指纹识别过程可能会占用大量资源。
¥Enabling fingerprinting may lengthen build times, as the fingerprinting process can be resource-intensive.
"sdkVersion"
运行时版本策略(已弃用)¥"sdkVersion"
runtime version policy (deprecated)
已弃用:不推荐使用"sdkVersion"
运行时版本策略,建议使用"appVersion"
策略。此策略仅应用于在 SDK 48 或更低版本上测试 Expo Go 的更新。
"sdkVersion"
策略会将运行时版本设置为项目的当前 SDK 版本。例如,如果项目使用的是 Expo SDK 1.0.0,则具有此策略的运行时版本将为 "exposdk:1.0.0"
。每当我们更新项目的 Expo SDK 时,该运行时版本都会更新。因此,如果我们运行 expo upgrade
并安装 Expo SDK 2.0.0,那么运行时版本将变为 "exposdk:2.0.0"
。
¥The "sdkVersion"
policy will set the runtime version to the current SDK version of a project. For instance, if the project is on Expo SDK 1.0.0, the runtime version with this policy will be "exposdk:1.0.0"
. This runtime version will update any time we update the project's Expo SDK. So, if we ran expo upgrade
and installed Expo SDK 2.0.0, then the runtime version would become "exposdk:2.0.0"
.
{
"expo": {
"runtimeVersion": {
"policy": "sdkVersion"
}
}
}
"runtimeVersion"
¥Custom "runtimeVersion"
你还可以设置满足 运行时版本格式要求 的自定义运行时版本:
¥You can also set a custom runtime version that meets the runtime version formatting requirements:
{
"expo": {
"runtimeVersion": "1.0.0"
}
}
对于想要手动管理运行时版本(与项目应用配置中存在的任何其他版本号分开)的开发者来说,此选项非常有用。它使开发者可以完全控制哪些更新与哪些版本兼容。
¥This option is good for developers who want to manage the runtime version manually, separately from any other version numbers present in a project's app config. It gives the developer complete control over which updates are compatible with which builds.
"runtimeVersion"
¥Platform specific "runtimeVersion"
你还可以为特定平台设置运行时版本:
¥You can also set a runtime version for a specific platform:
{
"expo": {
"android": {
"runtimeVersion": "1.0.0"
}
}
}
当同时设置顶层运行时和特定于平台的运行时时,特定于平台的运行时优先。
¥When both a top level runtime and a platform specific runtime are set, the platform specific one takes precedence.
¥Avoiding crashes with incompatible updates
发布更新时可能出现的主要问题是更新可能依赖于其运行的版本不支持的原生代码。例如,假设我们使用 "1.0.0"
的运行时版本进行了构建。然后,我们将该版本提交给应用商店并向公众发布。
¥The main issue that can arise when publishing updates is that the update could rely on native code that the build it's running on does not support. For instance, imagine we made a build with a runtime version of "1.0.0"
. Then, we submitted that build to the app stores and released it to the public.
后来,假设我们开发了一个依赖于新安装的原生库的更新,例如 expo-in-app-purchases
库,并且我们没有更新 "runtimeVersion"
属性,因此它仍然是 "1.0.0"
。如果我们发布更新,使用 "runtimeVersion"
或 "1.0.0"
的构建会认为具有相同运行时版本的传入更新是兼容的,并且会尝试加载更新。由于更新将调用构建中不存在的代码,因此应用将崩溃。
¥Later on, imagine that we developed an update that relied on a newly installed native library, like the expo-in-app-purchases
library, and we did not update the "runtimeVersion"
property, so that it is still "1.0.0"
. If we published an update, the builds with the "runtimeVersion"
of "1.0.0"
would think the incoming update with the same runtime version was compatible and it would attempt to load the update. Since the update would make calls to code that does not exist inside the build, the app would crash.
有几种方法可以避免此类崩溃:
¥There are a few ways to avoid crashes like this:
每当我们安装或更新原生代码时,都会迭代项目的应用配置 (app.json/app.config.js) 中的 "runtimeVersion"
属性。
¥Whenever we install or update native code, iterate the "runtimeVersion"
property in the project's app config (app.json/app.config.js).
创建应用的预览版本并将其加载到测试设备上。然后,将更新发布到 "preview" 分支,以确保其按预期工作,然后再将其发布到项目的生产分支。
¥Create a preview build of your app and load it on a test device. Then, publish the update to the "preview" branch to make sure it works as expected before publishing it to the project's production branch.
如果确实发生此错误,则你可以重新发布以前的已知良好更新,然后要求用户删除该应用并重新安装。
¥If this error does occur, then you can republish a previous known-good update, then ask users to delete the app and reinstall it.
将来,expo-updates
库将防止许多此类实例导致应用崩溃。如果我们能够检测到这个特定问题,我们将自动回滚到以前的更新,而不是加载错误的更新。
¥In the future, the expo-updates
library will prevent many instances of this from crashing the app. If we can detect this particular issue, we'll automatically roll back to a previous update instead of loading the bad update.