axiom-app-store-diag

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

App Store Rejection Diagnostics

App Store 拒审诊断

Overview

概述

Systematic App Store rejection diagnosis and remediation. Covers the 6 most common rejection categories that account for 90% of all App Review failures.
Core principle 90% of App Store rejections fall into 6 categories. Reading the rejection message carefully and mapping to the correct guideline prevents the #1 mistake: fixing the wrong thing and getting rejected again for the same reason.
Most developers waste 1-2 weeks on rejection cycles because they skim the rejection message, assume the cause, and "fix" something that wasn't the problem. This skill provides systematic diagnosis from rejection message to targeted fix.
系统性的App Store拒审诊断与修复方案,覆盖了占所有App Review失败案例90%的6类最常见拒审原因。
核心原则 90%的App Store拒审案例都属于6个类别。仔细阅读拒审消息并对应到正确的指南,能避免最常见的错误:修复了错误的问题,导致因同一原因再次被拒。
大多数开发者会在拒审循环上浪费1-2周时间,因为他们只是略读拒审消息,假设问题原因,然后“修复”了根本不存在的问题。本技能提供从拒审消息到针对性修复的系统性诊断方法。

Red Flags — Suspect Submission Issue

红色警报——疑似提交问题

If you see ANY of these, suspect a submission issue and use this skill:
  • Rejection message cites a specific guideline number
  • "Binary Rejected" without clear guideline (technical gate failure)
  • Same app rejected multiple times for different reasons
  • "Metadata Rejected" (no code change needed)
  • Rejection mentions "privacy" or "data collection"
  • Rejection mentions "login" or "authentication"
  • Reviewer asks for demo account or more information
  • FORBIDDEN "The reviewer is wrong, let's just resubmit"
    • Re-read the rejection. App Review is right 95% of the time.
    • Resubmitting without changes wastes 3-7 days per cycle.
    • If you genuinely disagree, use the appeal process (Pattern 7).
如果出现以下任何一种情况,怀疑是提交问题,请使用本技能:
  • 拒审消息引用了特定的指南编号
  • 显示“Binary Rejected”但未明确给出指南(技术审核关卡失败)
  • 同一应用因不同原因多次被拒
  • 显示“Metadata Rejected”(无需修改代码)
  • 拒审消息提及“隐私”或“数据收集”
  • 拒审消息提及“登录”或“身份验证”
  • 审核人员要求提供演示账号或更多信息
  • 禁止“审核人员错了,我们重新提交就行”
    • 重新阅读拒审消息。App Review的判断95%都是正确的。
    • 未做修改就重新提交,每个循环会浪费3-7天时间。
    • 如果确实认为判断有误,请使用申诉流程(模式7)。

Mandatory First Steps

强制前置步骤

ALWAYS do these BEFORE changing any code:
  1. Read the FULL rejection message — Don't skim. Copy the exact text. Note every guideline number cited.
  2. Identify rejection type:
    • "App Rejected" → Guideline violation, code/content fix needed
    • "Metadata Rejected" → ASC metadata issue, no build needed
    • "Binary Rejected" → Technical gate (SDK, manifest, encryption)
    • "Removed from Sale" → Post-approval enforcement
  3. Check the specific guideline — Look up the exact number in app-store-ref
  4. Screenshot the rejection — Save for team communication and appeal reference
  5. Check App Review messages in ASC — Sometimes they ask for information, not reject
在修改任何代码之前,必须完成以下步骤:
  1. 完整阅读拒审消息 —— 不要略读。复制完整文本,记录所有引用的指南编号。
  2. 识别拒审类型
    • “App Rejected” → 违反指南,需要修改代码/内容
    • “Metadata Rejected” → App Store Connect(ASC)元数据问题,无需构建新版本
    • “Binary Rejected” → 技术关卡失败(SDK、配置文件、加密等问题)
    • “Removed from Sale” → 应用上架后被强制下架
  3. 查阅具体指南 —— 在app-store-ref中查找对应的指南编号
  4. 截图保存拒审消息 —— 用于团队沟通和申诉参考
  5. 查看ASC中的App Review消息 —— 有时他们只是要求提供信息,并非拒审

What this tells you

这些步骤的作用

Rejection TypeWhat ChangedNext Step
"App Rejected" + Guideline 2.1App crashed or had placeholdersPattern 1
"Metadata Rejected"Screenshots or description wrongPattern 2
"App Rejected" + Guideline 5.1Privacy policy or manifest gapsPattern 3
"App Rejected" + Guideline 4.8Missing Sign in with ApplePattern 4
"App Rejected" + Guideline 3.xBusiness/monetization violationPattern 5
"Binary Rejected" / no guidelineSDK, signing, or encryption issuePattern 6
Reviewer seems incorrectGenuine misunderstandingPattern 7
Guideline 1.x citedSafety/content issueContent review needed
Guideline 4.1-4.3 citedDesign/originality issueFunctionality review needed
拒审类型问题所在下一步操作
"App Rejected" + 指南2.1应用崩溃或存在占位内容模式1
"Metadata Rejected"截图或描述与实际应用不符模式2
"App Rejected" + 指南5.1隐私政策或配置文件存在漏洞模式3
"App Rejected" + 指南4.8缺少Sign in with Apple(SIWA)模式4
"App Rejected" + 指南3.x违反商业/变现规则模式5
"Binary Rejected" / 无指南编号SDK、签名或加密问题模式6
认为审核人员判断错误审核人员存在误解模式7
引用指南1.x安全/内容问题需要审核内容合规性
引用指南4.1-4.3设计/原创性问题需要审核功能独特性

MANDATORY INTERPRETATION

强制解读规则

Before changing ANY code, identify ONE of these:
  1. If "App Rejected" with guideline number → Map to specific pattern (1-5)
  2. If "Metadata Rejected" → Fix in ASC, no build required (Pattern 2)
  3. If "Binary Rejected" → Technical gate failure (Pattern 6)
  4. If multiple guidelines cited → Fix ALL cited issues, not just the first one. Both binary AND metadata can be rejected simultaneously — binary issues need a new build, metadata issues can be fixed in ASC. Fix both before resubmitting.
  5. If reviewer asks for information → Reply in ASC before making code changes
在修改任何代码之前,必须确定以下情况之一:
  1. 如果是“App Rejected”且带有指南编号 → 对应到特定模式(1-5)
  2. 如果是“Metadata Rejected” → 在ASC中修复,无需构建新版本(模式2)
  3. 如果是“Binary Rejected” → 技术关卡失败(模式6)
  4. 如果引用了多个指南编号 → 修复所有提及的问题,而不仅仅是第一个。二进制和元数据问题可能同时存在——二进制问题需要重新构建版本,元数据问题可在ASC中修复。重新提交前需修复所有问题。
  5. 如果审核人员要求提供信息 → 在修改代码前先在ASC中回复

If rejection reason is unclear or contradictory

如果拒审原因不明确或自相矛盾

  • STOP. Do NOT start fixing code yet
  • Reply to App Review in ASC asking for clarification
  • Include screenshots or video showing the feature working
  • Wait for response before making changes
  • 停止操作。不要开始修改代码
  • 在ASC中回复App Review,要求澄清问题
  • 附上展示功能正常运行的截图或视频
  • 等待回复后再进行修改

Decision Tree

决策树

