On Demand Resources 已弃用:Background Assets 的代价
苹果用 13 个词让一套服役十年的内容分发机制退场:”On Demand Resources and the NSBundleResourceRequest API are deprecated. Use Background Assets instead.”1
这句话就是词条的全文。它挂着雷达号 170066290,位于 Deprecations 之下,并在三份彼此独立的发行说明中一字不差地重复出现。123 苹果没有公布移除版本,没有为这次弃用配套迁移指南,macOS 与 watchOS 的发行说明里也没有任何呼应。
真正的工作量藏在最后四个词里。Background Assets 并非铁板一块,而是分成三种配置:托管模型不同,最低部署目标不同,迁移成本相差近一个数量级。这道选择题在写下第一行代码之前就要作答,选错了,代价最昂贵。
摘要
- 苹果在 iOS 与 iPadOS 27、tvOS 27、visionOS 27 的发行说明中弃用了 On Demand Resources 和
NSBundleResourceRequest。123 ODR 依然可用。苹果未指定移除日期,被弃用的接口照常随 SDK 发布,也照常解析标签。 - 接口自身的可用性数据把弃用范围扩展到六个平台,比任何一份发行说明都多出两个:Mac Catalyst 和 watchOS。4 而 Background Assets 完全没有公布 watchOS 可用性,于是 watchOS 迎来了一次没有任何文档化替代方案的弃用。56
- “改用 Background Assets”这句话分成三条路:苹果托管的托管式、自行托管的托管式,以及非托管式。两条托管路径都要求最低部署目标为 iOS 26.0。78 低于 26.0 就只剩非托管这一条路,而它要求您自己托管文件、自己设计清单格式、自己解析。9
- 磁盘管理的归属彻底反转。ODR 允许系统清除未使用的标记资源,而
setPreservationPriority(_:forTags:)只是给系统一个清除顺序的提示。410 Background Assets 则会把每一个已下载的资源包一直留在设备上,直到您的代码调用remove(assetPackWithID:)。11 - 苹果最多为每个 App 记录托管 200 GB 压缩后的资源包、最多 200 个包,额度在您的 App 所支持的全部平台间共享;资源包上传至 App Store Connect,并与构建版本分开审核。1213
苹果究竟弃用了什么
这条说明里有三个关键细节,而它一个也没写。
波及范围比发行说明更广。 承载该词条的文档共三份:iOS 与 iPadOS 27、tvOS 27、visionOS 27,每份都置于 On Demand Resources 标题下的 Deprecations 子标题中,引用的雷达号完全相同。123 macOS 27 和 watchOS 27 的说明对此只字未提。
接口的可用性标注讲的是一个范围更广的故事。NSBundleResourceRequest 标注为 iOS 9.0 引入、27.0 弃用,同样的 27.0 弃用标记还出现在 iPadOS 9.0、Mac Catalyst 13.1、tvOS 9.0、visionOS 1.0 和 watchOS 2.0 上。4 元数据里是六个平台,发行说明中点名的只有四个。Bundle 的两个保留优先级方法带着同样的六平台标注。10 仅凭发行说明做审计,会把 Mac Catalyst 和 watchOS 这两条完全漏掉。
Mac Catalyst 那一条名存实亡。苹果明确写过,NSBundleResourceRequest“会忽略来自以 Mac Catalyst 构建的 Mac App 的调用”,所以这次弃用只是给一个本就什么都不做的接口收了尾。4 watchOS 那一条则不然。Background Assets 公布的可用性覆盖 iOS 16.0、iPadOS 16.0、Mac Catalyst 16.0、macOS 13.0、tvOS 18.4 和 visionOS 2.4,唯独没有 watchOS 一行。5 苹果直言,苹果托管的资源包”面向通过 App Store 分发的 App 提供,覆盖除 watchOS 外的所有平台”。6 于是使用 ODR 的 watchOS App 只收获一条弃用警告,却无处可迁。
在我写过的三项 27 周期变更中,这一项的强制力最弱。 弃用就只是弃用。苹果没有公布移除版本,没有设置提交关口,也没有运行时失败。对比同一周期的场景生命周期强制要求——用新 SDK 构建的 App”将无法启动”;再对比启动屏幕要求——App Store 会直接拒绝该构建版本。这两样 ODR 都不沾。已有标签照常解析,已有调用照常返回资源,已发布的二进制文件照常运转。真正到来的,是一条编译警告,和一个谁也读不出刻度的倒计时。
这个时间点更像一次决策,而非一次清理。 苹果一次性在四个平台名下弃用该接口,距其替代方案的托管层交付仅隔一个版本。请把这次弃用看作一扇迁移窗口就此打开——而苹果并未公布这扇窗口会开多久——而不是一场火烧眉毛的急事。
写代码之前就要走的岔路
苹果的框架概览描述了两种托管模型,以及一个”替您处理下载、更新、压缩等事务”的托管式默认方案。若选择苹果托管,”您将资源上传至 App Store Connect 并在那里维护,方式与 App 构建版本类似”。5 Xcode 的 Background Download 扩展模板直接给出两种类型:苹果托管的托管式,以及自行托管的非托管式。911 而属性列表键里还藏着第三种组合:将 BAHasManagedAssetPacks 设为 YES 但不启用 BAUsesAppleHosting,选中的就是由您自行托管的托管式资源包,其文档会把您导向 ManagedDownloaderExtension 协议,而非 StoreKit 的 StoreDownloaderExtension。7814
| 苹果托管、托管式 | 托管式、自行托管 | 自行托管、非托管 | |
|---|---|---|---|
| 最低 iOS 版本 | 26.0715 | 26.0714 | 16.19 |
| 谁托管文件 | 苹果,经由 App Store Connect6 | 您 | 您 |
| 清单格式 | 苹果的 JSON 结构11 | 苹果的 JSON 结构11 | 由您自行设计并解析9 |
| 扩展协议 | StoreDownloaderExtension716 |
ManagedDownloaderExtension714 |
BADownloaderExtension9 |
| 下载、更新、压缩 | 系统5 | 系统5 | 您9 |
| 属性列表键 | 3 个11 | 无完整文档7 | 4 个顶层键,其中一个内含 3 个9 |
对多数团队而言,部署目标就是答案。所有托管式入口都至少要求 iOS 26.0,上至 AssetPackManager 和 ManagedDownloaderExtension,下至那三个属性列表键,无一例外。781415 一个仍需支持 iOS 18 的 App 根本无缘托管层,选项收窄为两条:走可回溯至 iOS 16.1 的非托管路径,或者留在已弃用的 ODR 上,等部署目标抬上去再说。9
非托管路径是另一份工作。按苹果给出的流程,系统会在 App 启动前从 BAManifestURL 下载清单,把文件交给您的扩展,再取回一组下载请求。9 苹果对分工的表述毫不含糊:”为自行托管的非托管资源创建清单文件是您的责任(格式由您自选),并由您的代码解析出 URL 和文件大小交给系统。”9 托管、CDN、清单结构、解析器、域名白名单,统统由您提供。把”改用 Background Assets”读成一次接口替换的人,看的是托管层,报的却是非托管层的账单。
ODR 曾经代劳、如今需要您手工重建的部分
ODR 的三项行为没有任何可直接替换的等价物。
标签变成资源包。 ODR 用在 Xcode 中分配的字符串标签标识内容,由 NSBundleResourceRequest(tags:) 认领其中一个或多个。4 Background Assets 用资源包取代标签:由 JSON 清单描述的文件目录,再经命令行工具压缩成 .aar 归档。粒度单位变大了,而分配动作也从 Xcode 的资源目录移到了一份由您维护的文件里。
苹果托管意味着另起一条发布流水线。 ODR 的内容随构建版本一同发布。苹果托管的资源包则通过 Transporter、altool、iTMSTransporter 或 App Store Connect API 独立上传,并与 App 分开提交 App Review。1113 解耦本身就是卖点:不发新构建也能上新内容。代价是第二条提交流水线、第二个审核队列,以及第二套需要盯着的状态。
自动清理成了您的分内事,而这次反转是全部变化中最锋利的一处。 ODR 把已下载内容视作系统所有的缓存。苹果的文档写道,只要”至少有一个 NSBundleResourceRequest 对象正在管理某个标签,系统就不会尝试从设备存储中清除该标签标记的资源”——这是关于清除时机的承诺,而非关于是否清除。4 setPreservationPriority(_:forTags:) 的存在意义,恰恰是”向系统提示 bundle 内各组标记资源的相对清除顺序”。10 您结束认领,系统按自己的节奏回收空间,低存储场景的处理是苹果的问题。
Background Assets 把所有权翻了过来。系统会自动保持资源包为最新,checkForUpdates() 会移除服务器上已作废的包。15 但这两套机制都不会驱逐一个您单纯用完了的包。苹果的指示写得明白:”只要您的 App 处于安装状态,系统就不会自动移除您的资源包。因此,用完某个资源包后,请调用 remove(assetPackWithID:) 方法。”11
那套有作用域、带引用计数的模式,坍缩成了一次需要您主动决定去调用的显式删除:
// ODR: claim a tag, use the file, release the claim.
// The system reclaims the space afterward on its own schedule.
let request = NSBundleResourceRequest(tags: ["Tutorial"])
try await request.beginAccessingResources()
let url = Bundle.main.url(forResource: "Introduction", withExtension: "m4v")
request.endAccessingResources()
import System // url(for:) and contents(at:) take a FilePath
// Background Assets: ensure the pack, read the file, delete the pack.
// Nothing reclaims the space if you skip the last line.
let manager = AssetPackManager.shared
guard let pack = try await manager.manifest.assetPack(withID: "Tutorial") else { return }
try await manager.ensureLocalAvailability(of: pack, requireLatestVersion: false)
let url = try manager.url(for: "Videos/Introduction.m4v")
try await manager.remove(assetPackWithID: "Tutorial")
凡是代码里内含 ODR 驱逐假设的 App,都需要为它专门写一份存储策略。失效方式极其安静:不崩溃,不告警,设备存储一路攀升,直到用户在存储列表里看见您的 App。
迁移面,逐项拆解
若走苹果托管的托管式路径,按苹果自己的步骤可以整理出下面这份清单。
把文件归入资源包,并逐包选定下载策略。策略共三种。essential 在安装期间下载,并计入用户在 App Store、TestFlight 和主屏幕上盯着看的那条进度。prefetch 在安装期间启动,并在安装结束后于后台继续。onDemand 只在您的代码提出请求时才下载。11 对 essential 和 prefetch 而言,嵌套的 installationEventTypes 数组接受 firstInstallation、subsequentUpdate 或两者兼有,因此教程包可以只在首次安装时下载,跳过之后的每一次更新。11
逐包编写清单。Xcode 会生成带注释的模板:
xcrun ba-package template -o Manifest.json
{
"assetPackID": "Tutorial",
"downloadPolicy": {
"essential": {
"installationEventTypes": ["firstInstallation"]
}
},
"fileSelectors": [
{ "file": "Videos/Introduction.m4v" },
{ "directory": "Textures/Tutorial" }
],
"platforms": ["<identifiers from the generated template comments>"]
}
文件路径相对于您运行打包命令的目录解析,这一点在稍后按路径回读文件时会再次变得要紧。11 逐包归档:
xcrun ba-package Manifest.json -o Tutorial.aar
在 Application Extension 下添加一个 Background Download 扩展目标,类型选苹果托管的托管式。为 App 和扩展都添加 App Groups 能力,并把两者放进同一个组。随后给 App 目标添加三个属性列表键:BAAppGroupID、设为 YES 的 BAHasManagedAssetPacks,以及设为 YES 的 BAUsesAppleHosting。苹果要求,苹果托管的项目须省略其余全部 Background Assets 键。11 有一处约束很容易踩空:采用 AssetPackManager 却不同时采用配套的扩展协议,用苹果的原话说,是”一个编程错误”。15
回读文件走的是一个合并后的命名空间。苹果会”自动把您的所有资源包合并进一个共享命名空间,效果相当于把您的资源根目录原样粘贴到用户设备上重建一遍”,因此代码按路径寻址文件即可,无需追踪文件究竟在哪个包里。11 读取默认返回内存映射的 Data,另有一个供程序化加载使用的文件描述符变体,需要您自行关闭。11
本地测试的准备工作值得单独排一项预算。Background Assets 的每一次下载都走 HTTPS,因此模拟服务器需要证书。苹果给出的路径依次是:用”钥匙串访问”创建自签名根 CA,用 Apple Configurator 制作携带该 CA 的描述文件,在每台测试设备上安装并信任该描述文件,签发一张名称与服务器 IP 地址或主机名完全一致的 SSL 叶证书,启动服务器,再在每台设备的开发者设置中设定 URL 覆盖。17
xcrun ba-serve --host localhost Tutorial.aar HighQualityTextures.aar
请把这套流程当作一项独立任务来安排。On Demand Resources 从头到尾不需要您提供任何服务器:苹果将其描述为面向”托管在 App Store 上的内容”的管理器,设备上缺失的资源”会向 App Store 请求”。4 迁移意味着,您得先把托管环境(或一个受信任的模拟版本)立起来,才能跑通哪怕一次下载。把两套流程并排读下来,我预计吃掉迁移第一天的会是证书链,而不是接口适配。
用来做计划的那些数字
苹果为其托管的资源包公布了两条硬上限:总量 200 GB,每个 App 记录最多 200 个资源包。两者都”在您的 App 所提供的全部平台间共享”。12 总量的算法是取符合 TestFlight 或 App Store 分发条件的各版本中的最大体积,排除 Awaiting Upload、Processing、Failed 及已被完全取代的版本,达到上限 80% 时苹果会发邮件通知。归档某个资源包可以回收空间,代价是移除它的全部版本,包括已在 App Store 上线的版本。12
非托管路径把这些上限换成了四个由您自己设定的顶层属性列表键,其中一个是内含三个键的字典;而压缩与未压缩之分是个货真价实的陷阱。BADownloadAllowance 和 BAEssentialDownloadAllowance 限制下载体积,取的是压缩后的值。BAMaxInstallSize 和 BAEssentialMaxInstallSize 限制安装后体积,取的是未压缩的值。9 苹果给安装体积这两个键附了一条警告,而它实质上是一条产品警告:”App Store 会用此键在产品页面上展示您的 App 体积,因此请提供准确数值……不要虚报您所需的磁盘空间。”18 BADownloadDomainAllowList 补全了这一组,接受 DNS 格式的域名,可用前导星号表示通配。9
还有一个数字该写进计划,它来自可用性元数据而非正文。AssetPackManager 随 iOS 26.0 交付,其中已有四个成员带上了弃用标记:ensureLocalAvailability(of:) 与 status(ofAssetPackWithID:) 于 26.4 弃用,随后是 27.0 上的 assetPack(withID:) 与 allAssetPacks。19 查询、状态、下载调用,各自都在两个小版本之间挪过一次位置。苹果如今指向的新路线——经由管理器的 manifest 属性——在 27.0 的 SDK 里带着 beta 标注,批量版的 ensureLocalAvailability(of:requireLatestVersions:) 同样如此。19 而苹果自家那篇讲苹果托管的演练文章,至今仍在演示其中两个已弃用的调用。11 因此实际的下限高于该层名义上的 26.0。要写出前文那段下载代码而不吃到弃用警告,就意味着以 27.0 为目标,并为此接受带 beta 标注的符号。这套被要求采用的替代方案,比它所替代的接口更年轻,也变动得更快。
这次弃用真正波及谁
受影响的群体很窄,窄到我在自己的代码里一处都没找到。我在七个已发布项目中检索了 NSBundleResourceRequest、beginAccessingResources、setPreservationPriority、任何 ON_DEMAND_RESOURCES 构建设置、knownAssetTags,以及资源目录的标签配置。七个项目,每一种模式,命中数均为零。对项目目录下全部 Swift、Objective-C、属性列表和 pbxproj 文件做的全仓扫描,没有返回任何 ODR 符号,也没有返回任何 Background Assets 符号。20
这个空结果的成因值得点破,因为它有普遍性。ODR 的存在,是为了那些内容体量远超代码体量的 App。我最大的资源目录属于 Return,66.6 MB,其余每个 App 都在 8 MB 以下,Water 和 Yawara 更是不足 100 KB。20 在这样的体量上,把内容拆成资源包只会平添网络失败模式、一份存储策略和第二条审核流水线,省下的却是一次根本没人抱怨的下载。真正需要 Background Assets 的,是带关卡内容的游戏、分发大体积机器学习模型的 App,以及任何按语言配备视频的产品——而这恰恰就是苹果在 iOS 27 中推出本地化资源包所瞄准的人群。21
部署目标让画面更清晰,它也是任何代码库里最该先查的那个数字。我六个 iOS App 中有五个已经在 iOS 26.0 或更高,托管层今天就对它们开放。Ace Citizenship 的部分目标仍声明 17.0 和 17.5,这就排除了托管层,只留下非托管路径或已弃用的 ODR。20 设计任何方案之前先做这项检查:决定您实际能拿到哪种迁移方案的,是最低部署目标,不是资源体量。
常见问题
On Demand Resources 在 iOS 27 中会停止工作吗?
不会。苹果把 ODR 和 NSBundleResourceRequest 标记为弃用,既没有公布移除版本,也没有设置提交关口或运行时失败。1 被弃用的接口继续正常工作,已有标签继续解析。您得到的是一条编译警告。与同一周期其他破坏性变更的对比很能说明问题:场景生命周期强制要求会让 App”无法启动”,启动屏幕要求会让 App Store 拒绝构建版本。ODR 的弃用是启动了一个倒计时,而不是关上了一扇门。
这次弃用覆盖哪些平台?
发行说明在三份文档中点名四个平台:iOS 与 iPadOS 27、tvOS 27、visionOS 27,引用的都是雷达号 170066290。123 接口的可用性元数据范围更宽,把 NSBundleResourceRequest 与 Bundle 的保留优先级方法在六个平台上标记为 27.0 弃用,多出 Mac Catalyst 和 watchOS。410 Mac Catalyst 只有理论意义,因为苹果写明该类会忽略来自 Catalyst App 的调用。4 watchOS 则不然:Background Assets 没有公布任何 watchOS 可用性,苹果托管的资源包覆盖”除 watchOS 外的所有平台”,于是 watchOS App 手握一个被弃用的接口,却没有任何有文档可依的继任者。56
我的 App 支持 iOS 18,还能迁移吗?
迁不到托管层。AssetPackManager、ManagedDownloaderExtension、BAHasManagedAssetPacks 和 BAUsesAppleHosting 一律要求 iOS 26.0。781415 这条门槛之下还剩两个选项。非托管路径自 iOS 16.1 起可用,但要求您自行托管资源、定义自己的清单格式、在扩展中解析它,并在属性列表中声明下载额度和域名白名单。9 否则就继续用已弃用的 ODR,直到部署目标抬到 26.0——苹果迄今没给出移除日期,这条路目前是走得通的。
如果把 ODR 代码原样搬过去,什么会悄悄坏掉?
存储。ODR 允许系统清除未使用的标记内容,setPreservationPriority(_:forTags:) 只是提示顺序而已。410 Background Assets 则在 App 保持安装状态期间,绝不移除一个您已经用完的包,那块空间归您所有,直到您调用 remove(assetPackWithID:)。11 照搬旧的 beginAccessingResources 与 endAccessingResources 模式、却不补上一次显式删除的代码,会无休止地泄漏磁盘空间,既不崩溃,也没有任何警告能让您在测试中抓到它。请先写驱逐策略,再写下载代码。
关键要点
面向 iOS 开发者:
- 一切之前,先查最低部署目标。低于 iOS 26.0,托管层对您并不存在,”改用 Background Assets”意味着在非托管路径上自建托管、清单格式和解析器。79
- 把驱逐策略写进迁移方案。remove(assetPackWithID:) 没有自动对应物,而 ODR 那套”结束认领、信任系统”的习惯,只会让存储悄无声息地涨下去。11
面向分发大体积内容的团队: - 把本地测试的搭建与编码分开列预算。苹果给出的路径包括自签名根 CA、在每台设备上安装并信任的 Apple Configurator 描述文件、与服务器主机名匹配的 SSL 叶证书,以及逐台设备的 URL 覆盖。17 - 按 200 GB 和每个 App 记录 200 个资源包来做规划,额度在您的 App 分发的所有平台间共享,并留意苹果在 80% 时发出的邮件。12 为回收空间而归档,会一并移除已在 App Store 上线的版本。12
面向发布负责人: - 苹果托管的资源包意味着第二条提交流水线:经 Transporter 或 App Store Connect API 上传,独立于构建版本做版本管理,并单独提交 App Review。1113 审核周期的人力要按此配置。 - 本周期没有任何东西在逼您迁移。把 ODR 排在场景生命周期强制要求和启动屏幕要求之后——那两项都带着真正的强制力——等苹果公布移除版本时再回头处理。
27 周期一直在按牙齿的锋利程度给破坏性变更排序:场景生命周期让 App 起不来,启动屏幕让构建发不出去,而 ODR 只是启动了一个倒计时。分得清孰轻孰重,才算把这个周期花在了刀刃上。同样的模式在更小的切面上还有一例,参见 ImageCreator 从 Image Playground 中移除。整个系列的索引页是 Apple 生态系列。
参考资料
-
Apple, iOS & iPadOS 27 Release Notes, On Demand Resources section, Deprecations (radar 170066290): “On Demand Resources and the
NSBundleResourceRequestAPI are deprecated. Use Background Assets instead.” 已于 2026 年 7 月 25 日对照苹果文档 JSON 核实。该词条即全文;发行说明中不含任何关于 On Demand Resources 的移除版本、提交要求或运行时失败表述。 ↩↩↩↩↩↩ -
Apple, tvOS 27 Release Notes, On Demand Resources section, Deprecations (radar 170066290). 措辞与 iOS 及 iPadOS 说明完全一致。 ↩↩↩↩
-
Apple, visionOS 27 Release Notes, On Demand Resources section, Deprecations (radar 170066290). 措辞完全一致。macOS 27 与 watchOS 27 的发行说明不含对应词条,已于 2026 年 7 月 25 日检索其文档 JSON 核实。 ↩↩↩↩
-
Apple, NSBundleResourceRequest, Foundation. 可用性:iOS 9.0、iPadOS 9.0、Mac Catalyst 13.1、tvOS 9.0、visionOS 1.0 和 watchOS 2.0,均在 27.0 弃用。以下内容的出处:标签模型(”您在开发期间通过创建称为标签的字符串标识符来标识按需资源”)、清除行为(”只要至少有一个
NSBundleResourceRequest对象正在管理某个标签,系统就不会尝试从设备存储中清除该标签标记的资源”)、Mac Catalyst 说明(”此类会忽略来自以 Mac Catalyst 构建的 Mac App 的调用”)以及单次使用约束。成员接口init(tags:)、beginAccessingResources(completionHandler:)和endAccessingResources()带有同样的六平台 27.0 弃用标记。 ↩↩↩↩↩↩↩↩↩↩ -
Apple, Background Assets, 框架概览。可用性:iOS 16.0、iPadOS 16.0、Mac Catalyst 16.0、macOS 13.0、tvOS 18.4 和 visionOS 2.4,无 watchOS 一行。以下内容的出处:”Managed Background Assets 的默认实现会替您处理下载、更新、压缩等事务”以及”若选择 Apple-Hosted Background Assets,您将资源上传至 App Store Connect 并在那里维护,方式与 App 构建版本类似”。 ↩↩↩↩↩↩
-
Apple, Creating managed asset packs, Background Assets. 以下内容的出处:”Apple-Hosted Background Assets 最多可托管 200GB 的压缩资源,面向通过 App Store 分发的 App 提供,覆盖除 watchOS 外的所有平台。” ↩↩↩↩
-
Apple, BAHasManagedAssetPacks, Information Property List 参考。布尔值,iOS 26.0、iPadOS 26.0、macOS 26.0、tvOS 26.0 和 visionOS 26.0。扩展协议路由说明的出处:”若将
BAUsesAppleHosting键设为YES,请使用 StoreKit 的StoreDownloaderExtension协议;否则请使用 Background Assets 的ManagedDownloaderExtension协议。”该路由说明记录了托管式、自行托管这一组合,而各篇演练文章并未对其做完整覆盖。 ↩↩↩↩↩↩↩↩↩↩ -
Apple, BAUsesAppleHosting 与 BAAppGroupID, Information Property List 参考。两者均标注 iOS 26.0、iPadOS 26.0、macOS 26.0、tvOS 26.0 和 visionOS 26.0。需注意,
BAAppGroupID、BAHasManagedAssetPacks和BAUsesAppleHosting在其余平台的 26.0 之外,各自都带有一条异常的 Mac Catalyst 16.0 记录;托管层的 iOS 26.0 下限依据的是AssetPackManager、ManagedDownloaderExtension和BAHasManagedAssetPacks,而不是非托管路径同样需要的BAAppGroupID。 ↩↩↩↩ -
Apple, Configuring an unmanaged Background Assets project, Background Assets. 以下内容的出处:Self-Hosted, Unmanaged 扩展类型、两个目标上的 App Groups 要求、安装与更新的下载流程,以及责任声明:”为自行托管的非托管资源创建清单文件是您的责任(格式由您自选),并由您的代码解析出 URL 和文件大小交给系统。”也是
BAManifestURL、BAInitialDownloadRestrictions、BADownloadAllowance与BAEssentialDownloadAllowance(压缩后体积)、BAMaxInstallSize与BAEssentialMaxInstallSize(未压缩体积)以及BADownloadDomainAllowList(DNS 格式域名,可用前导星号表示通配)的出处。BADownloaderExtension自 iOS 16.1、iPadOS 16.1、Mac Catalyst 16.1、macOS 13.0、tvOS 18.4 和 visionOS 2.4 起可用;BAManifestURL自 iOS 16.1 起可用。 ↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
Apple, setPreservationPriority(_:forTags:) 与 preservationPriority(forTag:), Foundation. 两者均自 iOS 9.0 引入,并在 iOS、iPadOS、Mac Catalyst、tvOS、visionOS 和 watchOS 上于 27.0 弃用。”向系统提示 bundle 内各组标记资源的相对清除顺序”一语的出处。 ↩↩↩↩↩
-
Apple, Downloading Apple-hosted asset packs, Background Assets,以及 Creating managed asset packs。以下内容的出处:Background Download 扩展模板及其 Apple-Hosted, Managed 类型、共享 App 组要求、三键属性列表配置以及”省略其余全部 Background Assets 信息属性列表键”的指示、
xcrun ba-package template与xcrun ba-package命令、清单键(assetPackID、downloadPolicy、含firstInstallation与subsequentUpdate的installationEventTypes、含file与directory的fileSelectors,以及platforms)、三种下载策略(essential、prefetch和onDemand)及其安装期行为、路径相对于打包目录解析的规则、合并命名空间(”系统会自动把您的所有资源包合并进一个共享命名空间,效果相当于把您的资源根目录原样粘贴到用户设备上重建一遍”)、内存映射Data读取及其文件描述符变体、上传渠道(Transporter、altool、iTMSTransporter 和 App Store Connect API),以及存储指示:”只要您的 App 处于安装状态,系统就不会自动移除您的资源包。因此,用完某个资源包后,请调用remove(assetPackWithID:)方法。”本文的下载示例同时调用了assetPack(withID:)(苹果可用性数据将其标记为 27.0 弃用)和ensureLocalAvailability(of:)(26.4 弃用,参见注 19)。 ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
Apple, Apple-hosted asset pack size limits, App Store Connect Help. 资源包总量 200 GB;资源包数量 200。以下内容的出处:”上传至 App Store Connect 中某个 App 记录的所有资源包的体积占用总和”、计算方法(取符合 TestFlight 或 App Store 分发条件的各版本中的最大体积,排除 Awaiting Upload、Processing、Failed 及已被完全取代的版本)、80% 邮件通知、”这些限制在您的 App 所提供的全部平台间共享”,以及归档行为——它”会从 App Store Connect 中移除某个资源包的全部版本,包括正在 TestFlight 中测试的版本和已在 App Store 上线的版本”。 ↩↩↩↩↩
-
Apple, Overview of Apple-hosted asset packs, App Store Connect Help. 以下内容的出处:四步流程(打包、上传、通过 TestFlight 测试、提交 App Review)、资源包独立于 App 构建版本,以及苹果托管的托管式资源所支持的平台列表:iOS 26+、iPadOS 26+、macOS 26+、tvOS 26+ 和 visionOS 26+。 ↩↩↩
-
Apple, ManagedDownloaderExtension, Background Assets. 协议,在所列六个平台上均自 iOS 26.0 起可用。为继承自
BADownloaderExtension的每一项要求提供默认实现,并警告不要实现这些继承要求,仅backgroundDownload(_:didReceive:)可选实现除外。 ↩↩↩↩↩ -
Apple, AssetPackManager, Background Assets. Actor,iOS 26.0、iPadOS 26.0、Mac Catalyst 26.0、macOS 26.0、tvOS 26.0 和 visionOS 26.0。以下内容的出处:选择加入说明(”当您的代码首次引用共享管理器时,Background Assets 即认为您的 App 选择加入了资源包的系统自动管理”)以及配对要求——采用管理器却不采用配套的托管式扩展协议,是”一个编程错误”。也是
checkForUpdates()(”从服务器获取最新的资源包信息,更新过期的资源包,并移除已作废的资源包”)以及remove(assetPackWithID:)、url(for:)(nonisolated,接受FilePath并返回URL)和statusUpdates(forAssetPackWithID:)的出处,这几个均未被弃用。AssetPack与ManagedBackgroundAssetsError具有相同的 iOS 26.0 可用性。该管理器中已弃用的成员,参见注 19。 ↩↩↩↩↩ -
Apple, StoreDownloaderExtension, StoreKit. 精化
ManagedDownloaderExtension的协议,可用于 iOS 26.0、iPadOS 26.0、macOS 26.0、tvOS 26.0 和 visionOS 26.0。 ↩ -
Apple, Testing asset packs locally, Background Assets. 以下内容的出处:HTTPS 要求、”钥匙串访问”根 CA 流程、Apple Configurator 描述文件的创建及逐台设备的安装与信任步骤、名称须为”有效 IP 地址、主机名或域名”并与服务器匹配的 SSL 叶证书、
xcrun ba-serve命令,以及开发者设置中的 URL 覆盖(iOS、iPadOS、tvOS 和 visionOS 上为”设置 > 开发者 > 开发覆盖”;macOS 上为xcrun ba-serve url-override)。 ↩↩ -
Apple, BAEssentialMaxInstallSize 与 BAMaxInstallSize, Information Property List 参考。
BAEssentialMaxInstallSize自 iOS 18.0 起,BAMaxInstallSize自 iOS 16.0 起。两者均载有:”App Store 会用此键在产品页面上展示您的 App 体积,因此请提供准确数值。若对资源做了压缩,此值请使用文件未压缩时的体积。不要虚报您所需的磁盘空间。”两者均被标为使用 Background Assets 的必需项。 ↩ -
AssetPackManager成员的苹果可用性元数据,于 2026 年 7 月 25 日读取自苹果文档 JSON。已弃用成员均自 iOS 26.0 引入:ensureLocalAvailability(of:) 于 26.4 弃用;status(ofAssetPackWithID:) 于 26.4 弃用,由status(relativeTo:)取代;assetPack(withID:) 于 27.0 弃用,附说明”请在管理器manifest属性的值上调用assetPack(withID:)“;allAssetPacks 于 27.0 弃用,由清单的assetPacks属性取代。自 iOS 27.0 引入并在当前 SDK 中标记为 beta 的替代符号:manifest、AssetPackManifest.assetPack(withID:)(同步,返回可选的AssetPack)以及 ensureLocalAvailability(of:requireLatestVersions:)。ensureLocalAvailability(of:requireLatestVersion:) 于 26.4 引入,未被弃用。苹果自家那篇讲苹果托管的演练文章至今仍在演示assetPack(withID:)与ensureLocalAvailability(of:)这两个已弃用调用——这一观察出自作者本人,依据是同日将文章正文与符号可用性作了比对。 ↩↩ -
作者于 2026 年 7 月 25 日对七个已发布项目所做的普查:Reps、Return、Banana List、Ace Citizenship、Water、ResumeGeni 和 Yawara。检索了全部 Swift、Objective-C、头文件、属性列表和
project.pbxproj文件(排除build、DerivedData、.build、Pods和.git),检索项包括NSBundleResourceRequest、beginAccessingResources、setPreservationPriority、On Demand Resources、任何ON_DEMAND_RESOURCES构建设置、knownAssetTags和ASSETCATALOG_COMPILER_*TAG设置。每个项目中每一种模式的匹配数均为零,Background Assets 符号的匹配数同样为零。资源目录总量以du统计全部.xcassets目录得出,排除构建产物、fastlane 截图和报告目录:Return 66.62 MB、Ace Citizenship 7.81 MB、Banana List 2.04 MB、Reps 1.66 MB、Water 0.04 MB、Yawara 0.01 MB。各project.pbxproj中读取的IPHONEOS_DEPLOYMENT_TARGET值:Reps 为 26.0 和 26.2,Return 为 26.1,Banana List 为 26.0,Water 为 26.0,Yawara 为 26.5,Ace Citizenship 各目标为 17.0、17.5 和 26.1。 ↩↩↩ -
Apple, Reducing download and storage demands with localized asset packs, Background Assets. 以下内容的出处:macOS 27、iOS 27、tvOS 27 和 visionOS 27 中为资源包新增的
language指定、BCP-47 标识符规则(仅限语言、地区和文字子标签,不含变体或扩展),以及 Xcode 27 模板中的language键。 ↩