App 隐私问卷被拒 / 不一致:3 个原因 + 修复路径

Apple 标你的隐私 nutrition 标签与 App 行为不一致。常见原因:第三方 SDK 收了你没申报的(analytics / 广告 / 崩溃 / attribution);申报"未收"但 SDK 证明在收;必需披露(与用户关联 / 用于 tracking)缺。先做:列每个 SDK + 各收什么(看各 SDK 隐私文档)。

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

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

常见原因

按命中率排序,多数 App 中枪 #1 或 #2。

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 链路可达,必须申报。

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 月起,某些 API(UserDefaults、文件时间戳、系统启动时间、磁盘空间、活跃键盘)必须在 PrivacyInfo.xcprivacy 里声明用途。漏了会触发独立但相关的拒回码(ITMS-91053 / ITMS-91056)。

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

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

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

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

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

动手前先确认

  • 弄清拒回到底是问卷、build、还是两者——文案在 App Store Connect 里不同。
  • 完整记下审核员原文及 ITMS 码(某些代码必须精确回应)。
  • 改之前先把当前问卷答案截图全留底,Apple 不保留历史版本。
  • 确认你的 App Store Connect 角色是 Account Holder 或 Admin,Developer 改不了 Privacy。

需要收集的信息

  • 审核员完整原文 + 所有 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 → My Apps → 你的 App → App Privacy → Edit。对每个数据类型:

  1. 勾 “Yes, we collect this data.”
  2. 选所有用途(Analytics、App Functionality、Product Personalization 等)。
  3. 按 SDK 列设 “Linked to User” Yes/No。
  4. 按 SDK 列设 “Used for Tracking” Yes/No——选 Yes 就必须在读 IDFA 前调用 ATTrackingManager.requestTrackingAuthorization

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 的 Required Reason API 文档

Step 4:核对隐私政策文案

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

Step 5:重新提交

App Store Connect 里改完问卷点 Save,然后回到 App Store 标签里那个 build → Submit for Review。如果拒回只针对问卷而没要求换 build,不用重新打包。

怎么确认已经修好

  • App Privacy 页显示的 “Saved” 时间戳是今天。
  • 审核状态在 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 的 Required Reason API 更新日志,这个表每季度都在扩。

相关阅读

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