你交上一个一切正常的版本,睡一觉醒来收到一份引用 5.1.1 ——“数据收集与存储”的拒信。理由可能是:App 收集了个人信息却没有隐私政策、政策与 App Store Connect 中声明的数据类型不一致,或者二进制请求的数据政策里压根没提。没有崩溃、没有功能损坏;审核员只是读了你的 Info.plist 用途描述、跑了一遍 App、看到它在调用分析 SDK,又发现你的隐私营养标签里写的是”未收集数据”。5.1.1 是 2025 年最高频的拒信理由,绝大多数情况都能追溯到声明与运行时行为之间的 6 种错位之一。
常见原因
按拒信中出现的频率排序。
1. 营养标签写”未收集数据”,但 SDK 在收集
你集成了 Firebase Analytics、Sentry、Adjust、Branch 或 Facebook SDK。按苹果的分类,每一个都属于”为分析收集数据”或”关联到用户”,但因为你自己的代码没碰用户数据,你在 App Store Connect 里直接勾了”我们不收集任何数据”。
如何识别:进入 App Store Connect → App 隐私。如果”你或第三方合作伙伴是否从此 App 中收集数据?“的答案是否,而你的 Podfile 或 SPM 清单里列着分析、崩溃上报、归因 SDK,那么标签就是错的。
2. 隐私政策 URL 返回 404、重定向或非公开
审核员会在审核期间点开这个链接。重定向到营销落地页、404、需要登录才能看的 noindex 页面、或者要求填邮箱才能看的 Notion 链接,都算”没有隐私政策”。
如何识别:用无痕窗口打开 App Store Connect → App 信息 → 隐私政策 URL 中填写的链接。如果点一次还看不到可读的政策正文,审核员就会标记。
3. 隐私政策正文没有列出你收集的数据类型
政策里写”我们为账号创建收集你的邮箱”,但 App 还把设备 ID、IP、崩溃日志发给 Sentry。审核员会把政策、营养标签、Info.plist 用途字符串交叉对照;任何一处声明了而政策正文里没写的数据类型都会触发 5.1.1。
如何识别:在政策页里 Cmd-F 搜你声明的每个数据类型 ——“设备标识符”、“崩溃”、“分析”、“广告”。任何一项搜不到都是漏点。
4. App 在显示有意义内容前就请求数据访问
你在第一屏启动页就弹相机、通讯录或定位授权。苹果要求授权弹窗必须出现在使用相关功能的上下文里 —— 用户真的在用到这个权限的功能时才弹。
如何识别:录制冷启动的前 30 秒。任何在用户点击相关功能前就出现的系统授权弹窗都有 5.1.1(同时也是 5.1.2)风险。
5. 账号删除缺失或藏得太深
自 2022 年 6 月 30 日起,任何包含账号注册的 App 必须提供应用内账号删除。把它藏在网页链接或”联系客服”表单后面会被以 5.1.1(v) 拒。
如何识别:在 App 内导航至 设置 → 账号。必须有清晰标记的删除账号入口,并且整个流程必须在 App 内完成 —— 不能是一个 mailto: 链接。
6. 用了 Required Reason API 却没声明 NSPrivacyAccessedAPITypes
自 2024 年 5 月 1 日起,苹果要求提交一份 PrivacyInfo.xcprivacy 清单,声明使用了”必填理由”API(UserDefaults、fileTimestamp、systemBootTime、diskSpace、activeKeyboards)。不带这份清单提交,或者清单里没有覆盖你的代码(或嵌入 SDK)调用的 API,会拿到 5.1.1 / ITMS-91053 拒信。
如何识别:在 build 里搜 PrivacyInfo.xcprivacy。如果文件不存在,或者没有覆盖到代码实际调用的 API,就等着被拒。
开始之前
- 从 App Store Connect → App 审核 → 信息中复制完整拒信原文,留意苹果引用的具体子条款(5.1.1(i)、(ii)、(v))。
- 在改动之前先录一份冷启动流程视频 —— 苹果有时会指向某个具体页面,你需要能对得上。
- 列出
Podfile.lock、Package.resolved或 framework 文件夹里所有的第三方 SDK。
需要收集的信息
- 当前隐私政策 URL,以及未登录访客看到的页面截图。
- App Store Connect 里的完整 App 隐私答案(把问卷导出成清单)。
Info.plist中所有的NSXxxUsageDescription字符串。- 每个第三方 SDK 的数据收集声明(主流 SDK 如 Firebase、Sentry、Adjust 都会发布)。
- App 是否有账号注册,以及删除账号按钮在哪。
修复步骤
顺序:先补齐实质性缺口,再回复审核员。
步骤 1:跑一遍 SDK 数据审计
对每一个 SDK,记录它收集了什么:
grep -RE "Firebase|Sentry|Branch|Adjust|Facebook|Amplitude|Mixpanel|OneSignal" \
Podfile Podfile.lock Package.resolved 2>/dev/null
对每一个命中的 SDK,打开它的”App Store Privacy”文档页(主流 SDK 都有一份)。记下数据类型以及是否关联到用户。
步骤 2:重做 App 隐私营养标签
在 App Store Connect → App 隐私 → 编辑。把每个分类都走一遍:
- 标识符:几乎每个分析 SDK 都收集设备 ID。
- 诊断:崩溃数据和性能数据由 Sentry、Firebase Crashlytics、Bugsnag 收集。
- 使用数据:产品交互由 Mixpanel、Amplitude、GA4 收集。
- 联系信息:只要有账号注册,就会收集邮箱。
如果你存了一个用户 ID 一起上报,就标关联到用户;如果 SDK 配置成匿名,就标未关联。如果用了 IDFA 或做跨 App/站点画像,就标追踪。
步骤 3:重写隐私政策与声明对齐
加一张”我们收集的数据”表格,一行一个类型,写明用途和接收方。最少应包含以下章节:
- 收集的数据类型(与营养标签一一对应)
- 收集目的(分析、广告、App 功能等)
- 数据接收的第三方(具名,并附上对方隐私页面链接)
- 数据保留周期
- 用户权利:访问、删除、导出、联系邮箱
- 如适用,儿童隐私(COPPA)声明
托管在公开的 HTTPS URL 上,不能有登录墙。自己域名上的静态 HTML 或 GitHub Pages 都可以;Notion 公开页能用但加载慢。
步骤 4:为 Required Reason API 添加 PrivacyInfo.xcprivacy
Xcode 中:File → New → File → App Privacy File。为每个必填理由 API 添加条目。UserDefaults 示例:
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string>
</array>
</dict>
</array>
NSPrivacyAccessedAPICategoryFileTimestamp、SystemBootTime、DiskSpace、ActiveKeyboards 同理逐项补全。SDK 厂商会在 framework 内自带 .xcprivacy;确认最终归档里它们都还在。
步骤 5:实现应用内账号删除
如果有账号体系,在设置里加一个 destructive 按钮:
Button(role: .destructive) {
showDeleteConfirmation = true
} label: {
Text("Delete Account")
}
.confirmationDialog("Delete account permanently?", isPresented: $showDeleteConfirmation) {
Button("Delete", role: .destructive) { Task { await deleteAccount() } }
Button("Cancel", role: .cancel) { }
}
deleteAccount() 必须真的在后端完成删除(或在 30 天内排队删除),登出用户,并清掉本地数据。一个 mailto: 链接不算。
步骤 6:把权限弹窗移到上下文中
把每个 requestAuthorization / requestWhenInUseAuthorization 调用都挪到真正需要那个功能的用户点击之后。系统弹窗出现之前,先用一个 pre-prompt 用大白话告诉用户为什么需要这个权限。
步骤 7:通过 Resolution Center 用结构化回复
在 App Store Connect → App 审核 → 信息中,写一份按点回复:
您好,
感谢就 5.1.1 给出的详细反馈。
针对每一点我们已做出以下修改:
1. App 隐私营养标签已更新为:
- 设备 ID(诊断,关联到用户),由 Firebase Analytics 收集
- 崩溃数据(诊断,未关联),由 Sentry 收集
2. https://example.com/privacy 上的隐私政策已重写,列出每一种
数据类型、第三方接收方和保留周期。
3. 1.4.2 (8203) 版本已加入 PrivacyInfo.xcprivacy,覆盖
UserDefaults 与 FileTimestamp 的必填理由。
4. 应用内账号删除入口现位于 设置 > 账号 > 删除账号
(随附演示视频)。
5. 相机权限弹窗已从首启动流程移至"扫描文档"按钮的
点击上下文中。
新版本 1.4.2 (8203) 已进入审核。如仍有未覆盖之处请告知。
带具体新 build 号、按点回应的结构化回复通常会在 24-48 小时内复审。
验证
- 新隐私政策 URL 在无痕窗口里能完整加载,不重定向、不需要登录。
- 你声明的 App 隐私答案与每个 SDK 公布的清单加上你自己的收集行为完全匹配。
- 冷启动 App:用户点到相关功能之前没有任何系统授权弹窗出现。
设置 → 账号 → 删除账号能完成删除并登出。- 归档包里包含
PrivacyInfo.xcprivacy,覆盖二进制实际调用到的每个必填理由 API。
长期预防
- 把隐私声明当成 CI 步骤:
Podfile中新增任意 SDK 都触发”是否同步更新了 App 隐私与政策文本?“检查清单。 - 维护一份唯一来源的电子表格,记录 SDK → 数据类型 → 关联/未关联 → 政策章节的映射。
- 每次大版本前重新跑一遍 SDK 审计;SDK 会悄悄加追踪。
- 订阅 developer.apple.com 的隐私新闻,避免 2024 年 5 月必填理由 API 这类时间点踩坑。
- 自研的每个 framework 都附带一份
PrivacyInfo.xcprivacy,即便不对外发布。 - 隐私政策保留一份带”最后更新日期”的公开版本历史 —— 审核员和欧盟用户都会看。
常见坑
- 抄别家的隐私政策但忘了改 SDK 名字;审核员一眼看出分析厂商对不上。
- 因为没存姓名就全部标”未关联到用户”—— 苹果的”关联”定义包含任何持久设备 ID 加用户行为的组合。
- 把删除账号藏在一个需要邮件联系客服的确认页背后,苹果认为这不是应用内删除。
- 忘了 TestFlight 一旦涉及外部测试者,隐私政策 URL 同样必须有效。
- 主 App 加了
PrivacyInfo.xcprivacy,但 vendor 的 XCFramework 没有 —— SDK 的清单缺失就会触发 ITMS-91053。 - 在政策里写了一些其实并没收集的数据类型,想着多写点更安全 —— 审核员也可能因为”过度披露引起用户混淆”拒你。
FAQ
Q:我的政策放在 Notion 上,会有问题吗?
Notion 公开页能用,但加载慢,有时会先显示一个看上去像出错的 loading 壳。最稳妥的做法是自己域名上挂一份快速的静态页;放在 Notion 上的一句话政策是我们见过最常见的 5.1.1 触发点。
Q:我自己什么数据都不收集,只用 Crashlytics 报崩溃。也需要声明吗?
需要。Crashlytics 收集设备 ID、崩溃日志、性能数据;这些都必须在 App 隐私里声明为”诊断”,并在政策里列出。第三方的收集仍然算你的 App 的收集。
Q:苹果具体引用了 5.1.1(v),那是什么?
那个子条款是账号删除。按上文加上应用内的删除账号流程,单这一项修好就能解决 (v)。
Q:如果我觉得拒信不对能申诉吗?
可以,通过 Resolution Center 或 App Review Board 申诉。但 5.1.1 的申诉几乎都不会成功,除非你能证明审核员看错了二进制;直接把底层问题修了重新提交更快。回复策略可以参考App Review 2.1 信息不足。
Q:我没有账号、没有 SDK,还需要隐私政策吗?
需要。任何收集用户输入、使用任何分析(包括苹果自家的)、或访问任何设备标识符的 App 都需要政策。“完全不需要隐私政策”的门槛是一个零网络调用、纯只读的静态 App。