Background Assets 的新功能
What's new in Background Assets
2023年6月5日
一句话判断
Background Assets 的核心理念是”用户打开 App 时不应该等待下载”——通过 App Extension 在安装、更新和后台周期性运行来预加载资源,如果你的 App 有大量按需下载的内容(游戏资源包、地图数据、AI 模型),这是必看的技术。
这场 Session 讲了什么
Session 详细介绍了 Background Assets 框架(iOS 16.1 引入)的架构和今年新增的功能。
Background Assets 基础回顾:
- 由框架 + App Extension 组成。Extension 在 App 未运行时也能工作。
- 三个触发时机:App 安装时、App 更新时、后台周期性。
- 关键能力:Extension 可以在用户首次启动 App 之前就运行——App Store 安装完成后立即开始下载资源。
- 通过 CDN 或自有服务器下载内容。
- 支持 macOS、iOS、iPadOS。
Extension 生命周期:
- App Store 安装/更新 App。
- 系统下载
BAManifestURL(Info.plist 中配置)指向的清单文件。 - 系统唤醒 Extension,传入清单文件路径。
- Extension 解析清单,返回一组
BADownload对象。 - 系统暂停或终止 Extension 以节省资源。
- 下载完成后系统再次唤醒 Extension,移动文件到最终位置。
运行时限制:
- 内存限制:几 MB。超过会被系统终止。
- 运行时间:每天默认几分钟(根据 App 使用频率动态调整)。
- 常用 App 获得更多运行时间,不常用的 App 会被限流。
- 低电量模式或关闭后台刷新时 Extension 不运行。
- 内存映射的文件不计入内存限制——用
mmap读取大文件是推荐做法。
新增功能:
- Session 末尾提到了全新的重大功能(但 transcript 在此处截断)。
值得深挖的点
“安装即下载”的能力是 Background Assets 最有价值的设计。传统的按需下载意味着用户第一次打开 App 时要等待。Background Assets 让你在 App Store 安装阶段就开始拉取资源——用户第一次点击图标时,核心资源已经在设备上了。这对游戏、导航、教育类 App 的首次启动体验改善巨大。
Extension 的沙盒设计限制了它的用途——它只能用于管理 Background Assets 内容。如果你发现需要在 Extension 中调用其他 API,说明你可能在错误的地方放了逻辑。Session 明确说如果沙盒限制影响到了你,应该通过 Feedback Assistant 反馈。
运行时间的动态分配是一个聪明的调度策略。系统根据 App 的使用频率调整 Extension 的运行预算——常用 App 获得更多后台时间,不常用的被限流。这意味着你不能依赖 Extension 每天稳定运行特定时长,要设计成”能跑就跑,不能跑就下次”的弹性模式。
代码片段
Info.plist 配置和 Extension 协议:
// Info.plist 中配置清单 URL
// Key: BAManifestURL
// Value: https://your-server.com/assets/manifest.json
// Extension 实现 BADownloaderExtension 协议
class BackgroundAssetExtension: BADownloaderExtension {
// 主要入口:返回需要下载的资源列表
func downloads(for request: BAContentRequest,
manifestURL: URL) -> Set<BADownload> {
// 解析清单文件,对比已下载的内容
let manifest = parseManifest(at: manifestURL)
// 使用内存映射读取大文件(不计入内存限制)
// let data = mmap(...)
var downloads = Set<BADownload>()
for asset in manifest.newAssets {
let download = BADownload(
identifier: asset.id,
url: asset.url,
fileSize: asset.size
)
downloads.insert(download)
}
return downloads
}
// 下载完成回调
func downloadDidComplete(for download: BADownload,
with error: Error?) {
guard error == nil else {
// 处理下载失败
return
}
// 将文件移动到最终位置
moveDownloadedFile(download)
}
}
清单文件结构示例:
{
"version": "1.2.0",
"assets": [
{
"id": "textures-pack-1",
"url": "https://cdn.example.com/assets/textures-v1.tar",
"size": 52428800,
"required": true
},
{
"id": "models-pack-1",
"url": "https://cdn.example.com/assets/models-v1.tar",
"size": 104857600,
"required": false
}
]
}
最佳实践
- 清单文件保持精简——Extension 的内存限制很紧,用内存映射读取大文件。
- 区分必需资源和可选资源——安装时下载核心资源,后台周期性下载可选内容。
- 设计弹性的下载策略——不能假设 Extension 每天都能运行,要做好”这次没跑成”的兜底。
- 在 App 进程中也提供手动下载入口——Background Assets 是优化,不是唯一路径。
- 文件下载完成后在 Extension 中立即移动到最终位置,不要等 App 启动后再处理。
- 测试时模拟 Extension 的各入口点(安装、更新、后台),确保覆盖所有场景。
还有什么值得关注
- Background Assets 框架在 iOS 16.1 引入,今年有新增功能,建议同时看去年的介绍 Session。
- Extension 的运行时限制可能在未来的系统版本中调整,关注 release notes。
- 如果你的 App 使用 On-Demand Resources(ODR),评估是否应该迁移到 Background Assets——后者有更灵活的调度能力。
- 内存映射(mmap)是处理大文件的关键技术,在 Extension 中尤为重要。
- CDN 的选择影响下载速度——Apple 没有限制使用哪个 CDN,选择最适合你用户群的。