App 因 5.1.1 隐私条款被拒:如何重新提交

苹果援引 5.1.1 时,通常是你的隐私政策、App 隐私标签或同意流程与二进制实际运行行为不一致。逐项诊断 6 种成因并重新提交。

你交上一个一切正常的版本,睡一觉醒来收到一份引用 5.1.1 ——“数据收集与存储”的拒信。理由可能是:App 收集了个人信息却没有隐私政策、政策与 App Store Connect 中声明的数据类型不一致,或者二进制请求的数据政策里压根没提。没有崩溃、没有功能损坏;审核员只是读了你的 Info.plist 用途描述、跑了一遍 App、看到它在调用分析 SDK,又发现你的 App 隐私标签里写的是”未收集数据”(Data Not Collected)。5.1.1 是最高频的拒信理由之一,截至 2026 年 6 月,绝大多数情况都能追溯到声明与运行时行为之间的 6 种错位之一。

最快的修法:先在 Resolution Center 里看苹果具体引用了哪个子条款(它会告诉你命中了 6 种成因里的哪一种),让二进制和你的 App 隐私标签对齐,然后带上新 build 号按点回复。最常见的触发点是某个分析或崩溃上报 SDK(Firebase、Sentry、Crashlytics)在收集数据,而你的标签却写着”未收集数据”。如果你正是这种情况,直接跳到步骤 2

你属于哪一种成因?

把苹果引用的子条款对应到修法。苹果当前的子条款编号(截至 2026 年 6 月):

苹果引用 / 写的内容成因跳转
”与 App Privacy 不一致” 或 写着”未收集数据”但有 SDK标签与 SDK 不一致成因 1,步骤 2
”隐私政策 URL… 无法访问” / 404 / 登录墙政策 URL 打不开成因 2,步骤 3
政策正文缺了某个已声明的数据类型政策与标签不一致成因 3,步骤 3
5.1.1(iii) 数据最小化 / 上下文之前就请求权限弹窗脱离上下文成因 4,步骤 6
5.1.1(v) Account Sign-In没有应用内账号删除成因 5,步骤 5
ITMS-91053 / “Missing API declaration”没有 PrivacyInfo.xcprivacy 清单成因 6,步骤 4

常见原因

按拒信中出现的频率排序。

1. App 隐私标签写”未收集数据”,但 SDK 在收集

你集成了 Firebase Analytics、Sentry、Adjust、Branch 或 Facebook SDK。按苹果的分类,每一个都属于”为分析收集数据”或”关联到你”(Linked to You),但因为你自己的代码没碰用户数据,你在 App Store Connect 里直接勾了”我们不收集任何数据”。苹果会把第三方的收集算作你 App 的收集。

如何识别:进入 App Store Connect,打开你的 App,再进 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)“Account Sign-In”。把删除藏在网页链接或”联系客服”表单后面会被以 5.1.1(v) 拒。苹果要求你删除整条账号记录及相关个人数据,仅仅停用或禁用不行;应用内必须有一个发起删除的入口。

如何识别:在 App 内导航至 设置,再到 账号。必须有清晰标记的删除账号入口,并且在 App 内发起删除请求 —— 不能是一个 mailto: 链接,也不能是”我们会给你发邮件”的表单。(高度受监管行业的 App 可以按 5.1.1(ix) 加一个客服确认环节,但应用内的入口仍然必须有。)

6. 用了 Required Reason API 却没声明 NSPrivacyAccessedAPITypes

自 2024 年 5 月 1 日起,苹果要求提交一份 PrivacyInfo.xcprivacy 清单,声明使用了”必填理由”API(UserDefaultsfileTimestampsystemBootTimediskSpaceactiveKeyboards)。不带这份清单提交,或者清单里没有覆盖你的代码(或嵌入 SDK)调用的 API,会拿到 5.1.1 / ITMS-91053 拒信。

如何识别:在 build 里搜 PrivacyInfo.xcprivacy。如果文件不存在,或者没有覆盖到代码实际调用的 API,就等着被拒。

开始之前

  • 从 App Store Connect → App 审核 → 信息中复制完整拒信原文,留意苹果引用的具体子条款(5.1.1(i)、(ii)、(v))。
  • 在改动之前先录一份冷启动流程视频 —— 苹果有时会指向某个具体页面,你需要能对得上。
  • 列出 Podfile.lockPackage.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,进 App 隐私,点编辑。把苹果列出的每个分类都走一遍:

  • 标识符(Identifiers):几乎每个分析 SDK 都收集设备 ID(和用户 ID)。
  • 诊断(Diagnostics):崩溃数据和性能数据由 Sentry、Firebase Crashlytics、Bugsnag 收集。
  • 使用数据(Usage Data):产品交互由 Mixpanel、Amplitude、GA4 收集。
  • 联系信息(Contact Info):只要有账号注册,就会收集邮箱。

