修复 App 隐私问卷被拒 / 不一致

App Store Connect 标你的隐私 nutrition 标签与 App 行为不一致。最快的修法:建一份 SDK 到数据类型的清单,逐项把问卷答案对齐后再重交。

App Store Connect 里填完隐私问卷、提交了 build,第二天状态变成 Metadata Rejected,附一句 “the data collection practices you described do not match the data your app collects”。有时审核员会更具体,比如 “the app appears to collect Device ID for tracking, but Tracking is not declared”,有时只给一句泛泛的 “please review your responses”

最快的修法(覆盖多数情况):列出 build 里的每个 SDK,去各家厂商的隐私页查它收什么数据,然后让 App Store Connect 里的答案逐项对上——包括 “Linked to User” 和 “Used for Tracking” 这两个子开关。大约 80% 的此类拒回都是漏报了某个 analytics 或广告 SDK(下面的原因 #1 或 #2)。改问卷会立即生效,不需要重新打包,除非拒回同时也点了 binary。

Apple 会从三个维度比对你的答案:(a)审核员对 binary 跑静态分析的结果,(b)IPA 里检测到的 SDK,(c)你的 PrivacyInfo.xcprivacy 以及每个打进包里的 SDK manifest 所声明的收集行为。任何一条对不上就触发拒回。

注(截至 2026 年 6 月):答案本身没变,但 Apple 改版了 App Privacy 编辑器——首次填写的按钮现在叫 Get Started,改完后要点 Publish(不再只是 Save)。能编辑隐私的角色现在多了 App Manager,不再只有 Account Holder 和 Admin。具体步骤见下文。

你属于哪一类?

动手前,先把审核员的原话对到一个原因上。下面按命中率排序,多数 App 中枪 #1 或 #2。

审核员原话里有最可能的原因修复章节
”do not match the data your app collects”(泛泛)#1 漏报 SDKStep 1-2
”collect Device ID for tracking, but Tracking is not declared”#2 IDFA / ATT 不一致#2 + Step 2.4
”Linked to the User” / “Used to Track” 对不上#3 子项Step 2.3-2.4
ITMS-91053 / ITMS-91056(邮件,不在 Resolution Center)#4 Required Reason APIStep 3
某个具体 SDK 的 “missing privacy manifest” / “signature”#5 SDK manifest / 签名#5
明确提到 “privacy policy”#7 政策矛盾Step 4

常见原因

1. 第三方 SDK 收了你忘申报的数据

Analytics(Firebase / Amplitude / Mixpanel)、广告(AdMob / Meta Audience Network)、崩溃(Sentry / Crashlytics)、归因(Adjust / AppsFlyer / Branch)都会替你收数据。每家厂商的”数据类型”在它的隐私文档里都列着,但要靠你手动汇总到你的 nutrition 标签里。

如何判断:打开 Podfile.lockPackage.resolved,列出所有依赖,逐个去厂商隐私页(比如 firebase.google.com/docs/ios/app-store-data-collection)对照,差异即缺漏项。

2. 申报”未收集”但 SDK 证明在收

最高频版本:你勾了”不收集 Device ID”,但 AdMob 或 Meta SDK 在用户授予 ATT 后会读 IDFA。Apple 的静态扫描抓到 ASIdentifierManager 调用,答题立马翻车。

如何判断:扫 IPA 符号:nm -gU YourApp.app/YourApp | grep -i "ASIdentifierManager\|advertisingIdentifier"。有命中就说明 IDFA 链路可达,必须申报。

这里有个出名的死循环:如果审核员说你的声明仍然显示在追踪、而你以为已经去掉了,真正的根源通常是 IDFA / ATT 框架还链在包里。只要 AppTrackingTransparency 还在,App Store Connect 就不允许你把 Device ID 设成”收集但不追踪”。如果你确实不追踪,靠谱的修法是彻底移除 IDFA 代码路径(用只在内存里、绝不碰 advertisingIdentifier 的会话级 analytics),而不是反复切换答案——然后把 Device ID 重新声明为不收集。

3. “Linked to User” / “Used for Tracking” 子项漏选

每个数据类型有两个跟问:是否关联用户身份、是否用于 tracking(跨 App / 跨 Web)。很多人答对了顶层类型却漏了子项。Apple 把 SDK manifest 和你的子答案一比对,发现矛盾就拒。

如何判断:App Store Connect → App Privacy → 对每个数据类型,两个 toggle 都要和 SDK 文档对上。

4. PrivacyInfo.xcprivacy 没声明 Required Reason API

从 2024 年 5 月 1 日起,某些 API(UserDefaults、文件时间戳、系统启动时间、磁盘空间、活跃键盘)必须在 PrivacyInfo.xcprivacy 里声明用途。漏了会触发独立但相关的拒回码:ITMS-91053(“Missing API declaration”)或 ITMS-91056(“Invalid privacy manifest”)。这类提示通常在上传时以邮件形式发来,发生在正式审核之前,所以哪怕状态还是 “Waiting for Review” 也要查收件箱。

如何判断:Xcode → 你的 target → Build Phases → 看资源里有没有 PrivacyInfo.xcprivacy。打开它,确认 NSPrivacyAccessedAPITypes 覆盖了你的代码或打进包的 SDK 用到的所有 Required Reason API。

5. 列表内的某个 SDK 缺隐私 manifest 或签名

从 2024 年 5 月 1 日起,只要你新增(或在更新里新增)了 Apple 常用第三方 SDK 列表 上的 SDK——大约 80 个,包含 Firebase 全家桶、Facebook / Meta SDK、GoogleSignIn、Alamofire、RealmSwift、SDWebImage 等——该 SDK 就必须自带隐私 manifest、声明 required reasons,并且(作为 binary / XCFramework 依赖时)带有效的代码签名。否则 Apple 不接受这个 build,拒回会点名该 SDK。列表内 SDK 的任意版本,以及任何重新打包它们的库,都算在内。

如何判断:审核员邮件或 Resolution Center 留言会点名该 SDK(“missing privacy manifest” 或 “signature”)。修法是把该 SDK 升到厂商已合规、带隐私 manifest 的版本(多数主流 SDK 在 2024 年都发了);不要替别人的 binary 手写 manifest。

6. 联系方式 / 健康 / 财务数据整组漏报

带登录的 App 会收 Email 和 Name;带分享的会收 “User Content”;带订阅的会收 “Purchase History”。常因”感觉太显然不用勾”被拒。

7. 隐私政策 URL 和问卷矛盾

审核员打开你的政策 URL,看到提到 Google Analytics,但问卷写”无 analytics”。即便 SDK 没打进 binary,Apple 也会标矛盾。

动手前先确认

  • 弄清拒回到底是问卷、build、还是两者——文案在 App Store Connect 里不同。
  • 完整记下审核员原文及 ITMS 码(某些代码必须精确回应)。
  • 改之前先把当前问卷答案截图全留底,Apple 不保留历史版本。
  • 确认你的 App Store Connect 角色是 Account HolderAdminApp Manager;Developer 角色改不了 Privacy(Marketing 角色只能改隐私政策 URL)。截至 2026 年 6 月,App Manager 是能编辑问卷的最低角色。

需要收集的信息

  • 审核员完整原文 + 所有 ITMS-91xxx 码。
  • 所有直接 / 间接依赖列表(Podfile.lock / Package.resolved / 手动集成)+ 版本号。
  • strings YourApp.app/YourApp | grep -i "tracking\|advertising\|idfa" 的输出。
  • 当前隐私政策 URL,以及里面提到数据用途的具体段落。
  • 出问题的 build 号 + 提交时间。

最短修复路径

Step 1:建 SDK 清单

对每个直接和间接依赖:

# CocoaPods
cat Podfile.lock | grep -E "^  - " | sort -u

# SPM
cat YourApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved | jq '.pins[].identity'

逐项找厂商的 “App Store Connect privacy guide” 文档,建表:

SDK数据类型Linked to userUsed for tracking文档 URL
Firebase AnalyticsIdentifiers, Usage DataYesNofirebase.google.com/…/data-collection
AdMobIdentifiers, DiagnosticsYesYesdevelopers.google.com/admob/…/privacy

Step 2:把表回填到 App Store Connect

App Store Connect → Apps → 你的 App → 侧栏 App Privacy。从没填过就点 Get Started,否则点 “Data Types” 旁的 Edit。对每个数据类型:

  1. 选 “Yes, we collect this data.”
  2. 选所有用途(Analytics、App Functionality、Product Personalization、Developer’s Advertising or Marketing、Third-Party Advertising 等)。
  3. 按 SDK 列设 “Is this data linked to the user’s identity?” Yes/No。
  4. 按 SDK 列设 “Do you use this data for tracking?” Yes/No。选 Yes:binary 必须调用 ATTrackingManager.requestTrackingAuthorization,且只在用户授权后才读 IDFA;选 No:代码里不能有 IDFA 路径(见原因 #2)。

每个类型都对了之后,点 Save,再点 Publish。Publish 后答案立即上线到产品页——问卷文案本身没有单独的审核。

Step 3:补全 PrivacyInfo.xcprivacy 里的 Required Reason

Xcode 里给主 target 加 PrivacyInfo.xcprivacy,填 NSPrivacyAccessedAPITypes

<key>NSPrivacyAccessedAPITypes</key>
<array>
  <dict>
    <key>NSPrivacyAccessedAPIType</key>
    <string>NSPrivacyAccessedAPICategoryUserDefaults</string>
    <key>NSPrivacyAccessedAPITypeReasons</key>
    <array>
      <string>CA92.1</string>
    </array>
  </dict>
</array>

理由码查 Apple 的 Describing use of required reason API 文档。例如 CA92.1 是 UserDefaults 的一个批准理由,对应”访问 app group container 里的信息”。

Step 4:核对隐私政策文案

打开你提交的隐私政策。所有里面提到的数据类别都要在问卷里出现;反过来问卷里勾的类别也要在政策里有交代。政策提到 “we use Google Analytics” 就必须勾 analytics + identifiers。

Step 5:重新提交

Publish 完问卷后,进该版本的 Distribution(原来叫 “App Store”)标签 → Add for Review / Submit for Review。如果拒回只针对问卷而没要求换 build,不用重新打包;但原因 #4 和 #5 一定要重新打包,因为它们活在 IPA 的 manifest 里。

怎么确认已经修好

  • App Privacy 页把你的改动显示为 Published,时间戳是今天。
  • 审核状态在 1-2 小时内从 Metadata Rejected 回到 Waiting for Review
  • 上传后没再收到新的 ITMS-91xxx 邮件。
  • 对 build 的拒回:TestFlight 处理完成时不再带隐私警告横幅。

如果还是没修好

  1. 在 Resolution Center 回复,列出你逐项对照的 SDK + 数据类型对,附厂商文档 URL。
  2. 审核员若指出具体符号(如 advertisingIdentifier),扫 IPA 确认是否真被调用;如果是 SDK 里的 dead code,向厂商要”关闭数据收集”的变体版本。
  3. 把 build 缩到最小:一次去掉一个 SDK 重交,直到拒回消失,定位罪魁祸首。
  4. 通过 App Review Contact 表单升级,附上 IPA 静态分析输出作为证据。

预防建议

  • 仓库里维护 PRIVACY.md,列每个 SDK 和它接触的数据类型;加 SDK 的 PR 必须同时更新它。
  • 加 CI 步骤:若 PrivacyInfo.xcprivacy 缺失,或 NSPrivacyTrackingtrue 但代码里找不到 ATT 弹窗调用,构建失败。
  • 每次提交前花 5 分钟 diff 一遍:问卷截图 vs SDK 清单 vs 隐私政策文案。
  • 锁 SDK 版本;新 minor 版本偶尔会加新数据收集而不升 major。
  • 订阅 Apple Developer News:Required Reason API 列表和常用 SDK 列表都在不定期扩充。

常见问题

只改问卷需要重新上传 build 吗? 如果拒回只针对 metadata,就不需要。改完并 Publish 隐私答案后立即生效,不用新 binary。只有拒回点了 IPA 本身才需要重新打包——也就是缺 Required Reason 声明(ITMS-91053 / ITMS-91056),或某个 SDK 缺隐私 manifest / 签名,因为这两类都在 build 里面。

重交之后多久状态会变? 纯 metadata 修复,状态一般在重交后 1-2 小时内从 Metadata Rejected 回到 Waiting for Review。如果上传了新 build,要先留出 TestFlight / 处理时间。

审核员说我在追踪用户,但我没有,为什么不能直接答”不追踪”? 因为 App Store Connect 把答案和你的 binary 绑在一起。只要 AppTrackingTransparency 框架或 advertisingIdentifier 在 IPA 里还可达,静态扫描就会推翻你的”否”,拒回反复出现。去掉 IDFA 代码路径(或把拉进它的广告 / 归因 SDK 删掉),打个新 build,再把 Device ID 声明为不收集。

每个 SDK 收什么数据去哪查? 每家厂商都有一个 “App Store data collection” 或 “privacy details” 页面,列出确切的数据类型、是否关联用户、是否用于追踪。Step 1 里那张表照着这些页面填,别靠猜。

PrivacyInfo.xcprivacy 和 App Store Connect 问卷是一回事吗? 不是。问卷是你在网页控制台里填的 metadata(对外公开的 nutrition 标签)。PrivacyInfo.xcprivacy 是 app / SDK 包里的一个文件,声明 Required Reason API 用途和 tracking 域名。Apple 会拿两者一起跟 binary 比对,必须一致。

哪些角色能编辑 App Privacy? Account Holder、Admin 或 App Manager(截至 2026 年 6 月)。Developer 角色不行;Marketing 角色只能改隐私政策 URL。

相关阅读

标签: #排查 #App Store #App 审核