App Store rejection?
├─ What does the rejection say?
│  │
│  ├─ Cites Guideline 2.1?
│  │  ├─ App crashed during review? → Pattern 1 (check crash logs)
│  │  ├─ Placeholder content found? → Pattern 1 (search project)
│  │  ├─ Broken links? → Pattern 1 (verify URLs)
│  │  └─ Missing demo credentials? → Pattern 1 (provide in review notes)
│  │
│  ├─ Cites Guideline 2.3?
│  │  ├─ Screenshots don't match app? → Pattern 2 (retake screenshots)
│  │  ├─ Description promises missing features? → Pattern 2 (update text)
│  │  └─ Keywords contain trademarks? → Pattern 2 (remove keywords)
│  │
│  ├─ Cites Guideline 5.1?
│  │  ├─ Privacy policy missing/inaccessible? → Pattern 3 (add/fix policy)
│  │  ├─ Purpose strings missing? → Pattern 3 (add to Info.plist)
│  │  ├─ Privacy manifest incomplete? → Pattern 3 (update PrivacyInfo)
│  │  └─ Tracking without ATT? → Pattern 3 (implement ATT)
│  │
│  ├─ Cites Guideline 4.8?
│  │  ├─ Third-party login without SIWA? → Pattern 4 (add SIWA)
│  │  ├─ SIWA button hidden or broken? → Pattern 4 (fix prominence)
│  │  └─ Exception applies? → Pattern 4 (verify exemption)
│  │
│  ├─ Cites Guideline 3.x?
│  │  ├─ Digital content without IAP? → Pattern 5 (implement StoreKit)
│  │  ├─ Subscription issues? → Pattern 5 (fix terms/value)
│  │  └─ Loot box odds not disclosed? → Pattern 5 (add disclosure)
│  │
│  ├─ "Binary Rejected" / no guideline?
│  │  ├─ Wrong SDK version? → Pattern 6 (update Xcode)
│  │  ├─ Privacy manifest missing? → Pattern 6 (add PrivacyInfo)
│  │  ├─ Encryption not declared? → Pattern 6 (add ITSAppUsesNonExemptEncryption)
│  │  └─ Invalid signing? → Pattern 6 (regenerate provisioning)
│  │
│  ├─ "I believe the reviewer is wrong"?
│  │  └─ → Pattern 7 (Appeal Process)
│  │
│  ├─ Cites Guideline 1.x?
│  │  └─ Safety/content issue → Review content against guideline
│  │
│  └─ Cites Guideline 4.1-4.3?
│     └─ Design/originality issue → Review app uniqueness/functionality
App Store拒审?
├─ 拒审消息内容是什么?
│  │
│  ├─ 引用了指南2.1?
│  │  ├─ 应用在审核期间崩溃? → 模式1(检查崩溃日志)
│  │  ├─ 发现占位内容? → 模式1(搜索项目文件)
│  │  ├─ 存在无效链接? → 模式1(验证URL)
│  │  └─ 缺少登录演示账号? → 模式1(在审核备注中提供)
│  │
│  ├─ 引用了指南2.3?
│  │  ├─ 截图与应用不符? → 模式2(重新拍摄截图)
│  │  ├─ 描述中承诺了未实现的功能? → 模式2(更新文本)
│  │  └─ 关键词包含商标? → 模式2(移除关键词)
│  │
│  ├─ 引用了指南5.1?
│  │  ├─ 缺少隐私政策或无法访问? → 模式3(添加/修复政策)
│  │  ├─ 缺少权限说明字符串? → 模式3(添加到Info.plist)
│  │  ├─ 隐私配置文件不完整? → 模式3(更新PrivacyInfo)
│  │  └─ 未获得ATT授权就进行用户追踪? → 模式3(实现ATT)
│  │
│  ├─ 引用了指南4.8?
│  │  ├─ 存在第三方登录但无SIWA? → 模式4(添加SIWA)
│  │  ├─ SIWA按钮隐藏或无法使用? → 模式4(调整显示优先级)
│  │  └─ 符合豁免条件? → 模式4(验证豁免资格)
│  │
│  ├─ 引用了指南3.x?
│  │  ├─ 数字内容未使用IAP? → 模式5(实现StoreKit)
│  │  ├─ 订阅存在问题? → 模式5(修复条款/价值)
│  │  └─ 未披露开箱类商品的概率? → 模式5(添加披露信息)
│  │
│  ├─ 显示“Binary Rejected”/无指南编号?
│  │  ├─ SDK版本过时? → 模式6(更新Xcode)
│  │  ├─ 缺少隐私配置文件? → 模式6(添加PrivacyInfo)
│  │  ├─ 未申报加密合规? → 模式6(添加ITSAppUsesNonExemptEncryption)
│  │  └─ 签名无效? → 模式6(重新生成配置文件)
│  │
│  ├─ “我认为审核人员错了”?
│  │  └─ → 模式7(申诉流程)
│  │
│  ├─ 引用了指南1.x?
│  │  └─ 安全/内容问题 → 根据指南审核内容
│  │
│  └─ 引用了指南4.1-4.3?
│     └─ 设计/原创性问题 → 审核应用的独特性/功能

Pattern Selection Rules (MANDATORY)

模式选择规则(强制)

Before proceeding to a pattern:
  1. Copy the exact rejection text — Word for word, including guideline numbers
  2. Match guideline number to pattern — Don't guess, map directly
  3. If multiple guidelines cited — Fix ALL of them before resubmitting
  4. If no guideline number — Likely Binary Rejected, start with Pattern 6
  5. If unsure — Reply to reviewer for clarification first
在使用具体模式之前:
  1. 复制完整的拒审文本 —— 一字不差,包括指南编号
  2. 将指南编号与模式对应 —— 不要猜测,直接匹配
  3. 如果引用了多个指南编号 —— 重新提交前修复所有问题
  4. 如果没有指南编号 —— 很可能是Binary Rejected,从模式6开始排查
  5. 如果不确定 —— 先回复审核人员要求澄清

Apply ONE pattern at a time

一次只应用一个模式

  • Identify the correct pattern from the rejection message
  • Implement the complete fix for that pattern
  • If multiple guidelines cited, fix each one before resubmitting
  • DO NOT resubmit after fixing only one of multiple cited issues
  • 根据拒审消息确定正确的模式
  • 完成该模式的完整修复
  • 如果引用了多个指南编号,修复每个问题后再重新提交
  • 不要只修复第一个提及的问题就重新提交

FORBIDDEN

禁止操作

  • Resubmitting without changes hoping for a different reviewer
  • Skimming the rejection and guessing the fix
  • Fixing only the first cited guideline when multiple are cited
  • Arguing emotionally in App Review messages
  • Disabling privacy features to avoid Guideline 5.1
  • 未做修改就重新提交,寄希望于换一个审核人员通过
  • 略读拒审消息就猜测修复方案
  • 引用多个指南时只修复第一个提及的问题
  • 在App Review消息中情绪化争论
  • 为了规避指南5.1而禁用隐私相关功能

Diagnostic Patterns

诊断模式

Pattern 1: Guideline 2.1 — App Completeness

模式1:指南2.1 —— 应用完整性

Time cost 3-7 days per rejection cycle
时间成本 每个拒审循环3-7天

Symptom

症状

  • Rejection citing "App Completeness"
  • Crashes during review
  • Placeholder content found
  • Broken links (support URL, privacy policy, in-app links)
  • Missing demo credentials for login-required apps
  • 拒审消息提及“应用完整性”
  • 审核期间应用崩溃
  • 发现占位内容
  • 存在无效链接(支持URL、隐私政策、应用内链接)
  • 需要登录的应用缺少演示账号

Common causes

常见原因

  1. App crashes on reviewer's device (different OS version, different device class)
  2. Placeholder text or images visible in any screen
  3. Broken links (support URL, privacy policy, in-app links)
  4. Missing demo credentials for login-required apps
  5. Backend service was down during review window
  1. 应用在审核人员的设备上崩溃(不同OS版本、不同设备类型)
  2. 任何界面存在占位文本或图片
  3. 存在无效链接(支持URL、隐私政策、应用内链接)
  4. 需要登录的应用缺少演示账号
  5. 审核期间后端服务宕机

Diagnosis

诊断

bash
undefined
bash
undefined

1. Check crash logs in App Store Connect

1. 在App Store Connect中检查崩溃日志

Xcode Organizer > Crashes > Filter by version

Xcode Organizer > Crashes > 按版本筛选

2. Search for placeholder strings

2. 搜索占位字符串

grep -r "Lorem|TODO|FIXME|placeholder|sample|test data"
--include=".swift" --include=".storyboard" --include="*.xib" .
grep -r "Lorem|TODO|FIXME|placeholder|sample|test data"
--include=".swift" --include=".storyboard" --include="*.xib" .

3. Verify all URLs resolve

3. 验证所有URL可访问

curl -sI "https://your-support-url.com" | head -1 curl -sI "https://your-privacy-policy-url.com" | head -1
curl -sI "https://your-support-url.com" | head -1 curl -sI "https://your-privacy-policy-url.com" | head -1

4. Test on latest shipping iOS

4. 在最新正式版iOS上测试

Check ASC for specific iOS version reviewer used (noted in rejection)

在拒审消息或ASC中查看审核人员使用的具体iOS版本

undefined
undefined

Fix

修复方案

swift
// ❌ WRONG — Demo credentials that expire
// Review Notes: "Login: test@test.com / password123"
// (If this account expires or gets locked, instant rejection)

// ✅ CORRECT — Permanent demo credentials
// Review Notes:
// "Demo Account: demo@yourapp.com / ReviewDemo2024!
//  This account has pre-populated sample data.
//  Account will not expire during review period."
swift
// ❌ WRONG — Placeholder still in code
Text("Lorem ipsum dolor sit amet")

