下载更新
了解下载和启动更新的策略。
信息 本页上的所有以下信息仅适用于发布版本和启用了
EX_UPDATES_NATIVE_DEBUG的调试版本。
在本节中,我们将介绍下载和启动更新的不同策略。目标是确保终端用户在应用发布后尽快采用最新版本,同时不会因为引入加载缓慢的屏幕或其他问题而影响用户体验。这些策略并非相互排斥,你可以根据应用的需求灵活组合使用。
🌐 In this section, we'll cover the different strategies for downloading and launching updates. The goal is to ensure that the end user adopts the latest version of the app as soon as possible after it is published, without sacrificing the user experience by introducing slow loading screens or other issues. The strategies are not mutually exclusive, and you can mix and match them as needed for the requirements of your app.
默认情况下,更新在启动时异步加载
🌐 Updates are loaded asynchronously on startup by default
默认行为是在应用冷启动(从已停止状态启动)时检查更新,并在有可用更新时进行下载。这个过程不会阻塞应用的加载,因此使用这种策略时,终端用户只有在应用在发布更新后冷启动时才会加载更新,然后在某个时候杀掉并重新启动应用(例如,如果他们从操作系统的最近应用列表中关闭它,或者关闭并重新开启设备)。
🌐 The default behavior is to check for an update when the app is cold booted (launched from a killed state) and download the update if it's available. This process does not block loading the app, so when using this strategy the end user will only load the update when they cold boot the app after an update has been published, and then at some point kill and restart the app (for example, if they close it from the recent apps list on the OS or if they turn the device off and on).
这种行为是安全的,因为它不会在应用启动时等待网络请求完成(在用户遇到网络慢的情况时被卡在加载界面几秒,这会带来很糟糕的用户体验)。缺点是用户采用最新版本应用所需的时间会更长。如果理想情况是希望所有用户在更新发布后立即采用,那么这种策略远远不能达到这一点。
🌐 This behavior is safe because it doesn't interfere with app startup to wait for a network request to complete (which would be a bad user experience in common real-world cases where a user finds themself with a slow connection and they are stuck on a loading screen for several seconds). The downside is that it takes much longer for users to adopt the latest version of the app. If the ideal is for an update to be adopted immediately by all users as soon as it is published, then this strategy falls very short of that.
如果我想在下载最新更新之前一直阻止应用启动,该怎么办?
我们不推荐这种策略,因为由此带来的用户体验非常差。通常,当用户在启动应用时被卡在启动画面时,他们会关闭应用并重试(这样下载更新就无法完成),或者放弃并使用其他应用。当用户的设备连接到慢速网络时,即使没有更新,他们可能也需要等待几秒钟或更长时间才能加载应用。如果确保用户始终使用你应用的最新版本至关重要,你可能需要考虑此处解释的其他策略之一。
🌐 We recommend against this strategy because the resulting user experience is extremely poor. Typically when a user is stuck waiting on a splash screen when booting an app, they will close the app and try again (and so downloading the update won't complete), or give up and use another app. When the users' device is connected to a slow network, even when there is no update, they may have to wait several seconds or more to load the app. If ensuring that your users always have the latest version of your app is critical, you may want to explore one of the other strategies explained here.
我如何禁用默认行为?
你可以通过在 updates 配置中将 checkAutomatically 选项设置为 NEVER 来禁用默认行为。这将阻止应用自动检查更新和下载更新。
🌐 You can disable the default behavior by setting the checkAutomatically option to NEVER in the updates configuration. This will prevent the app from checking for updates and downloading them automatically.
在应用运行时检查更新
🌐 Checking for updates while the app is running
你可以在应用运行时使用 Updates.checkForUpdateAsync() 来检查更新。这将返回一个承诺,该承诺解析为一个 UpdateCheckResult 对象,如果有可用更新,isAvailable 会被设置为 true,并且更新的信息会包含在 manifest 属性中。
🌐 You can use Updates.checkForUpdateAsync() to check for updates while the app is running. This will return a promise that resolves to a UpdateCheckResult object, with isAvailable set to true if an update is available, and information about the update in the manifest property.
如果有更新可用,你可以使用 Updates.fetchUpdateAsync() 方法来下载更新。这将返回一个在下载完成时解决的 promise。最后,你可以使用 Updates.reloadAsync() 方法重新加载应用以使用新版本。useUpdates() 钩子也可以用于从 React 组件监控 expo-updates 库的状态。
🌐 If an update is available, you can use the Updates.fetchUpdateAsync() method to download the update. This will return a promise that resolves when the download is complete. Finally, you can use the Updates.reloadAsync() method to reload the app with the new version. The useUpdates() hook can also be used to monitor the state of the expo-updates library from a React component.
在应用运行时,检查更新的常见模式有哪些?
- 你可以在应用生命周期的各个阶段检查更新,例如当应用置于前台时或在某个时间间隔内。当发现更新时,你可能想显示一个对话框,提示用户进行更新。
- 你可以在启动时检查更新并显示你自己的自定义加载界面,如果确保用户在启动时总是获取最新版本对你的使用场景非常重要的话。
应用在后台时检查更新
🌐 Checking for updates while the app is backgrounded
你可以使用 expo-background-task 在应用处于后台时检查更新。为此,请使用与前台相同的 Updates.checkForUpdateAsync() 和 Updates.fetchUpdateAsync() 方法,但将它们在后台任务中执行。这是一种确保用户始终拥有应用最新版本的好方法,即使他们有一段时间没有打开应用。
🌐 You can use expo-background-task to check for updates while the app is backgrounded. To do this, use the same Updates.checkForUpdateAsync() and Updates.fetchUpdateAsync() methods as you would in the foreground, but execute them inside of a background task. This is a great way to ensure that the user always has the latest version of the app, even if they have not opened the app in a while.
值得考虑的是,你是否希望在后台下载更新后重新加载应用,还是等待用户关闭并重新打开它。如果你选择只在后台下载而不应用,这仍然是有用的,因为可以确保下一次启动时立即使用最新版本,并且相比默认行为,这将导致更新的采用率更快。
🌐 It's worth considering whether you want to reload the app after an update is downloaded in the background, or wait for the user to close and reopen it. If you choose to only download it in the background and not apply it, this should still be useful to ensure that the next boot will immediately have the latest version, and it will lead to a faster adoption rate for updates compared to the default behavior.
如何在后台检查更新的示例
为了确保在应用启动时注册后台任务,请在顶层组件中导入并调用 setupBackgroundUpdates 函数。
🌐 To ensure the background task is registered when the application starts, import and invoke the setupBackgroundUpdates function within the top-level component.
import * as TaskManager from 'expo-task-manager'; import * as BackgroundTask from 'expo-background-task'; import * as Updates from 'expo-updates'; const BACKGROUND_TASK_NAME = 'task-run-expo-update'; export const setupBackgroundUpdates = async () => { TaskManager.defineTask(BACKGROUND_TASK_NAME, async () => { const update = await Updates.checkForUpdateAsync(); if (update.isAvailable) { await Updates.fetchUpdateAsync(); await Updates.reloadAsync(); } return Promise.resolve(); }); await BackgroundTask.registerTaskAsync(BACKGROUND_TASK_NAME, { minimumInterval: 60 * 24, }); }; setupBackgroundUpdates();
当应用在后台运行时,我也应该使用 Updates.reloadAsync() 来应用更新吗?
在应用处于后台时调用 Updates.reloadAsync() 的支持是实验性的。这是一个新功能,使用范围不广,首次启用时请注意监控崩溃情况。在后台下载更新是安全的。
在应用处于后台时重新加载更新,可以确保用户在再次打开应用时拥有最新版本。然而,需要注意的是,除非你保存应用在进入后台时的状态并恢复该状态,否则用户在再次打开应用时会经历冷启动。缓解这种情况的一种方法是,仅在应用处于后台并且非活动状态达到一定时间后再执行重新加载,这样用户就不太可能期望应用恢复其之前的状态。
🌐 Reloading an update while the app is backgrounded can be a great way to ensure that the user has the latest version of the app when they open it again. However, it is important to note that, unless you persist the state that the app was in at the time it was backgrounded and restore that state, the user will experience a cold boot when they open the app again. One way to mitigate this is to only do a reload in the background if the app has been inactive for a certain period of time, after which a user is unlikely to expect the app to restore its previous state.
关键/强制更新
🌐 Critical/mandatory updates
expo-updates 库没有对关键/强制更新的一级支持。不过,你可以自己实现逻辑来检查关键更新并手动应用它们。expo/UpdatesAPIDemo 仓库 包含了一种实现此方法的示例。你可以将这种方法与上述策略结合起来检查更新。
🌐 There is no first-class support for critical/mandatory updates in the expo-updates library. However, you can implement your own logic to check for critical updates and apply them manually. The expo/UpdatesAPIDemo repository contains an example of one way to approach this. You can combine that approach with the strategies above to check for updates.
控制从客户端加载哪些更新
🌐 Controlling which update to load from the client side
使用 EAS Update 的典型方式是在应用构建中嵌入单个更新 URL 和一组请求头(例如更新通道名称)。要控制加载哪个更新,你可以通过 eas update 命令或 EAS 仪表板在服务器上进行更改。例如,你将一个新更新发布到你的构建所指向的通道,然后构建在下次启动时会获取该更新。使用这种方法,发布到与你的构建所指向通道不同的通道的更新将不会被下载。
🌐 The typical way to use EAS Update is to have a single update URL and a set of request headers (such as update channel name) embedded in a build of your app. To control which update is loaded, you make changes on the server through the eas update command or the EAS dashboard. For example, you publish a new update to a channel that your build is pointing to, then the build fetches that update on the next launch. Updates published to a channel different from the one your build is pointing to will not be downloaded with this approach.
你可以在运行时使用 Updates.setUpdateURLAndRequestHeadersOverride() 方法覆盖更新 URL 和请求头。如果你想加载特定更新或在应用运行时更改更新通道,这会很有用。了解更多。
🌐 You can override the update URL and request headers at runtime using the Updates.setUpdateURLAndRequestHeadersOverride() method. This can be useful if you want to load a specific update or change the update channel while the app is running. Learn more.
监控更新的采用情况
🌐 Monitoring adoption of updates
更新的详细信息页面(例如:https://expo.dev/accounts/[account]/projects/[project]/updates/[id])显示运行该更新的用户数量指标,以及安装失败的次数(指下载并尝试运行更新但发生崩溃的用户)。
🌐 The details page for an update (for example: https://expo.dev/accounts/[account]/projects/[project]/updates/[id]) shows metrics for the number of users who have run the update, in addition to the number of failed installs (users who download and attempted to run the update, but it crashed).
部署页面(例如:https://expo.dev/accounts/[account]/projects/[project]/deployments/production/[runtime-version])包括一个表格和图表,显示在特定时间段内,运行与特定更新通道和运行时版本组合相关的每个更新的用户数量。
🌐 The deployments page (for example: https://expo.dev/accounts/[account]/projects/[project]/deployments/production/[runtime-version]) includes a table and chart that shows the number of users who have run each update related to a particular update channel and runtime version combination, over a given time period.