苹果会针对每个声明的数据类型问你它如何被使用。如果它绑定到了用户身份(你存了用户 ID 或账号一起上报),就标关联到你(Linked to You);如果 SDK 配置成匿名、数据无法回溯到个人,就标未关联到你(Not Linked to You);如果用了 IDFA 或做跨 App、跨站点画像,就标用于追踪你(Used to Track You)。标了”用于追踪你”还要求运行时弹出 App Tracking Transparency 授权 —— 参见 ATT 追踪弹窗不出现

步骤 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>

你代码或任意 SDK 用到的每个必填理由 API 分类都同理逐项补全。五个分类及其最常用的批准理由码(已对照苹果 “Describing use of required reason API” 文档核实,截至 2026 年 6 月):

API 分类NSPrivacyAccessedAPIType 取值常用理由码
用户偏好NSPrivacyAccessedAPICategoryUserDefaultsCA92.1
文件时间戳NSPrivacyAccessedAPICategoryFileTimestampC617.13B52.1
系统启动时间NSPrivacyAccessedAPICategorySystemBootTime35F9.1
磁盘空间NSPrivacyAccessedAPICategoryDiskSpaceE174.17D9E.1
已启用键盘NSPrivacyAccessedAPICategoryActiveKeyboards54BD.1

选与你实际用法相符的理由;如果声明的理由与代码路径对不上,苹果同样会拒。完整分类与批准码见苹果的 Describing use of required reason API 文档。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() 必须真的在后端完成删除(或在一个合理、已披露的周期内排队删除),登出用户,并清掉本地数据。一个 mailto: 链接不算。苹果的 Offering account deletion in your app 页面是判断”什么才算数”的权威参考。

步骤 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:用户点到相关功能之前没有任何系统授权弹窗出现。
  • 在 App 内 设置、账号、删除账号 确实能完成删除并登出用户。
  • 从归档生成 Privacy Report:在 Xcode 打开 Organizer,右键归档,选 Generate Privacy Report。这份 PDF 会列出整个二进制及打包 SDK 涉及的每个数据类型和必填理由 API。确认它与你的 App 隐私标签一致,且没有 SDK 显示清单缺失。
  • 确认归档包里包含 PrivacyInfo.xcprivacy,覆盖二进制实际调用到的每个必填理由 API。

长期预防

  • 把隐私声明当成 CI 步骤:Podfile 中新增任意 SDK 都触发”是否同步更新了 App 隐私与政策文本?“检查清单。
  • 维护一份唯一来源的电子表格,记录 SDK → 数据类型 → 关联/未关联 → 政策章节的映射。
  • 每次大版本前重新跑一遍 SDK 审计;SDK 会悄悄加追踪。
  • 订阅 developer.apple.com 的隐私新闻,避免 2024 年 5 月 1 日必填理由 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),那是什么?

5.1.1(v) 是”Account Sign-In”,它带有应用内账号删除的要求。按上文加上应用内的删除账号流程,单这一项修好就能解决 (v)。注意它必须删除账号记录,而不只是停用。

Q:我的 App 是银行 / 医疗 / 加密货币类,删除需要身份核验。能把用户引到客服吗?

部分可以。按 5.1.1(ix),高度受监管行业(银行、医疗、博彩、合法大麻、航空、加密货币交易所)的 App 可以加一个客服环节来确认并完成删除。但你仍然需要一个应用内入口来发起这个请求 —— 不能让客服成为唯一路径。不属于这些行业的 App 不能要求打电话或发邮件才能删除。

Q:如果我觉得拒信不对能申诉吗?

可以,通过 Resolution Center 或 App Review Board 申诉。但 5.1.1 的申诉几乎都不会成功,除非你能证明审核员看错了二进制;直接把底层问题修了重新提交更快。回复策略可以参考App Review 2.1 信息不足

Q:我没有账号、没有 SDK,还需要隐私政策吗?

需要。任何收集用户输入、使用任何分析(包括苹果自家的)、或访问任何设备标识符的 App 都需要政策。“完全不需要隐私政策”的门槛是一个零网络调用、纯只读的静态 App。

相关阅读

标签: #排查 #App Store #App 审核 #privacy #guideline-5-1-1