// ✅ CORRECT — Real content in every screen
Text("Welcome to YourApp. Get started by creating your first project.")
swift
// ❌ 错误示例 —— 会过期的演示账号
// 审核备注: "Login: test@test.com / password123"
// (如果该账号过期或被锁定,会直接被拒)

// ✅ 正确示例 —— 永久演示账号
// 审核备注:
// "Demo Account: demo@yourapp.com / ReviewDemo2024!
//  该账号已预填充示例数据。
//  审核期间账号不会过期。"
swift
// ❌ 错误示例 —— 代码中仍存在占位内容
Text("Lorem ipsum dolor sit amet")

// ✅ 正确示例 —— 所有界面使用真实内容
Text("欢迎使用YourApp。创建第一个项目开始使用吧。")

Verification

验证步骤

  • Submit to TestFlight first, test every screen on multiple devices
  • Verify ALL URLs load successfully (including privacy policy from within the app)
  • Ensure demo credentials work and won't expire
  • Test on the specific iOS version mentioned in rejection (check rejection message or ASC Activity → Build → review device info)
  • Monitor backend uptime during review window (don't deploy during review)
  • Check ASC crash logs (Xcode Organizer → Crashes) for the specific device and OS version the reviewer used

  • 先提交到TestFlight,在多台设备上测试每个界面
  • 验证所有URL可正常访问(包括应用内的隐私政策链接)
  • 确保演示账号可用且不会过期
  • 在拒审消息中提到的具体iOS版本上测试(查看拒审消息或ASC Activity → Build → 审核设备信息)
  • 审核期间监控后端服务可用性(审核期间不要部署更新)
  • 在Xcode Organizer → Crashes中查看审核人员使用的设备和OS版本对应的崩溃日志

Pattern 2: Guideline 2.3 — Metadata Issues

模式2:指南2.3 —— 元数据问题

Time cost 1-3 days (metadata fix, no build needed)
时间成本 1-3天(仅修复元数据,无需构建版本)

Symptom

症状

  • "Metadata Rejected" — no code change required
  • Screenshots don't match current app UI
  • Description promises features not in the app
  • Keywords contain trademarked or competitor names
  • 显示“Metadata Rejected” —— 无需修改代码
  • 截图与当前应用UI不符
  • 描述中承诺了应用中未实现的功能
  • 关键词包含商标或竞品名称

Common causes

常见原因

  1. Screenshots show old UI or features that no longer exist
  2. Description promises features not yet implemented
  3. Keywords contain trademarked terms or competitor names
  4. App name implies functionality that doesn't exist
  5. Category selection doesn't match app's primary function
  1. 截图展示的是旧版UI或已移除的功能
  2. 描述中承诺了尚未实现的功能
  3. 关键词包含商标或竞品名称
  4. 应用名称暗示了未实现的功能
  5. 类别选择与应用主要功能不符

Diagnosis

诊断

Compare every screenshot to current app UI. Read description word by word — does each claim exist in the app? Check keywords against Apple's trademark list.
Checklist:
☐ Every screenshot matches current build
☐ Every feature mentioned in description exists and works
☐ No trademarked terms in keywords (e.g., "Instagram", "Uber")
☐ App icon appropriate for all audiences
☐ Age rating matches actual content
☐ Category selection accurate
☐ "What's New" text matches actual changes
将每张截图与当前应用UI对比。逐字阅读描述——描述中的每个功能是否在应用中存在?检查关键词是否违反Apple的商标规则。
检查清单:
☐ 每张截图都与当前应用UI匹配
☐ 描述中提及的每个功能都已实现且可用
☐ 关键词中无商标术语(如“Instagram”、“Uber”)
☐ 应用图标适合所有受众
☐ 年龄分级与实际内容匹配
☐ 类别选择准确
☐ “版本更新说明”与实际修改内容一致

Fix

修复方案

Update metadata directly in App Store Connect. No new build needed for metadata-only rejections.
✅ Take fresh screenshots FROM THE SUBMITTED BUILD (not dev build)
✅ Remove any features from description that aren't fully functional
✅ Replace trademarked keywords with generic equivalents
   ("photo sharing" not "Instagram-like")
✅ Ensure "What's New" describes changes in this specific version
直接在App Store Connect中更新元数据。仅元数据问题无需重新构建版本。
✅ 从提交的版本中重新拍摄截图(而非开发版)
✅ 移除描述中所有未实现的功能
✅ 将商标关键词替换为通用表述
   (用“照片分享”代替“类似Instagram”)
✅ 确保“版本更新说明”描述的是当前版本的修改内容

Verification

验证步骤

  • Take screenshots on the exact build version submitted
  • Have someone outside the team read the description and verify each claim
  • Search keywords for any trademarked terms

  • 使用提交的版本重新拍摄截图
  • 让团队外的人员阅读描述,验证每个功能是否存在
  • 检查关键词是否包含商标术语

Pattern 3: Guideline 5.1 — Privacy Violations

模式3:指南5.1 —— 隐私违规

Time cost 3-10 days (code + manifest + policy changes)
时间成本 3-10天(代码+配置文件+政策修改)

Symptom

症状

  • Rejection citing privacy policy, data collection, purpose strings, or tracking
  • Privacy manifest missing required reason API declarations
  • Third-party SDK collects data not disclosed
  • 拒审消息提及隐私政策、数据收集、权限说明字符串或用户追踪
  • 缺少隐私配置文件(PrivacyInfo.xcprivacy)中要求的API声明
  • 第三方SDK收集了未披露的数据

Common causes

常见原因

  1. Privacy policy missing or not accessible from within the app
  2. Privacy policy doesn't match actual data collection
  3. Missing purpose strings for permission requests
  4. Privacy manifest (PrivacyInfo.xcprivacy) missing required reason API declarations
  5. Third-party SDK collects data not disclosed in privacy nutrition labels
  6. App tracks users without ATT (App Tracking Transparency) consent
  1. 缺少隐私政策,或应用内无法访问隐私政策
  2. 隐私政策与实际数据收集情况不符
  3. 权限请求缺少说明字符串
  4. 缺少隐私配置文件(PrivacyInfo.xcprivacy)中要求的API声明
  5. 第三方SDK收集了隐私营养标签中未披露的数据
  6. 未获得ATT(App Tracking Transparency)授权就追踪用户

Diagnosis

诊断

swift
// 1. Check: Is privacy policy URL in ASC AND accessible from within the app?
// Both are required. In-app access is commonly missed.

// 2. Check purpose strings
// ❌ WRONG — Generic purpose string
"NSCameraUsageDescription" = "Camera access needed"

// ✅ CORRECT — Specific purpose string explaining why
"NSCameraUsageDescription" = "Take photos for your profile picture and upload to your account"

// 3. Generate privacy report
// Xcode: Product → Archive → Generate Privacy Report
// This shows aggregate data from all frameworks and your code

// 4. Check privacy manifest
// Verify PrivacyInfo.xcprivacy exists in your app target
// AND in every framework target that uses required reason APIs
swift
// 1. 检查:隐私政策URL是否在ASC中配置,且应用内可访问?
// 两者都是必须的。应用内访问是常被忽略的点。

// 2. 检查权限说明字符串
// ❌ 错误示例 —— 通用说明字符串
"NSCameraUsageDescription" = "需要访问相机"

// ✅ 正确示例 —— 具体说明使用原因
"NSCameraUsageDescription" = "拍摄头像照片并上传到您的账号"

// 3. 生成隐私报告
// Xcode: Product → Archive → Generate Privacy Report
// 该报告显示所有框架和代码的汇总数据收集情况

// 4. 检查隐私配置文件
// 验证PrivacyInfo.xcprivacy存在于应用目标中
// 且存在于所有使用受限API的框架目标中

Fix

修复方案

Purpose strings (Info.plist)
权限说明字符串(Info.plist)
xml
<!-- Every permission MUST have a specific, honest purpose string -->
<key>NSCameraUsageDescription</key>
<string>Take photos for your profile picture and upload to your account</string>

<key>NSLocationWhenInUseUsageDescription</key>
<string>Show nearby restaurants on the map and calculate delivery distance</string>

<key>NSPhotoLibraryUsageDescription</key>
<string>Select photos from your library to attach to messages</string>
xml
<!-- 每个权限必须有具体、真实的说明字符串 -->
<key>NSCameraUsageDescription</key>
<string>拍摄头像照片并上传到您的账号</string>

<key>NSLocationWhenInUseUsageDescription</key>
<string>在地图上显示附近餐厅并计算配送距离</string>

<key>NSPhotoLibraryUsageDescription</key>
<string>从相册中选择照片以附加到消息</string>
Privacy manifest (PrivacyInfo.xcprivacy)
隐私配置文件(PrivacyInfo.xcprivacy)
xml
<!-- Required if you use any "required reason" APIs -->
<!-- UserDefaults, file timestamp, disk space, system boot time, etc. -->
<dict>
    <key>NSPrivacyAccessedAPITypes</key>
    <array>
        <dict>
            <key>NSPrivacyAccessedAPIType</key>
            <string>NSPrivacyAccessedAPICategoryUserDefaults</string>
            <key>NSPrivacyAccessedAPITypeReasons</key>
            <array>
                <string>CA92.1</string>
            </array>
        </dict>
    </array>
</dict>
xml
<!-- 如果使用了任何“受限原因”API,则必须配置 -->
<!-- 例如UserDefaults、文件时间戳、磁盘空间、系统启动时间等 -->
<dict>
    <key>NSPrivacyAccessedAPITypes</key>
    <array>
        <dict>
            <key>NSPrivacyAccessedAPIType</key>
            <string>NSPrivacyAccessedAPICategoryUserDefaults</string>
            <key>NSPrivacyAccessedAPITypeReasons</key>
            <array>
                <string>CA92.1</string>
            </array>
        </dict>
    </array>
</dict>
Privacy policy requirements
隐私政策要求
Your privacy policy MUST specifically list:
☐ What data is collected (every type)
☐ How data is collected (automatically, user-provided)
☐ All uses of collected data
☐ Third-party sharing (who, why)
☐ Data retention period
☐ How users can request deletion
☐ Contact information for privacy inquiries
您的隐私政策必须明确列出:
☐ 收集的数据类型(所有类型)
☐ 数据收集方式(自动收集、用户提供)
☐ 收集数据的所有用途
☐ 与第三方共享的数据(对象、原因)
☐ 数据保留期限
☐ 用户如何请求删除数据
☐ 隐私问题的联系方式
App Tracking Transparency
App Tracking Transparency
swift
// Required if app tracks users across other companies' apps/websites
import AppTrackingTransparency

func requestTrackingPermission() {
    ATTrackingManager.requestTrackingAuthorization { status in
        switch status {
        case .authorized:
            // Enable tracking (analytics, ad attribution)
            break
        case .denied, .restricted, .notDetermined:
            // Disable ALL tracking
            // Remove IDFA access, disable third-party analytics that track
            break
        @unknown default:
            break
        }
    }
}
swift
// 如果应用跨其他公司的应用/网站追踪用户,则必须实现
import AppTrackingTransparency

func requestTrackingPermission() {
    ATTrackingManager.requestTrackingAuthorization { status in
        switch status {
        case .authorized:
            // 启用追踪(分析、广告归因)
            break
        case .denied, .restricted, .notDetermined:
            // 禁用所有追踪
            // 移除IDFA访问权限,禁用第三方分析工具的追踪功能
            break
        @unknown default:
            break
        }
    }
}

Verification

验证步骤

  • Generate Privacy Report (Product > Archive > Generate Privacy Report) and verify all APIs declared
  • Test privacy policy link from within the app (not just browser)
  • Verify every permission request has a specific, honest purpose string
  • Audit all third-party SDKs for undisclosed data collection
  • Test ATT flow: deny tracking, verify app works correctly without it

  • 生成隐私报告(Product > Archive > Generate Privacy Report)并验证所有API已声明
  • 测试应用内的隐私政策链接(而非仅在浏览器中测试)
  • 验证每个权限请求都有具体、真实的说明字符串
  • 审核所有第三方SDK的未披露数据收集情况
  • 测试ATT流程:拒绝追踪后,验证应用仍能正常运行

Pattern 4: Guideline 4.8 — Missing Sign in with Apple

模式4:指南4.8 —— 缺少Sign in with Apple

Time cost 3-7 days (implementation + resubmit)
时间成本 3-7天(实现+重新提交)

Symptom

症状

  • Rejection citing Guideline 4.8
  • App has third-party login but no Sign in with Apple (SIWA)
  • 拒审消息引用指南4.8
  • 应用有第三方登录但无Sign in with Apple(SIWA)

Common causes

常见原因

  1. App has Google/Facebook/Twitter login but no SIWA
  2. SIWA button exists but doesn't work
  3. SIWA not offered at equal prominence (hidden or secondary)
  4. SIWA flow doesn't handle credential revocation
  1. 应用有Google/Facebook/Twitter登录但无SIWA
  2. SIWA按钮存在但无法使用
  3. SIWA的显示优先级低于其他登录选项(隐藏或次要位置)
  4. SIWA流程未处理凭证撤销

Diagnosis

诊断

The rule is simple: If your app uses ANY third-party or social login service, you MUST offer Sign in with Apple as an equivalent option.
Exceptions (SIWA not required):
  • App exclusively uses your company's own accounts
  • App is for education (managed Apple IDs)
  • App requires government or institution ID
  • App is a client for a third-party service (e.g., email client)
规则很简单:如果应用使用任何第三方或社交登录服务,必须提供Sign in with Apple作为等效选项。
豁免情况(无需提供SIWA):
  • 应用仅使用公司自有账号系统
  • 应用面向教育领域(使用Managed Apple ID)
  • 应用要求使用政府或机构ID登录
  • 应用是第三方服务的客户端(如邮件客户端)

Fix

修复方案

swift
import AuthenticationServices

// ✅ CORRECT — SIWA at same prominence as other login options
struct LoginView: View {
    var body: some View {
        VStack(spacing: 16) {
            // Sign in with Apple — MUST be at same visual level
            SignInWithAppleButton(.signIn) { request in
                request.requestedScopes = [.fullName, .email]
            } onCompletion: { result in
                switch result {
                case .success(let authorization):
                    handleAuthorization(authorization)
                case .failure(let error):
                    handleError(error)
                }
            }
            .signInWithAppleButtonStyle(.black)
            .frame(height: 50)

            // Other login options at same size/prominence
            GoogleSignInButton()
                .frame(height: 50)
        }
    }

    func handleAuthorization(_ authorization: ASAuthorization) {
        guard let credential = authorization.credential
            as? ASAuthorizationAppleIDCredential else { return }

        let userIdentifier = credential.user
        let fullName = credential.fullName
        let email = credential.email
        // Note: fullName and email only provided on FIRST sign-in
        // Store them immediately — they won't be provided again

        // Send to your backend for account creation/login
    }
}
swift
// ✅ Handle credential revocation (required for account deletion support)
func checkCredentialState() {
    let provider = ASAuthorizationAppleIDProvider()
    provider.getCredentialState(forUserID: storedUserIdentifier) { state, error in
        switch state {
        case .authorized:
            break // User is still signed in
        case .revoked:
            // User revoked credentials — sign out immediately
            signOut()
        case .notFound:
            // Credential not found — show sign-in
            showLogin()
        @unknown default:
            break
        }
    }
}
swift
import AuthenticationServices

// ✅ 正确示例 —— SIWA与其他登录选项显示优先级一致
struct LoginView: View {
    var body: some View {
        VStack(spacing: 16) {
            // Sign in with Apple —— 必须与其他登录选项视觉层级一致
            SignInWithAppleButton(.signIn) { request in
                request.requestedScopes = [.fullName, .email]
            } onCompletion: { result in
                switch result {
                case .success(let authorization):
                    handleAuthorization(authorization)
                case .failure(let error):
                    handleError(error)
                }
            }
            .signInWithAppleButtonStyle(.black)
            .frame(height: 50)

            // 其他登录选项尺寸/显示优先级一致
            GoogleSignInButton()
                .frame(height: 50)
        }
    }

    func handleAuthorization(_ authorization: ASAuthorization) {
        guard let credential = authorization.credential
            as? ASAuthorizationAppleIDCredential else { return }

        let userIdentifier = credential.user
        let fullName = credential.fullName
        let email = credential.email
        // 注意:fullName和email仅在首次登录时提供
        // 需立即存储 —— 后续登录不会再提供

        // 将信息发送到后端用于账号创建/登录
    }
}
swift
// ✅ 处理凭证撤销(账号删除支持所需)
func checkCredentialState() {
    let provider = ASAuthorizationAppleIDProvider()
    provider.getCredentialState(forUserID: storedUserIdentifier) { state, error in
        switch state {
        case .authorized:
            break // 用户仍处于登录状态
        case .revoked:
            // 用户已撤销凭证 —— 立即退出登录
            signOut()
        case .notFound:
            // 未找到凭证 —— 显示登录界面
            showLogin()
        @unknown default:
            break
        }
    }
}

Verification

验证步骤

  • SIWA button is visually equal to other login buttons (same size, same screen)
  • Full SIWA flow works: sign in, account creation, credential check
  • Handle revocation: user can revoke in Settings > Apple ID > Sign-In & Security
  • Test account deletion flow (required since June 2022)

  • SIWA按钮与其他登录按钮视觉层级一致(相同尺寸、同一界面)
  • 完整SIWA流程可用:登录、账号创建、凭证检查
  • 处理凭证撤销:用户可在设置>Apple ID>登录与安全中撤销凭证
  • 测试账号删除流程(2022年6月起强制要求)

Pattern 5: Guideline 3.x — Business/Monetization

模式5:指南3.x —— 商业/变现违规

Time cost 3-14 days (may require architectural changes)
时间成本 3-14天(可能需要架构调整)

Symptom

症状

  • Rejection citing business guidelines
  • IAP requirements not met
  • Subscription doesn't provide ongoing value
  • External payment for digital content
  • 拒审消息引用商业指南
  • 未满足IAP要求
  • 订阅未提供持续价值
  • 数字内容使用外部支付渠道

Common causes

常见原因

  1. Digital content unlocked without IAP (using external payment for in-app features)
  2. Subscription doesn't provide ongoing value (one-time content sold as subscription)
  3. Loot box or random item purchase odds not disclosed
  4. Deceptive subscription flow (dark patterns, misleading free trial)
  5. IAP metadata incomplete or not submitted for review
  1. 数字内容未使用Apple IAP解锁(使用外部支付渠道解锁应用内功能)
  2. 订阅未提供持续价值(一次性内容以订阅形式售卖)
  3. 开箱类或随机商品未披露概率
  4. 欺骗性订阅流程(暗模式、误导性免费试用)
  5. IAP元数据不完整或未提交审核

Diagnosis

诊断

The key question: Is any digital content or feature unlocked without Apple IAP?
Digital goods/features → MUST use Apple IAP
  Examples: premium features, virtual currency, ad removal, content
  packs, subscription access to digital content

Physical goods/services → MAY use external payment
  Examples: physical merchandise, ride-sharing, food delivery,
  person-to-person services

Certain categories → MAY use external payment (3.1.3 exceptions)
  Examples: "reader" apps (Kindle, Netflix, Spotify), one-to-one
  real-time services
核心问题:是否有任何数字内容或功能未通过Apple IAP解锁?
数字商品/功能 → 必须使用Apple IAP
  示例:高级功能、虚拟货币、移除广告、内容包、订阅数字内容

实体商品/服务 → 可使用外部支付渠道
  示例:实体商品、网约车、外卖、一对一服务

特定类别 → 可使用外部支付渠道(3.1.3豁免)
  示例:“阅读器”类应用(Kindle、Netflix、Spotify)、一对一实时服务

Fix

修复方案

swift
// ❌ WRONG — Unlocking features via external payment
func unlockPremium(receiptFromServer: String) {
    // Bypass Apple IAP → rejection
    UserDefaults.standard.set(true, forKey: "isPremium")
}

// ✅ CORRECT — StoreKit 2 for all digital goods
import StoreKit

func purchasePremium() async throws {
    let product = try await Product.products(for: ["com.app.premium"]).first!
    let result = try await product.purchase()

    switch result {
    case .success(let verification):
        let transaction = try checkVerified(verification)
        // Unlock feature
        await transaction.finish()
    case .pending:
        // Payment pending (Ask to Buy, etc.)
        break
    case .userCancelled:
        break
    @unknown default:
        break
    }
}
swift
// ✅ Loot box disclosure (required if random items for purchase)
struct LootBoxView: View {
    var body: some View {
        VStack {
            Text("Mystery Box — $4.99")
            Text("Contents are random. Odds:")
                .font(.caption)

            // MUST disclose odds before purchase
            VStack(alignment: .leading) {
                Text("Common item: 60%")
                Text("Rare item: 30%")
                Text("Legendary item: 10%")
            }
            .font(.caption2)
            .foregroundStyle(.secondary)
        }
    }
}
swift
// ❌ 错误示例 —— 通过外部支付解锁功能
func unlockPremium(receiptFromServer: String) {
    // 绕过Apple IAP → 会被拒
    UserDefaults.standard.set(true, forKey: "isPremium")
}

// ✅ 正确示例 —— 所有数字商品使用StoreKit 2
import StoreKit

func purchasePremium() async throws {
    let product = try await Product.products(for: ["com.app.premium"]).first!
    let result = try await product.purchase()

    switch result {
    case .success(let verification):
        let transaction = try checkVerified(verification)
        // 解锁功能
        await transaction.finish()
    case .pending:
        // 支付待处理(如Ask to Buy等)
        break
    case .userCancelled:
        break
    @unknown default:
        break
    }
}
swift
// ✅ 开箱类商品概率披露(购买随机商品时必须提供)
struct LootBoxView: View {
    var body: some View {
        VStack {
            Text("神秘宝箱 — 4.99美元")
            Text("内容随机。概率:")
                .font(.caption)

            // 购买前必须披露概率
            VStack(alignment: .leading) {
                Text("普通物品:60%")
                Text("稀有物品:30%")
                Text("传奇物品:10%")
            }
            .font(.caption2)
            .foregroundStyle(.secondary)
        }
    }
}

Verification

验证步骤

  • ALL digital content/features use Apple IAP (StoreKit 2)
  • IAP products submitted and approved in ASC before app submission
  • Subscription terms clearly communicated before purchase screen
  • Free trial duration and auto-renewal price clearly visible
  • Loot box odds disclosed before any purchase
  • No external payment links for digital goods (unless "reader" app exception applies)

  • 所有数字内容/功能均使用Apple IAP(StoreKit 2)
  • 应用提交前,IAP商品已在ASC中提交并通过审核
  • 订阅条款在购买界面清晰展示
  • 免费试用时长和自动续费价格清晰可见
  • 开箱类商品在购买前披露概率
  • 数字商品无外部支付链接(除非符合“阅读器”应用豁免条件)

Pattern 6: Binary Rejected — Technical Gates

模式6:Binary Rejected —— 技术关卡失败

Time cost 1-3 days (build configuration fix)
时间成本 1-3天(修复构建配置)

Symptom

症状

  • "Binary Rejected" with no specific guideline
  • Automated rejection during processing
  • Build stuck in "Processing" state
  • 显示“Binary Rejected”但无具体指南
  • 处理过程中自动被拒
  • 构建版本卡在“处理中”状态

Common causes

常见原因

  1. Built with outdated SDK version (must meet Apple's minimum)
  2. Privacy manifest (PrivacyInfo.xcprivacy) missing or invalid
  3. Encryption compliance not declared (ITSAppUsesNonExemptEncryption)
  4. Invalid signing or provisioning profile
  5. Missing required device capabilities in Info.plist
  6. App uses private or deprecated APIs
  7. App binary too large without on-demand resources
  1. 使用过时的SDK版本(必须符合Apple的最低要求)
  2. 缺少或无效的隐私配置文件(PrivacyInfo.xcprivacy)
  3. 未申报加密合规(ITSAppUsesNonExemptEncryption)
  4. 签名或配置文件无效
  5. Info.plist中缺少必需的设备权限
  6. 应用使用私有或废弃API
  7. 应用包过大且未使用按需资源

Diagnosis

诊断

bash
undefined
bash
undefined

1. Check Xcode and SDK version

1. 检查Xcode和SDK版本

xcodebuild -version
xcodebuild -version

Must be current or previous major Xcode version

必须是当前或上一个主要Xcode版本

2. Check processing logs in ASC

2. 在ASC中查看处理日志

App Store Connect → My Apps → [App] → Activity → Build → Processing Log

App Store Connect → 我的App → [应用名称] → Activity → Build → 处理日志

3. Verify encryption declaration

3. 验证加密申报

grep -c "ITSAppUsesNonExemptEncryption" Info.plist
grep -c "ITSAppUsesNonExemptEncryption" Info.plist

Must exist and be set to YES or NO

必须存在且设置为YES或NO

4. Check provisioning

4. 检查配置文件

security cms -D -i embedded.mobileprovision 2>/dev/null | head -20
security cms -D -i embedded.mobileprovision 2>/dev/null | head -20

Verify not expired

验证配置文件未过期

5. Check for private API usage

5. 检查私有API使用情况

Xcode: Product → Archive → Distribute App → Validate App

Xcode: Product → Archive → Distribute App → Validate App

This catches most private API issues before submission

提交前可检测大多数私有API问题

undefined
undefined

Fix

修复方案

xml
<!-- Encryption compliance (Info.plist) -->
<!-- If app uses ONLY standard HTTPS (URLSession, etc.) -->
<key>ITSAppUsesNonExemptEncryption</key>
<false/>

<!-- If app uses custom encryption beyond HTTPS -->
<key>ITSAppUsesNonExemptEncryption</key>
<true/>
<!-- Then upload export compliance documentation in ASC:
     App Store Connect → My Apps → [App] → App Information →
     Export Compliance Information → Upload documentation
     You may also need to file an annual self-classification
     report with the US Bureau of Industry and Security (BIS) -->
Encryption decision flow:
  1. Does your app use ONLY standard OS-provided HTTPS (URLSession, Alamofire)? → Set
    false
    , done
  2. Does your app call OpenSSL, libsodium, or custom crypto directly? → Set
    true
    , upload BIS docs
  3. Does your app implement proprietary encryption protocols? → Set
    true
    , upload BIS docs
  4. Unsure? → Run
    strings YourApp | grep -i "openssl\|libcrypto\|CCCrypt"
    to check
bash
undefined
xml
<!-- 加密合规(Info.plist) -->
<!-- 如果应用仅使用标准HTTPS(URLSession等) -->
<key>ITSAppUsesNonExemptEncryption</key>
<false/>

<!-- 如果应用使用HTTPS以外的自定义加密 -->
<key>ITSAppUsesNonExemptEncryption</key>
<true/>
<!-- 然后在ASC中上传出口合规文档:
     App Store Connect → 我的App → [应用名称] → 应用信息 →
     出口合规信息 → 上传文档
     您可能还需要向美国工业和安全局(BIS)提交年度自我分类报告 -->
加密决策流程:
  1. 应用是否仅使用系统提供的标准HTTPS(URLSession、Alamofire)? → 设置为
    false
    ,完成
  2. 应用是否直接调用OpenSSL、libsodium或自定义加密库? → 设置为
    true
    ,上传BIS文档
  3. 应用是否实现了专有加密协议? → 设置为
    true
    ,上传BIS文档
  4. 不确定? → 运行
    strings YourApp | grep -i "openssl\|libcrypto\|CCCrypt"
    检查
bash
undefined

Validate before submitting

提交前验证

Xcode: Product → Archive → Distribute App → Validate App

Xcode: Product → Archive → Distribute App → Validate App

Catches ~80% of binary rejection causes

可检测约80%的Binary Rejected原因

Clean build if signing issues

签名问题时清理构建缓存

rm -rf ~/Library/Developer/Xcode/DerivedData
rm -rf ~/Library/Developer/Xcode/DerivedData

Re-download provisioning profiles in Xcode Preferences → Accounts

在Xcode偏好设置 → 账号中重新下载配置文件

undefined
undefined

Verification

验证步骤

  • Run "Validate App" in Xcode Organizer before submitting
  • Verify Xcode version meets Apple's current requirements
  • Check PrivacyInfo.xcprivacy exists and is included in the app bundle
  • Verify ITSAppUsesNonExemptEncryption key is present
  • Ensure provisioning profile is not expired
  • Test app on physical device with release configuration

  • 提交前在Xcode Organizer中运行“Validate App”
  • 验证Xcode版本符合Apple当前要求
  • 检查PrivacyInfo.xcprivacy是否存在并包含在应用包中
  • 验证ITSAppUsesNonExemptEncryption键已存在
  • 确保配置文件未过期
  • 在物理设备上使用发布配置测试应用

Pattern 7: Appeal Process

模式7:申诉流程

Time to resolve 3-14 days
解决时间 3-14天

When to use

适用场景

  • You genuinely believe the reviewer misunderstood your app
  • You believe the wrong guideline was applied
  • Your app complies and you have evidence
  • 确实认为审核人员误解了应用
  • 认为应用被错误地套用了指南
  • 应用符合指南且有证据证明

When NOT to use

不适用场景

  • You disagree with Apple's rules (they won't change for your app)
  • You're hoping a different reviewer will approve without changes
  • You want to skip implementing a required feature (like SIWA)
  • 不同意Apple的规则(Apple不会为单个应用修改规则)
  • 寄希望于换一个审核人员通过而不做修改
  • 想跳过必需功能的实现(如SIWA)

Step 1: Reply in App Store Connect first

步骤1:先在App Store Connect中回复

Most issues resolve without a formal appeal. Reply to App Review messages in ASC with:
  • Specific evidence of compliance
  • Screenshots or video demonstrating the feature
  • Clear reference to the guideline you believe you comply with
大多数问题无需正式申诉即可解决。在ASC中回复App Review时需包含:
  • 符合指南的具体证据
  • 展示功能正常运行的截图或视频
  • 明确引用认为应用符合的指南条款

Step 2: If unresolved, submit formal appeal

步骤2:若未解决,提交正式申诉

URL: developer.apple.com/contact/app-store/?topic=appeal
网址:developer.apple.com/contact/app-store/?topic=appeal

Appeal writing

申诉撰写规范

✅ GOOD appeal structure:

"Our app complies with Guideline [X.Y] because [specific evidence].

The reviewer noted: '[quote exact rejection text]'

However, our app [specific counter-evidence with details]:
1. [Feature X] works as shown in [attached screenshot/video]
2. [Policy Y] is accessible at [URL] and within the app at [screen]
3. [Requirement Z] is implemented as described in [technical detail]

Attached: [screenshots, screen recording, or documentation]

We respectfully request re-review of this decision."
❌ BAD appeal examples:

"This is unfair. Other apps do the same thing. Please approve."
→ Apple reviews each app independently

"We've been rejected 3 times and are losing money."
→ Financial pressure is not relevant to guideline compliance

"The reviewer didn't understand our app."
→ Vague. Show specifically what they missed.

"We need this approved by Friday for our launch."
→ Deadlines are not App Review's concern
✅ 良好的申诉结构:

“我们的应用符合指南[X.Y],原因如下[具体证据]。

审核人员指出:'[引用完整拒审文本]'

然而,我们的应用[具体反驳证据,含细节]:
1. [功能X]的运行情况如[附件截图/视频]所示
2. [政策Y]可在[URL]访问,且在应用内[具体界面]可查看
3. [要求Z]已按[技术细节]实现

附件:[截图、录屏或文档]

我们恳请重新审核该决定。"
❌ 不良申诉示例:

“这太不公平了。其他应用也这么做。请通过审核。”
→ Apple会独立审核每个应用

“我们已经被拒3次了,正在损失收入。”
→ 财务压力与指南合规性无关

“审核人员不理解我们的应用。”
→ 表述模糊。需具体说明审核人员遗漏的内容。

“我们需要在周五前通过审核以配合发布。”
→ 截止日期与App Review无关

Step 3: Escalate if needed

步骤3:必要时升级申诉

If appeal is denied:
  1. Request a phone call with App Review (available through appeal process)
  2. Contact Apple Developer Relations as last resort
  3. Consider whether the app genuinely needs architectural changes
若申诉被驳回:
  1. 通过申诉流程请求与App Review进行电话沟通
  2. 最后可联系Apple Developer Relations
  3. 考虑应用是否需要架构调整

Verification

验证步骤

  • Wait for response before making code changes (if appealing)
  • Include ONE appeal per rejection (multiple appeals slow the process)
  • Respond to any information requests before filing appeal

  • 申诉期间等待回复,不要修改代码
  • 每次拒审仅提交一次申诉(多次申诉会延迟处理)
  • 提交申诉前先回复所有信息请求

Quick Reference Table

快速参考表

Rejection TypeLikely CauseFirst CheckPatternTypical Fix Time
Guideline 2.1Crashes/placeholdersTest on device, search placeholders11-3 days
Guideline 2.3Metadata mismatchCompare screenshots to app21 day (no build)
Guideline 5.1Privacy gapsCheck policy + manifest + purpose strings32-5 days
Guideline 4.8Missing SIWACheck for third-party login43-5 days
Guideline 3.xPayment methodReview IAP flows53-14 days
Binary RejectedTechnical gateCheck SDK, manifest, encryption61-2 days
Guideline 1.xSafety/contentReview content policyN/AVaries
Guideline 4.1-4.3Design/originalityReview app uniquenessN/AVaries
拒审类型可能原因首要检查项模式典型修复时间
指南2.1崩溃/占位内容设备测试、搜索占位内容11-3天
指南2.3元数据不匹配对比截图与应用21天(无需构建版本)
指南5.1隐私漏洞检查政策+配置文件+权限说明字符串32-5天
指南4.8缺少SIWA检查第三方登录43-5天
指南3.x支付方式违规审核IAP流程53-14天
Binary Rejected技术关卡失败检查SDK、配置文件、加密61-2天
指南1.x安全/内容问题根据指南审核内容N/A视情况而定
指南4.1-4.3设计/原创性问题审核应用独特性N/A视情况而定

Production Crisis Scenario

生产环境危机场景

Context: App rejected for 3rd time, different reason each time, launch is tomorrow

背景:应用第三次被拒,每次原因不同,明天就要发布

Situation: Marketing committed to a launch date. App was rejected for crashes (fixed), then metadata (fixed), now privacy policy "doesn't match actual data collection."
Pressure signals:
  • Product team already sent press releases with launch date
  • App Store rating will drop if launch delayed
  • Manager asking "why wasn't this caught earlier?"
  • Temptation to quick-fix only the cited privacy issue
Why this happens: Each review pass goes deeper. First pass catches obvious issues (crashes). Second pass checks metadata. Third pass audits privacy compliance. This is normal, not "the reviewer is picking on you."
场景:市场团队已对外公布发布日期。应用因崩溃被拒(已修复),然后因元数据被拒(已修复),现在因隐私政策“与实际数据收集情况不符”被拒。
压力信号:
  • 产品团队已发送包含发布日期的新闻稿
  • 发布延迟会导致App Store评分下降
  • 经理询问“为什么之前没发现这个问题?”
  • 倾向于仅快速修复提及的隐私问题
问题根源:每次审核会深入检查更多问题。第一次审核发现明显问题(崩溃),第二次检查元数据,第三次审核隐私合规性。这是正常流程,并非“审核人员针对你”。

Rationalization traps (DO NOT fall into these)

理性陷阱(切勿陷入)

  1. "Just fix the privacy policy wording and resubmit"
    • The reviewer said "doesn't match actual data collection"
    • That means your app collects data you didn't disclose
    • A wording change without auditing actual data collection = another rejection
  2. "The reviewer is being unreasonable, let's appeal"
    • Three rejections for three different valid issues is not unreasonable
    • Appealing wastes 3-14 days when you could fix and resubmit in 1-3 days
  3. "Let's remove the privacy-sensitive features to ship faster"
    • Removing features changes the app, requiring re-review of everything
    • May introduce new issues (broken UI, missing functionality)
  4. "Different reviewer next time might not notice"
    • Reviewers see the rejection history — they check previously cited issues
    • Repeat rejections get escalated to senior reviewers
  1. “只需修改隐私政策措辞然后重新提交”
    • 审核人员指出“与实际数据收集情况不符”
    • 这意味着应用收集了未披露的数据
    • 仅修改措辞而不审核实际数据收集情况 = 再次被拒
  2. “审核人员太不讲理,我们申诉吧”
    • 三次被拒对应三个不同的有效问题,并非审核人员不讲理
    • 申诉会浪费3-14天,而彻底修复只需1-3天
  3. “移除隐私敏感功能以加快发布”
    • 移除功能会改变应用,需要重新审核所有内容
    • 可能引入新问题(UI损坏、功能缺失)
  4. “换个审核人员可能不会注意到”
    • 审核人员会查看拒审历史 —— 他们会检查之前提及的问题
    • 多次拒审会升级到高级审核人员处理

MANDATORY approach

强制处理方法

  1. Don't panic. Don't resubmit without a thorough fix.
  2. Run the COMPLETE pre-flight checklist — not just the cited issue.
  3. Audit all data collection: every SDK, every analytics call, every API request that sends user data.
  4. Generate privacy report (Product > Archive > Generate Privacy Report) and cross-reference with privacy policy.
  5. Fix privacy policy to specifically list every data type actually collected.
  6. Verify all previous rejection issues still fixed (crashes, metadata).
  7. Request expedited review at developer.apple.com/contact/app-store/?topic=expedite if genuinely time-critical.
  8. Communicate to stakeholders: "Each review fixes more issues. This submission addresses privacy compliance comprehensively."
  1. 不要恐慌。未彻底修复前不要重新提交。
  2. 运行完整的预提交检查清单 —— not just the cited issue.
  3. 审核所有数据收集:每个SDK、每个分析调用、每个发送用户数据的API请求。
  4. 生成隐私报告(Product > Archive > Generate Privacy Report)并与隐私政策交叉对比。
  5. 修改隐私政策,明确列出所有实际收集的数据类型。
  6. 验证之前拒审的问题仍已修复(崩溃、元数据)。
  7. 若确实时间紧迫,在developer.apple.com/contact/app-store/?topic=expedite请求加急审核。
  8. 向利益相关方沟通:“每次审核都会修复更多问题。本次提交全面解决了隐私合规问题。”

Time comparison

时间对比

ApproachTime to Approval
Quick fix + resubmit7-14 more days (likely rejected again)
Full audit + thorough fix3-5 days (high confidence)
Full audit + expedited review1-3 days (if granted)
处理方式获得批准的时间
快速修复+重新提交7-14天(很可能再次被拒)
全面审核+彻底修复3-5天(高通过率)
全面审核+加急审核1-3天(若获批)

Professional communication template

专业沟通模板

To stakeholders:

"Root cause: Our third-party analytics SDK collects device identifiers
that weren't disclosed in our privacy policy or nutrition labels.

Fix: Updated privacy policy, privacy nutrition labels in ASC, and
PrivacyInfo.xcprivacy to accurately reflect all data collection.
Also audited all SDKs for undisclosed collection.

Timeline: Resubmitting today with expedited review request.
Expected approval: 1-3 business days.

Prevention: Adding privacy audit to our pre-submission checklist
so future submissions include accurate disclosure from the start."

致利益相关方:

“根本原因:我们的第三方分析SDK收集了设备标识符,但未在隐私政策和隐私营养标签中披露。

修复方案:更新了隐私政策、ASC中的隐私营养标签和PrivacyInfo.xcprivacy,以准确反映所有数据收集情况。同时审核了所有SDK的未披露数据收集情况。

时间线:今日重新提交并请求加急审核。预计1-3个工作日内获得批准。

预防措施:将隐私审核添加到预提交检查清单中,确保未来提交时从一开始就准确披露数据收集情况。”

Common Mistakes

常见错误

1. Skimming the Rejection Message

1. 略读拒审消息

Problem Developer reads "Guideline 5.1" and assumes they know the issue without reading the full explanation.
Why it fails Guideline 5.1 covers privacy policy, purpose strings, privacy manifest, tracking, AND data collection disclosure. The rejection message tells you exactly which aspect failed. Guessing the wrong one wastes a full review cycle (3-7 days).
Fix: Copy the FULL rejection text. Highlight every specific requirement mentioned. Map each one to the fix before writing any code.
问题 开发者看到“指南5.1”就假设知道问题,而未阅读完整说明。
后果 指南5.1涵盖隐私政策、权限说明字符串、隐私配置文件、用户追踪及数据收集披露。拒审消息会明确指出具体违规点。猜测错误会浪费一个完整的审核周期(3-7天)。
修复方案:复制完整的拒审文本。高亮提及的每个具体要求。在编写代码前将每个要求与修复方案对应。

2. Fixing Only the Cited Issue

2. 仅修复提及的问题

Problem Rejection cites Guideline 5.1 (privacy). Developer fixes privacy but doesn't check for other issues.
Why it fails Reviewers find new issues on each pass. First pass catches crashes, second catches metadata, third catches privacy. If you only fix privacy, the fourth pass might find a Guideline 4.8 (SIWA) issue.
Fix: Before every resubmission, run through ALL common rejection patterns (1-6). Fix everything proactively. One thorough submission beats three partial ones.
问题 拒审消息引用指南5.1(隐私)。开发者仅修复隐私问题,未检查其他问题。
后果 审核人员每次审核会发现新问题。第一次审核发现崩溃,第二次发现元数据问题,第三次发现隐私问题。若仅修复隐私问题,第四次审核可能会发现指南4.8(SIWA)问题。
修复方案:每次重新提交前,检查所有常见拒审模式(1-6)。主动修复所有问题。一次彻底提交胜过三次部分修复。

3. Resubmitting Without Changes

3. 未做修改就重新提交

Problem "Maybe a different reviewer will approve it."
Why it fails Reviewers see the rejection history. Unchanged resubmissions get the same result or escalated to senior reviewers. Each wasted cycle costs 3-7 days.
Fix: Always make at least the changes the reviewer requested. If you believe the rejection is wrong, reply in ASC with evidence first.
问题 “换个审核人员可能会通过。”
后果 审核人员会查看拒审历史。未修改的重新提交会得到相同结果,或升级到高级审核人员处理。每个浪费的周期会损失3-7天。
修复方案:至少完成审核人员要求的修改。若认为拒审错误,先在ASC中回复并提供证据。

4. Arguing Emotionally in App Review Messages

4. 在App Review消息中情绪化争论

Problem "This is unfair! Other apps do this! You're blocking our business!"
Why it fails App Review is a technical compliance review, not a negotiation. Emotional arguments are ignored. Specific evidence of compliance works.
Fix: Be factual, specific, and professional. Quote the guideline. Show screenshots. Provide technical evidence.
问题 “这太不公平了!其他应用也这么做!你们在阻碍我们的业务!”
后果 App Review是技术合规审核,并非谈判。情绪化争论会被忽略。具体的合规证据才有效。
修复方案:保持事实、具体、专业。引用指南条款。提供截图。提供技术证据。

5. Ignoring Third-Party SDK Issues

5. 忽略第三方SDK问题

Problem "We don't collect that data — it must be the SDK."
Why it fails Your app is responsible for ALL SDK behavior. If Facebook SDK collects device identifiers, YOUR privacy policy and nutrition labels must disclose it.
Fix: Audit every third-party SDK. Generate Privacy Report to see aggregate data collection. Update privacy policy and nutrition labels to cover all SDK behavior.
问题 “我们没有收集这些数据——肯定是SDK的问题。”
后果 应用需对所有SDK的行为负责。若Facebook SDK收集设备标识符,你的隐私政策和营养标签必须披露。
修复方案:审核每个第三方SDK。生成隐私报告查看汇总数据收集情况。更新隐私政策和营养标签以覆盖所有SDK的行为。

6. Deploying Backend Changes During Review

6. 审核期间部署后端变更

Problem Pushing a backend update that changes API responses while the app is under review.
Why it fails Reviewers may test at any time during the review window. A backend change that breaks the reviewed build = crash during review = Guideline 2.1 rejection.
Fix: Freeze backend during review period. If changes are necessary, ensure backward compatibility with the submitted build.
问题 审核期间推送后端更新,修改了API响应。
后果 审核人员可能在审核窗口内的任何时间测试应用。后端变更导致已审核的版本崩溃 = 指南2.1拒审。
修复方案:审核期间冻结后端更新。若必须变更,确保与提交的版本向后兼容。

7. Not Using Expedited Review When Available

7. 符合条件时未使用加急审核

Problem Developer doesn't know about or doesn't use expedited review for critical situations.
Why it fails Waiting 3-7 days for standard review when a 1-day expedited review is available for legitimate reasons.
Fix: Request expedited review at developer.apple.com/contact/app-store/?topic=expedite for: critical bug fixes, time-sensitive events, or security patches. Don't abuse it — Apple tracks usage and may deny future requests.

问题 开发者不知道或未在紧急情况下使用加急审核。
后果 本可使用1天的加急审核,却等待3-7天的标准审核。
修复方案:针对以下情况请求加急审核:关键Bug修复、时间敏感的活动、安全补丁。不要滥用——Apple会记录使用情况,可能会拒绝未来的请求。

Pre-Submission Checklist

预提交检查清单

Run through this BEFORE every App Store submission to prevent rejections:
App Completeness (2.1):
☐ Tested on latest shipping iOS version on physical device
☐ Tested on at least 2 device sizes (iPhone SE, iPhone Pro Max)
☐ No placeholder text (search: Lorem, TODO, FIXME, placeholder, sample)
☐ All URLs resolve (support URL, privacy policy, in-app links)
☐ Demo credentials provided if login required (non-expiring)
☐ Backend stable and not deploying during review window

Metadata (2.3):
☐ Screenshots taken from submitted build (not dev build)
☐ Every feature in description exists and works
☐ No trademarked terms in keywords
☐ Age rating matches content
☐ "What's New" text accurate

Privacy (5.1):
☐ Privacy policy accessible in-app AND via URL in ASC
☐ Privacy policy matches actual data collection
☐ Every permission has specific, honest purpose string
☐ PrivacyInfo.xcprivacy exists and lists all required reason APIs
☐ Privacy Report generated and cross-referenced
☐ ATT implemented if any cross-app tracking
☐ Privacy nutrition labels accurate (including third-party SDKs)

Sign in with Apple (4.8):
☐ If third-party login exists, SIWA offered at same prominence
☐ SIWA flow works: sign in, account creation, revocation handling
☐ Account deletion supported (required since June 2022)

Business (3.x):
☐ All digital goods/features use Apple IAP
☐ IAP products approved in ASC before app submission
☐ Subscription terms clear before purchase
☐ Loot box odds disclosed if applicable

Technical (Binary):
☐ Xcode version meets Apple's current requirements
☐ "Validate App" passes in Xcode Organizer
☐ ITSAppUsesNonExemptEncryption key present
☐ Provisioning profile not expired
☐ Tested with release configuration on device

每次App Store提交前运行以下清单,避免被拒:
应用完整性(2.1):
☐ 在最新正式版iOS的物理设备上测试过
☐ 至少在2种设备尺寸上测试过(iPhone SE、iPhone Pro Max)
☐ 无占位文本(搜索:Lorem、TODO、FIXME、placeholder、sample)
☐ 所有URL可访问(支持URL、隐私政策、应用内链接)
☐ 需要登录的应用提供了演示账号(不会过期)
☐ 后端稳定且审核期间不会部署更新

元数据(2.3):
☐ 截图来自提交的版本(而非开发版)
☐ 描述中提及的每个功能都已实现且可用
☐ 关键词中无商标术语
☐ 年龄分级与内容匹配
☐ “版本更新说明”准确

隐私(5.1):
☐ 隐私政策在应用内可访问,且在ASC中配置了URL
☐ 隐私政策与实际数据收集情况一致
☐ 每个权限都有具体、真实的说明字符串
☐ 存在PrivacyInfo.xcprivacy且列出了所有受限API
☐ 生成了隐私报告并交叉对比
☐ 若有跨应用追踪则已实现ATT
☐ 隐私营养标签准确(包括第三方SDK)

Sign in with Apple(4.8):
☐ 若有第三方登录,SIWA的显示优先级与其他登录选项一致
☐ SIWA流程可用:登录、账号创建、凭证撤销处理
☐ 支持账号删除(2022年6月起强制要求)

商业规则(3.x):
☐ 所有数字商品/功能使用Apple IAP
☐ 应用提交前IAP商品已在ASC中获批
☐ 订阅条款在购买前清晰展示
☐ 开箱类商品已披露概率(若适用)

技术要求(Binary):
☐ Xcode版本符合Apple当前要求
☐ 在Xcode Organizer中“Validate App”通过
☐ 存在ITSAppUsesNonExemptEncryption键
☐ 配置文件未过期
☐ 使用发布配置在物理设备上测试过

Cross-References

交叉引用

  • app-store-connect-ref — ASC crash analysis, TestFlight feedback, metrics dashboards
  • privacy-ux — Privacy manifest implementation details and required reason APIs
  • storekit-ref — StoreKit 2 IAP/subscription implementation
  • accessibility-diag — Accessibility compliance (Guideline 2.5.1)
  • ios-build — Build and signing issues that cause Binary Rejected
  • app-store-connect-ref —— ASC崩溃分析、TestFlight反馈、指标仪表盘
  • privacy-ux —— 隐私配置文件实现细节及受限API
  • storekit-ref —— StoreKit 2 IAP/订阅实现
  • accessibility-diag —— 无障碍合规性(指南2.5.1)
  • ios-build —— 导致Binary Rejected的构建和签名问题

Resources

资源

WWDC: 2025-328
Docs: /app-store/review/guidelines, /distribute/app-review, /support/offering-account-deletion-in-your-app, /contact/app-store/?topic=appeal
Skills: app-store-connect-ref, privacy-ux, storekit-ref, accessibility-diag
WWDC: 2025-328
文档: /app-store/review/guidelines, /distribute/app-review, /support/offering-account-deletion-in-your-app, /contact/app-store/?topic=appeal
相关技能: app-store-connect-ref, privacy-ux, storekit-ref, accessibility-diag