Xcode 27 PrivacyInfo.xcprivacy 未进 Archive?2026 排查
📋 本文目录
症状:工程里能看到 PrivacyInfo.xcprivacy,提交时却提示 Archive 缺失或清单无效。
最快解法:先检查最终 .xcarchive 中的应用和依赖 bundle,再追查 target 资源配置、Swift Package 声明或 SDK 包结构;文件存在仍不代表内容有效。Apple 的隐私清单文档说明,清单位置依产品类型而定,且键和值必须有效。
谁该看:本地构建正常,但归档缺少自有清单或提交校验异常的 iOS 开发者。
需要确认 Swift Package 或二进制 SDK 是否带入清单的移动端 CI 工程师。
要复现远程 Mac 归档差异,并建立可审计验收记录的 DevOps 工程师。
最后更新于 2026 年 10 月 5 日;规则与路径核对自 Apple 隐私清单文档、TN3181、第三方 SDK 要求页及 Xcode 官方资料。
Xcode 27 PrivacyInfo.xcprivacy Archive:先区分缺文件与文件无效
标题中的 Xcode 27 是当前工具链背景,不应据此推断 Apple 改变了隐私清单规则。Apple 的 Xcode 27 官方页面介绍的是该版本的工具与功能;清单要不要放、放在哪里、内容是否合法,仍应按 Apple 现行隐私文档核对。
先看归档产物,不要只看源码目录或 Xcode 导航器。下表按“最早能证明什么”分流,评级是排查优先级,不是 Apple 的官方判定:
| 现象 | 首要检查位置 | 先排除什么 | 排查优先级 |
|---|---|---|---|
| 应用自身清单缺失 | .xcarchive 内的应用 bundle 根目录 |
文件未加入正确 target、资源未复制 | 高 |
| Swift Package 清单缺失 | 包生成的资源 bundle,再看应用归档 | 仅放在 Sources,未声明为资源 |
高 |
| SDK 清单缺失 | SDK 的 framework 或 XCFramework bundle,再看归档 | SDK 版本未提供清单、归档未保留 bundle | 高 |
| 清单在归档中但提交报错 | 报错指定路径、清单键值、隐私报告 | plist 格式错误或声明值不合法 | 高 |
| 本地有、远程 CI 没有 | 同提交的 Xcode、配置、依赖解析和归档 | 构建输入不同,或 CI 使用了另一 Scheme | 中 |
iOS 应用清单通常位于 .app bundle 根目录;iOS framework 的清单位于 .framework bundle 根目录。macOS 应用和 framework 的路径不同。不要把一种产品的目录规则套用到另一种产品上;可对照 Apple 的按平台和 bundle 类型排列内容的说明,并以归档实际结构为准。
应用 target:源码有文件,Archive 里为什么没有?
若你问的是为什么 PrivacyInfo.xcprivacy 没进入 iOS Archive,先检查归档内最终 .app,不要先改清单内容。文件可能存在于仓库,却没有被当前归档 target 当作资源复制;也可能配置在另一个 target,或只加入了不参与发布的构建配置。
在 macOS 终端中,将占位符替换成实际归档路径和应用名称:
ARCHIVE="/path/to/Build.xcarchive"
APP="$ARCHIVE/Products/Applications/YourApp.app"
find "$APP" -name 'PrivacyInfo.xcprivacy' -print
如果应用自己的清单应在根目录,检查明确路径:
test -f "$APP/PrivacyInfo.xcprivacy" \
&& echo "应用清单存在" \
|| echo "应用根目录未找到清单"
检查失败后,再回到工程设置逐项核对:
- 在 Xcode 中选中清单文件,确认它加入的是实际构建应用的 target,而非测试 target、扩展 target 或另一个应用 target。
- 检查 Build Phases 的 Copy Bundle Resources,确认当前归档配置确实会复制该资源。
- 确认 Archive 使用的 Scheme、Build Configuration 与日常调试时一致。只比较源码文件,不比较 Scheme 和配置,会漏掉“调试有、归档无”的差异。
- 使用同一个 Scheme 重新执行 Archive,再检查新产物;旧归档不会因为你修改了工程设置而自动更新。
- 同时记录目标应用路径与搜索结果,避免在扩展或嵌套 bundle 中找到同名清单,就误判应用主 bundle 已包含。
若你采用脚本构建,保存 xcodebuild 的完整日志及 Archive 输出位置。这样才能分辨资源阶段未复制、产物路径看错,还是验收脚本检查了另一份归档。
Swift Package:怎样确认清单进入最终应用?
Swift Package 的清单需要作为包资源处理。文件仅仅放在 Sources 下,并不能证明它已经进入依赖包,更不能证明它最后出现在应用 Archive 中。Apple 的隐私清单添加说明要求将清单声明为 package resource;Swift Package 资源指南也说明资源按 target 管理。
先检查包的 Package.swift 中对应 target 是否声明该资源,例如:
.target(
name: "LibraryTarget",
resources: [
.process("PrivacyInfo.xcprivacy")
]
)
如果清单放在资源子目录,就让声明路径与实际目录一致,例如 .process("Resources")。注意:这段示例只展示资源声明形式,包的 target 名和目录都要按你的项目替换。也不要因为包的源码文件夹里找到了清单,就跳过产物检查。
接着分两段验:
- 包侧:检查构建生成的资源 bundle 中是否有
PrivacyInfo.xcprivacy。若包侧没有,优先核对包 target、文件路径与资源声明。 - 应用侧:在
.xcarchive内搜索清单,并确认它位于依赖包自己的 bundle 结构中。若包侧产物存在、归档侧没有,再查应用集成方式、依赖解析与归档资源阶段。 - 二进制包:若依赖以 XCFramework 分发,分别检查其实际使用的平台 slice 对应的 framework bundle;不要只检查仓库中未参与本次构建的另一个 slice。
这样可以把“包没有打出清单”和“包有清单但归档没有保留”分开,不会把所有问题都归咎于应用主 target。
第三方 SDK:缺清单与应用主清单不是一回事
对第三方 SDK,先确认供应方是否提供自己的清单,再检查二进制 framework 或 XCFramework 内是否包含它。随后回到最终 Archive,确认该 SDK 的 bundle 结构仍在、清单没有在复制或打包过程中丢失。
如果报错路径指向 SDK bundle,而应用自己的 PrivacyInfo.xcprivacy 已存在,不要把 SDK 的行为塞进应用主清单来“补齐”文件。Apple 说明,第三方 SDK 应提供反映其自身数据收集和 API 使用情况的清单;应用主清单不需要代替链接进来的 SDK 声明其收集的数据。(Apple 的数据使用说明)
责任也要分清:应用集成方应确认使用的 SDK 版本、链接方式和归档产物;如果 SDK 清单缺失或无效,应向 SDK 供应方索取修正版,而不是擅自伪造 SDK 的隐私声明。对于 Apple 指定的 SDK,按当前第三方 SDK 要求名单逐项核对;不要用旧的依赖清单推断当前提交要求。
本地有、远程 Mac CI 没有:用同一提交复现差异
远程 Mac CI 的 Archive 与本地不同,不等于远程机器“自动删掉了文件”。更常见的检查方向是:构建使用的 Xcode 不同、Scheme 或配置不同、依赖解析结果不同,或流水线检查了错误的产物路径。先把输入固定,再比较结果。
第一轮:核对构建输入
在本地和 CI 对同一提交分别保存以下信息:
xcode-select -p
xcodebuild -version
git rev-parse HEAD
另行归档本次构建使用的 Scheme、Archive 配置、依赖解析文件及 xcodebuild 日志。若 CI 重新解析依赖,而本地使用已解析的版本,比较的就不是同一组构建输入;若活动 Xcode 不同,也不能只凭工作区相同认定两次 Archive 等价。
第二轮:核对最终产物
保存 .xcarchive 后,先确认实际应用路径,再搜索清单:
find "/path/to/Build.xcarchive/Products/Applications" \
-name 'PrivacyInfo.xcprivacy' -print
搜索结果要连同完整路径留档。它能区分应用根目录、扩展 bundle、Swift Package 资源 bundle 和 SDK framework,但“搜索到文件”本身不能证明它的位置正确或内容有效。
第三轮:复现而非只比工作区
在相同提交、相同 Scheme、相同归档配置和相同依赖解析结果下重跑一次 Archive。若本地与 CI 产物仍不同,把两边的归档日志、依赖版本和 find 输出并排比较。这样才能判断问题来自资源配置,还是 CI 的环境或构建输入差异。
需要固定 macOS 归档环境时,你可以评估 MacDate 的远程 Mac 环境;它可以提供远程 macOS 构建节点,但不会替你验证清单内容、target 配置或 Archive 结构。
清单已存在却仍报错:转查格式和值
文件已进入正确 bundle,却仍被 App Store Connect 拒绝,排查重点就从“是否打包”切换到“内容是否合法”。常见方向包括 plist 格式错误、键值类型不匹配、必需理由 API 的类别或理由值无效,以及跟踪相关字段组合不符合要求。
先对源码中的清单运行 Apple TN3181 说明的格式检查:
plutil -lint "/path/to/PrivacyInfo.xcprivacy"
plutil -lint 通过,只能说明 plist 格式可解析,不代表所有键和值都符合 Apple 的清单规则。将提交报错中的具体文件路径,与归档中的同一路径对应起来,再根据 TN3181:无效隐私清单排查检查对应字段;涉及必需理由 API 时,对照 Apple 的理由 API 声明说明。
你还可以在 Xcode Organizer 为 Archive 生成隐私报告,核对应用及依赖 SDK 汇总出的隐私信息。报告有助于复核声明,但不能取代对原始 bundle 路径、清单内容及 SDK 版本的检查。Apple 在隐私数据使用文档中列出了从归档生成报告的入口。
不要直接修改已经归档的 .app 内文件来绕过问题。归档产物中的文件变更会使签名校验受到影响;应回到应用或 SDK 的构建源修正,再重新构建、归档与验收。若错误来自 SDK,优先更新至供应方修复版本,并重做完整归档。
按证据选择下一步:归档验收分支
下面这组条件用于值班分流,不是 Apple 的合规评分:
- 若应用 bundle 根目录没有清单,则回到应用 target、Build Phases 和 Archive Scheme;不要先改 SDK。
- 若 Swift Package 资源 bundle 没有清单,则核对包 target 的资源声明和路径;如果包侧本来就没有,再检查依赖版本或向维护方确认。
- 若 SDK bundle 缺清单或清单无效,则核对 Apple 当前要求及 SDK 供应方版本;不要由应用主清单代填 SDK 声明。
- 若所有预期 bundle 都能找到清单,但 App Store Connect 仍报错,则根据报错路径检查该文件的 plist 格式、键和值及必需理由 API 声明。
- 若本地与远程 Mac CI 结果不同,则先统一提交、Xcode、Scheme、配置和依赖解析;统一后仍不一致,再追查资源复制日志与归档路径。
- 若归档内路径正确、内容校验通过且隐私报告符合预期,则保留归档、日志和检查输出作为发布验收证据,并按 Apple 当前提交说明继续处理。
建议把这套验收记录作为 CI 发布门禁的输入:至少保存提交标识、活动 Xcode、依赖解析结果、归档路径、清单搜索结果、plutil 检查结果和隐私报告。这样后续有人只看到“工程里有文件”时,你仍能给出最终产物中的可复核证据。
如果你目前靠本地 Mac 临时手动归档,常见隐患是构建输入不易复现、机器离线时流水线中断、依赖和产物记录分散;如果只用 Linux CI,则无法直接完成 Xcode Archive。需要持续稳定的 macOS 归档节点时,可对比自购 Mac mini 与按需远程环境;购买决策可先看这份 Mac mini 价格指南。对偶发发布或需要隔离复现的任务,租用 MacDate 的远程 Mac 能让你在真实 macOS 环境里复跑 Archive;若工作负载长期高频、依赖物理接口或需要本地低延迟操作,自购设备可能更合适。