System & Services 进阶 20m
认识 Background Assets 框架
Meet Background Assets
2022年6月6日
一句话判断
Background Assets 让你的 App 在首次启动前就下载好所需资源——用户下载完 App 后直接用,不再面对二次下载等待。
这场 Session 讲了什么
用户从 App Store 下载你的 App,满怀期待打开,结果看到的却是一个下载进度条——这种体验太常见了。游戏需要下载纹理贴图,新闻 App 需要下载离线内容,各种 App 都有首次启动后还需要额外下载资源的需求。
Background Assets 框架专门解决这个问题。它提供了一个 App Extension,能在三个关键时机运行:App 首次安装但未启动时、App 在后台自动更新后、以及定期后台运行。Extension 的职责是调度下载任务,实际下载由系统服务完成。
框架的核心是 BADownloadManager,一个单例对象,用于调度、查询和取消下载任务。下载对象(如 BAURLDownload)需要指定 URL、App Group 标识符和唯一标识符。App 和 Extension 通过 App Group 共享已下载的文件。
值得深挖的点
- Extension 运行时机:App 安装后、更新后、定期后台——这三种时机覆盖了大部分资源预加载场景。但 Extension 的运行时间是短暂的,必须快速调度完下载任务,否则会被系统终止。
- 频率回退机制:Extension 的定期运行频率与 App 使用频率挂钩。如果 App 很少被使用,Extension 的运行频率会逐渐降低。这对资源更新策略有直接影响。
- 同步机制:框架提供了
BADownloadManager的同步 API,防止 App 和 Extension 同时操作同一个下载任务。在 Extension 中调度下载前,应该先检查 App 是否已经在下载相同的资源。 - App Group 的关键作用:下载的文件存储在 App Group 的共享容器中。App 和 Extension 必须属于同一个 App Group 才能共享资源。
代码片段
import BackgroundAssets
// 在 Extension 中调度下载
let url = URL(string: "https://example.com/assets/texture_pack.dat")!
let appGroupIdentifier = "group.com.example.myapp"
// 创建下载对象
let download = BAURLDownload(
identifier: "texture_pack_v1",
url: url,
appGroupIdentifier: appGroupIdentifier
)
// 获取下载管理器并调度
let manager = BADownloadManager.shared
try manager.schedule(download)
// 在 App 中查询已完成的下载
let downloads = manager.downloads
for download in downloads {
if download.identifier == "texture_pack_v1",
download.state == .finished {
// 从 App Group 容器中读取下载的文件
let fileURL = download.fileURL
// 使用资源...
}
}
最佳实践
- 给每个下载任务使用稳定且有意义的唯一标识符,系统不允许重复标识符的下载同时存在
- Extension 中只做调度,不做耗时操作——运行时间有限,超时会被杀掉
- 大文件下载优先在后台调度,让系统管理网络和电量
- 利用 App Group 容器存储下载进度和版本信息,App 启动后据此决定是否需要更新
- 定期清理过期的下载资源,不要无限占用用户存储空间
还有什么值得关注
- Background Assets 适用于游戏(纹理、关卡数据)、新闻阅读器(离线内容)、地图类 App(离线地图包)等场景
- 框架不限于首次安装,也可以用于增量更新——App 更新后自动下载新版本所需的资源
- “Meet declarative device management” 中介绍了 MDM 场景下如何管理 Background Assets 的行为
- 下载任务的网络行为遵循系统的低电量模式和后台刷新设置
WWDC 2022