On-Demand Resources "是Apple用于延迟加载应用程序内容的技术。开发人员不是将所有资源包含在安装包中,而是将它们放置在App Store服务器上,并在需要时请求。根据Apple ODR Guide,这可以减少初始安装大小,并在不更新应用程序版本的情况下添加新内容。
要点
On-Demand Resources (ODR) "是内置于iOS、tvOS和macOS的内容管理系统。它允许开发人员将应用程序资源分为必需资源(包含在安装包中)和按需加载资源(存储在App Store中,需要时下载)。
ODR系统使用三个关键实体:标签、资源包和请求。标签是连接一组文件的标识字符串。资源包是与标签关联的数据集。请求是启动资源包加载的NSBundleResourceRequest程序调用。
资源加载经历几个阶段:指定标签的请求初始化、检查本地存储中的可用性、如果不存在则从Apple服务器下载、通知应用程序准备就绪,以及使用后释放资源。系统自动管理缓存和未使用资源的删除。
| 阶段 | 系统操作 | 执行时间 |
|---|---|---|
| 初始化 | 使用标签创建NSBundleResourceRequest | 立即 |
| 缓存检查 | 在本地存储中搜索资源 | 0.1–0.5秒 |
| 下载 | 从Apple CDN下载 | 取决于大小 |
| 通知 | 调用完成处理器或委托 | 立即 |
| 释放 | 将资源标记为可被系统删除 | 应iOS要求 |
ODR机制基于后台服务,该服务管理来自App Store云存储的资源请求。当应用程序请求标签时,系统检查资源是否在本地缓存中。如果没有"通过支持在连接中断时恢复的后台URL会话开始下载。
import Foundation
class ResourceManager {
let odrRequest = NSBundleResourceRequest(tags: ["level-3"])
func loadLevel3() {
odrRequest.conditionallyBeginAccessingResources { available in
if available {
self.startLevel3()
} else {
self.odrRequest.beginAccessingResources { error in
guard error == nil else { return }
self.startLevel3()
}
}
}
}
func releaseResources() {
odrRequest.endAccessingResources()
}
}
conditionallyBeginAccessingResources方法检查资源在缓存中的可用性,而不立即加载。如果可用性标志为正"应用程序继续工作而无需延迟。如果资源缺失,beginAccessingResources通过progress属性启动带进度指示的下载。
iOS系统根据应用程序的当前活动自行管理ODR资源的加载优先级。如果应用程序在前台,加载以高优先级进行。在后台,iOS可能会延迟加载或在电池电量低时暂停加载。
ODR资源可以包括图像、视频、音频文件、精灵、关卡数据以及对启动应用程序不重要的任何其他文件。每个资源关联到一个或多个标签,这些标签确定其所属的功能块。
在Xcode中,标签通过Target Membership选项卡上的Resource Tags检查器进行配置。开发人员为项目中的每个文件指定它是主包的一部分还是通过标签加载。一个文件可以属于多个标签,允许资源在应用程序的不同部分之间重复使用。
<!-- Resource Tags 在 Info.plist 中的配置示例 -->
<key>NSBundleResourceRequestTags</key>
<dict>
<key>level-3</key>
<array>
<string>levels/level3.scnassets</string>
<string>textures/level3_tex.png</string>
</array>
</dict>
Apple根据资源在设备上应保留的时间长短区分三类ODR标签。Initial Install Tags随应用程序一起加载,永远不会被系统删除。Prefetch Tag Order确定安装后立即后台加载的顺序。主要标签按需加载,在空间不足时可能被iOS删除。
除了分类外,每个标签可以有加载优先级。高优先级标签优先于低优先级标签加载,即使它们后来才被请求。这允许开发人员管理内容出现的顺序:首先是主屏幕的关键资源,然后是应用程序深层部分的附加材料。
在Xcode中配置ODR包括三个阶段:按标签对资源进行分类、在Info.plist中配置加载参数以及通过NSBundleResourceRequest编程实现请求。大部分工作在项目构建方面完成。
// 检查ODR状态和监控进度
func monitorODRProgress(tag: String) {
let request = NSBundleResourceRequest(tags: [tag])
let observer = request.progress.observe(\.fractionCompleted) { progress, _ in
DispatchQueue.main.async {
let percent = Int(progress.fractionCompleted * 100)
print("ODR:\(percent)% 已加载")
}
}
}
加载进度通过NSProgress类的progress属性进行跟踪,支持KVO观察。应用程序可以在资源下载期间向用户显示进度指示器。加载完成后,资源通过FileManager和NSDataAsset的标准机制在应用程序的主包中可用。
ODR配额取决于iOS版本。从iOS 13开始,每个账户设备可以存储最多20GB按需加载的资源。这个容量在设备上安装的所有应用程序之间分配"如果一个应用程序占用很多空间,其他应用程序的空间就会减少。
监控已用空间通过NSBundleResourceRequest完成。应用程序可以检查可用的ODR存储空间,并据此决定首先加载哪些资源。建议实施备用机制:如果ODR存储空间已满,使用主包中降低质量的资源。
超过配额时,系统按最近最少使用的顺序删除带有On-Demand标签的资源,从最旧的开始。应用程序代码中的Resource Manager可以通过NSBundleResourceRequest属性跟踪当前占用的ODR存储容量。开发人员必须考虑到iOS可能随时决定删除On-Demand资源"应用程序应正确处理之前加载的资源突然不可用的情况。建议捕获资源访问错误并通过beginAccessingResources重新请求它们。对于应用程序无法运行的关键资源,请使用系统不会删除的Initial Install Tags。
On-Demand Resources为开发人员提供了管理应用程序大小的灵活工具,但对网络可用性和iOS存储策略施加了一系列限制。
ODR的主要优势是大幅减小初始安装大小。具有多个关卡的游戏、具有视频内容或大型图像集的应用程序可以分部分加载内容。用户立即获得基本功能的使用权,而额外资源在后台下载。
ODR在首次访问时需要持续的网络连接来加载资源。覆盖不良区域的用户可能会遇到加载延迟和错误。此外,Apple不保证加载的资源会保留在设备上"在空间不足时,iOS可能会在没有警告的情况下删除On-Demand标签。
常见问题
ODR允许在不发布新版本到App Store的情况下添加和修改资源。只需通过Xcode更新Apple服务器上的文件,并将它们分配给相同的标签。在下次请求时,应用程序将收到资源的最新版本。这对于季节性内容、临时促销和新图像及布局的A/B测试很方便。
系统在需要为其他应用程序释放空间时删除带有On-Demand标记的资源。Initial Install Tags资源不会被删除。删除顺序由LRU(最近最少使用)算法确定"首先删除最长时间未访问的资源。
从iOS 13开始,ODR存储的总限制为每个用户Apple ID 20GB。一个标签的大小不应超过512MB以获得最佳加载性能。超过限制时,请求会以NSBundleResourceRequestLowDiskSpaceError错误结束。
是的,加载后资源保存在本地缓存中,在离线模式下无需互联网连接即可使用。只有当iOS因空间不足删除了资源且用户没有网络尝试访问时才会出现问题。
ODR与App Store基础设施集成:资源托管在Apple CDN上,由缓存系统管理,不需要开发人员搭建自己的服务器。URLSession需要服务器基础设施、版本控制和手动缓存管理。ODR还能自动处理连接中断后的下载恢复。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。