axiom-app-store-diag
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseApp 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:
- Read the FULL rejection message — Don't skim. Copy the exact text. Note every guideline number cited.
- 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
- Check the specific guideline — Look up the exact number in app-store-ref
- Screenshot the rejection — Save for team communication and appeal reference
- Check App Review messages in ASC — Sometimes they ask for information, not reject
在修改任何代码之前,必须完成以下步骤:
- 完整阅读拒审消息 —— 不要略读。复制完整文本,记录所有引用的指南编号。
- 识别拒审类型:
- “App Rejected” → 违反指南,需要修改代码/内容
- “Metadata Rejected” → App Store Connect(ASC)元数据问题,无需构建新版本
- “Binary Rejected” → 技术关卡失败(SDK、配置文件、加密等问题)
- “Removed from Sale” → 应用上架后被强制下架
- 查阅具体指南 —— 在app-store-ref中查找对应的指南编号
- 截图保存拒审消息 —— 用于团队沟通和申诉参考
- 查看ASC中的App Review消息 —— 有时他们只是要求提供信息,并非拒审
What this tells you
这些步骤的作用
| Rejection Type | What Changed | Next Step |
|---|---|---|
| "App Rejected" + Guideline 2.1 | App crashed or had placeholders | Pattern 1 |
| "Metadata Rejected" | Screenshots or description wrong | Pattern 2 |
| "App Rejected" + Guideline 5.1 | Privacy policy or manifest gaps | Pattern 3 |
| "App Rejected" + Guideline 4.8 | Missing Sign in with Apple | Pattern 4 |
| "App Rejected" + Guideline 3.x | Business/monetization violation | Pattern 5 |
| "Binary Rejected" / no guideline | SDK, signing, or encryption issue | Pattern 6 |
| Reviewer seems incorrect | Genuine misunderstanding | Pattern 7 |
| Guideline 1.x cited | Safety/content issue | Content review needed |
| Guideline 4.1-4.3 cited | Design/originality issue | Functionality 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:
- If "App Rejected" with guideline number → Map to specific pattern (1-5)
- If "Metadata Rejected" → Fix in ASC, no build required (Pattern 2)
- If "Binary Rejected" → Technical gate failure (Pattern 6)
- 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.
- If reviewer asks for information → Reply in ASC before making code changes
在修改任何代码之前,必须确定以下情况之一:
- 如果是“App Rejected”且带有指南编号 → 对应到特定模式(1-5)
- 如果是“Metadata Rejected” → 在ASC中修复,无需构建新版本(模式2)
- 如果是“Binary Rejected” → 技术关卡失败(模式6)
- 如果引用了多个指南编号 → 修复所有提及的问题,而不仅仅是第一个。二进制和元数据问题可能同时存在——二进制问题需要重新构建版本,元数据问题可在ASC中修复。重新提交前需修复所有问题。
- 如果审核人员要求提供信息 → 在修改代码前先在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/functionalityApp 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:
- Copy the exact rejection text — Word for word, including guideline numbers
- Match guideline number to pattern — Don't guess, map directly
- If multiple guidelines cited — Fix ALL of them before resubmitting
- If no guideline number — Likely Binary Rejected, start with Pattern 6
- If unsure — Reply to reviewer for clarification first
在使用具体模式之前:
- 复制完整的拒审文本 —— 一字不差,包括指南编号
- 将指南编号与模式对应 —— 不要猜测,直接匹配
- 如果引用了多个指南编号 —— 重新提交前修复所有问题
- 如果没有指南编号 —— 很可能是Binary Rejected,从模式6开始排查
- 如果不确定 —— 先回复审核人员要求澄清
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
常见原因
- App crashes on reviewer's device (different OS version, different device class)
- Placeholder text or images visible in any screen
- Broken links (support URL, privacy policy, in-app links)
- Missing demo credentials for login-required apps
- Backend service was down during review window
- 应用在审核人员的设备上崩溃(不同OS版本、不同设备类型)
- 任何界面存在占位文本或图片
- 存在无效链接(支持URL、隐私政策、应用内链接)
- 需要登录的应用缺少演示账号
- 审核期间后端服务宕机
Diagnosis
诊断
bash
undefinedbash
undefined1. 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" .
--include=".swift" --include=".storyboard" --include="*.xib" .
grep -r "Lorem|TODO|FIXME|placeholder|sample|test data"
--include=".swift" --include=".storyboard" --include="*.xib" .
--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版本
undefinedundefinedFix
修复方案
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
常见原因
- Screenshots show old UI or features that no longer exist
- Description promises features not yet implemented
- Keywords contain trademarked terms or competitor names
- App name implies functionality that doesn't exist
- Category selection doesn't match app's primary function
- 截图展示的是旧版UI或已移除的功能
- 描述中承诺了尚未实现的功能
- 关键词包含商标或竞品名称
- 应用名称暗示了未实现的功能
- 类别选择与应用主要功能不符
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
常见原因
- Privacy policy missing or not accessible from within the app
- Privacy policy doesn't match actual data collection
- Missing purpose strings for permission requests
- Privacy manifest (PrivacyInfo.xcprivacy) missing required reason API declarations
- Third-party SDK collects data not disclosed in privacy nutrition labels
- App tracks users without ATT (App Tracking Transparency) consent
- 缺少隐私政策,或应用内无法访问隐私政策
- 隐私政策与实际数据收集情况不符
- 权限请求缺少说明字符串
- 缺少隐私配置文件(PrivacyInfo.xcprivacy)中要求的API声明
- 第三方SDK收集了隐私营养标签中未披露的数据
- 未获得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 APIsswift
// 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
常见原因
- App has Google/Facebook/Twitter login but no SIWA
- SIWA button exists but doesn't work
- SIWA not offered at equal prominence (hidden or secondary)
- SIWA flow doesn't handle credential revocation
- 应用有Google/Facebook/Twitter登录但无SIWA
- SIWA按钮存在但无法使用
- SIWA的显示优先级低于其他登录选项(隐藏或次要位置)
- 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
常见原因
- Digital content unlocked without IAP (using external payment for in-app features)
- Subscription doesn't provide ongoing value (one-time content sold as subscription)
- Loot box or random item purchase odds not disclosed
- Deceptive subscription flow (dark patterns, misleading free trial)
- IAP metadata incomplete or not submitted for review
- 数字内容未使用Apple IAP解锁(使用外部支付渠道解锁应用内功能)
- 订阅未提供持续价值(一次性内容以订阅形式售卖)
- 开箱类或随机商品未披露概率
- 欺骗性订阅流程(暗模式、误导性免费试用)
- 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
常见原因
- Built with outdated SDK version (must meet Apple's minimum)
- Privacy manifest (PrivacyInfo.xcprivacy) missing or invalid
- Encryption compliance not declared (ITSAppUsesNonExemptEncryption)
- Invalid signing or provisioning profile
- Missing required device capabilities in Info.plist
- App uses private or deprecated APIs
- App binary too large without on-demand resources
- 使用过时的SDK版本(必须符合Apple的最低要求)
- 缺少或无效的隐私配置文件(PrivacyInfo.xcprivacy)
- 未申报加密合规(ITSAppUsesNonExemptEncryption)
- 签名或配置文件无效
- Info.plist中缺少必需的设备权限
- 应用使用私有或废弃API
- 应用包过大且未使用按需资源
Diagnosis
诊断
bash
undefinedbash
undefined1. 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问题
undefinedundefinedFix
修复方案
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:
- Does your app use ONLY standard OS-provided HTTPS (URLSession, Alamofire)? → Set , done
false - Does your app call OpenSSL, libsodium, or custom crypto directly? → Set , upload BIS docs
true - Does your app implement proprietary encryption protocols? → Set , upload BIS docs
true - Unsure? → Run to check
strings YourApp | grep -i "openssl\|libcrypto\|CCCrypt"
bash
undefinedxml
<!-- 加密合规(Info.plist) -->
<!-- 如果应用仅使用标准HTTPS(URLSession等) -->
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<!-- 如果应用使用HTTPS以外的自定义加密 -->
<key>ITSAppUsesNonExemptEncryption</key>
<true/>
<!-- 然后在ASC中上传出口合规文档:
App Store Connect → 我的App → [应用名称] → 应用信息 →
出口合规信息 → 上传文档
您可能还需要向美国工业和安全局(BIS)提交年度自我分类报告 -->加密决策流程:
- 应用是否仅使用系统提供的标准HTTPS(URLSession、Alamofire)? → 设置为,完成
false - 应用是否直接调用OpenSSL、libsodium或自定义加密库? → 设置为,上传BIS文档
true - 应用是否实现了专有加密协议? → 设置为,上传BIS文档
true - 不确定? → 运行检查
strings YourApp | grep -i "openssl\|libcrypto\|CCCrypt"
bash
undefinedValidate 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偏好设置 → 账号中重新下载配置文件
undefinedundefinedVerification
验证步骤
- 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:
- Request a phone call with App Review (available through appeal process)
- Contact Apple Developer Relations as last resort
- Consider whether the app genuinely needs architectural changes
若申诉被驳回:
- 通过申诉流程请求与App Review进行电话沟通
- 最后可联系Apple Developer Relations
- 考虑应用是否需要架构调整
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 Type | Likely Cause | First Check | Pattern | Typical Fix Time |
|---|---|---|---|---|
| Guideline 2.1 | Crashes/placeholders | Test on device, search placeholders | 1 | 1-3 days |
| Guideline 2.3 | Metadata mismatch | Compare screenshots to app | 2 | 1 day (no build) |
| Guideline 5.1 | Privacy gaps | Check policy + manifest + purpose strings | 3 | 2-5 days |
| Guideline 4.8 | Missing SIWA | Check for third-party login | 4 | 3-5 days |
| Guideline 3.x | Payment method | Review IAP flows | 5 | 3-14 days |
| Binary Rejected | Technical gate | Check SDK, manifest, encryption | 6 | 1-2 days |
| Guideline 1.x | Safety/content | Review content policy | N/A | Varies |
| Guideline 4.1-4.3 | Design/originality | Review app uniqueness | N/A | Varies |
| 拒审类型 | 可能原因 | 首要检查项 | 模式 | 典型修复时间 |
|---|---|---|---|---|
| 指南2.1 | 崩溃/占位内容 | 设备测试、搜索占位内容 | 1 | 1-3天 |
| 指南2.3 | 元数据不匹配 | 对比截图与应用 | 2 | 1天(无需构建版本) |
| 指南5.1 | 隐私漏洞 | 检查政策+配置文件+权限说明字符串 | 3 | 2-5天 |
| 指南4.8 | 缺少SIWA | 检查第三方登录 | 4 | 3-5天 |
| 指南3.x | 支付方式违规 | 审核IAP流程 | 5 | 3-14天 |
| Binary Rejected | 技术关卡失败 | 检查SDK、配置文件、加密 | 6 | 1-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)
理性陷阱(切勿陷入)
-
"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
-
"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
-
"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)
-
"Different reviewer next time might not notice"
- Reviewers see the rejection history — they check previously cited issues
- Repeat rejections get escalated to senior reviewers
-
“只需修改隐私政策措辞然后重新提交”
- 审核人员指出“与实际数据收集情况不符”
- 这意味着应用收集了未披露的数据
- 仅修改措辞而不审核实际数据收集情况 = 再次被拒
-
“审核人员太不讲理,我们申诉吧”
- 三次被拒对应三个不同的有效问题,并非审核人员不讲理
- 申诉会浪费3-14天,而彻底修复只需1-3天
-
“移除隐私敏感功能以加快发布”
- 移除功能会改变应用,需要重新审核所有内容
- 可能引入新问题(UI损坏、功能缺失)
-
“换个审核人员可能不会注意到”
- 审核人员会查看拒审历史 —— 他们会检查之前提及的问题
- 多次拒审会升级到高级审核人员处理
MANDATORY approach
强制处理方法
- Don't panic. Don't resubmit without a thorough fix.
- Run the COMPLETE pre-flight checklist — not just the cited issue.
- Audit all data collection: every SDK, every analytics call, every API request that sends user data.
- Generate privacy report (Product > Archive > Generate Privacy Report) and cross-reference with privacy policy.
- Fix privacy policy to specifically list every data type actually collected.
- Verify all previous rejection issues still fixed (crashes, metadata).
- Request expedited review at developer.apple.com/contact/app-store/?topic=expedite if genuinely time-critical.
- Communicate to stakeholders: "Each review fixes more issues. This submission addresses privacy compliance comprehensively."
- 不要恐慌。未彻底修复前不要重新提交。
- 运行完整的预提交检查清单 —— not just the cited issue.
- 审核所有数据收集:每个SDK、每个分析调用、每个发送用户数据的API请求。
- 生成隐私报告(Product > Archive > Generate Privacy Report)并与隐私政策交叉对比。
- 修改隐私政策,明确列出所有实际收集的数据类型。
- 验证之前拒审的问题仍已修复(崩溃、元数据)。
- 若确实时间紧迫,在developer.apple.com/contact/app-store/?topic=expedite请求加急审核。
- 向利益相关方沟通:“每次审核都会修复更多问题。本次提交全面解决了隐私合规问题。”
Time comparison
时间对比
| Approach | Time to Approval |
|---|---|
| Quick fix + resubmit | 7-14 more days (likely rejected again) |
| Full audit + thorough fix | 3-5 days (high confidence) |
| Full audit + expedited review | 1-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