跳转到正文

iOS App Store 内购 (IAP) 审核指南

GitHub

让 App 在 App Store 通过审核,需要仔细遵循 Apple 的指南,尤其是在实现应用内购买和订阅时。本指南涵盖首次提交就能通过审核所需了解的一切。

iOS App Store 审核流程

在 Apple 审核你的购买流程之前,请确保 App Store Connect 中的应用信息已填写完整:

  • 添加一个 隐私政策 URL 在 App Store Connect 中
  • 添加一个 支持 URL 能引导用户找到真实联系方式的
  • 完成 年龄分级 问卷,以便应用可发布
  • 添加 App Review 联系方式 以及清晰的审核备注
  • 如果需要登录,请提供一个 在审核期间不会过期的演示账号
包含政策与支持链接的 App Store 上架元数据
  • 请使用正在审核的实际 build 的当前截图
  • 针对 iPhone, 1290 x 2796 (6.7 英寸) 是最简单的默认尺寸
  • 如果您的应用支持 iPad,请同时 upload iPad 截图
  • 目前通过审核的大尺寸 iPad 规格包括 2064 x 2752 (13 英寸) 以及 2048 x 2732 (12.9 英寸)
  • 切勿通过拉伸 iPhone 截图来伪造 iPad 支持

在真机上完整模拟 Apple 的审核路径:

  • 从 TestFlight 安装最新的 build
  • 使用你准备提供的审核账号登录
  • 进入付费墙,确保没有隐藏手势或调试菜单
  • 完成购买、恢复购买及管理订阅流程
  • 验证在拒绝权限请求时,App 仍能正常运行

Apple 要求在任何购买前极其清晰地披露价格:

必备要素:

  • 在购买按钮前显示准确价格
  • 显示计费周期(例如:“$9.99/月”)
  • 清晰说明用户付费后可获得的权益
  • 注明扣费发生的时间点

常见拒审原因:

“订阅价格必须清晰且事先明示。”

:::caution 价格一致性 所有价格必须在以下各项中保持一致:

  • App Store 元数据页面
  • 应用内购买界面
  • 订阅管理界面

即使商店详情页 ($4.99) 与 App 内价格 ($5.99) 只差 $1,也会触发自动拒审。 :::

必须包含的披露信息:

  • 所有可用的订阅层级需同时展示
  • 各层级功能的清晰对比
  • 禁止通过 UI 技巧默认勾选高级订阅层级
  • 易于查找的取消订阅说明

UI 设计该做与不该做

包含恢复购买和法律链接的 Paywall

合规 UI 示例:

import { NativePurchases } from '@capgo/native-purchases';
function SubscriptionScreen() {
return (
<div>
<h2>Choose Your Plan</h2>
{/* Show all tiers equally */}
<PlanCard
title="Basic"
price="$4.99/month"
features={['Feature A', 'Feature B']}
/>
<PlanCard
title="Premium"
price="$9.99/month"
features={['All Basic', 'Feature C', 'Feature D']}
highlighted={false} // Don't force premium
/>
{/* Clear cancellation info */}
<Text>
Cancel anytime in Settings > Subscriptions.
No refunds for partial periods.
</Text>
</div>
);
}

必须实现:

所有带 IAP 的应用都必须提供一种方式,让用户无需联系客服即可恢复之前的购买记录。

import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases';
async function restorePurchases() {
try {
await NativePurchases.restorePurchases();
const { purchases } = await NativePurchases.getPurchases({
productType: PURCHASE_TYPE.SUBS,
});
const activeSub = purchases.find(
(purchase) => purchase.isActive && purchase.expirationDate,
);
if (activeSub) {
unlockPremiumFeatures();
showMessage('Purchases restored successfully!');
return;
}
const { purchases: iaps } = await NativePurchases.getPurchases({
productType: PURCHASE_TYPE.INAPP,
});
const hasIap = iaps.some((purchase) => purchase.productIdentifier === 'premium_unlock');
showMessage(
hasIap ? 'Premium purchase restored!' : 'No previous purchases found.',
);
} catch (error) {
showError('Failed to restore purchases. Please try again.');
}
}
// Add a visible "Restore Purchases" button
<Button onClick={restorePurchases}>
Restore Purchases
</Button>

失败原因:

  • 应用在启动时崩溃
  • 购买流程无法完成
  • 截图中展示的功能无法使用

预防措施:

  • 在真机上测试(不只是模拟器)
  • 端到端测试所有订阅流程
  • 验证收据校验是否正常工作
  • 检查网络错误处理

失败原因:

  • 截图展示了当前版本中没有的功能
  • 描述中提到了不存在的功能
  • 元数据中的价格与应用内价格不一致

元数据检查清单

预防措施:

// Document exactly what's in each tier
const SUBSCRIPTION_FEATURES = {
basic: ['Ad-free', 'Cloud sync', 'Basic themes'],
premium: ['Ad-free', 'Cloud sync', 'All themes', 'Priority support']
};
// Use these in both your app AND App Store description

失败原因:

  • 未说明用途就请求相机/位置/健康权限
  • 权限请求被埋在多层页面深处
  • 权限描述模糊或过于笼统

预防措施:

更新您的 Info.plist 附带清晰的解释:

权限说明文案过于模糊,难以审核 权限说明文案解释更清晰
<key>NSCameraUsageDescription</key>
<string>Camera access is needed to scan product barcodes for quick subscription upgrades.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Location helps us show relevant local content in your Premium subscription.</string>

失败原因:

  • 缺乏证据的“全球排名第一”等说法
  • 带有隐藏限制的“无限”功能
  • 虚假的紧迫感策略(如“仅剩 2 个名额!”)

描述指南示例

补充描述指南

预防措施:

  • 描述应具体且基于事实
  • 避免使用缺乏证据的最高级词汇
  • 不要利用虚假的紧迫感向用户施压

失败原因:

  • 未提及如何取消订阅
  • 取消按钮被隐藏或难以找到
  • 取消流程过于繁琐,未遵循 Apple 原生流程

预防措施:

// Always inform users about cancellation
function SubscriptionInfo() {
return (
<div>
<h3>How to Cancel</h3>
<ol>
<li>Open iPhone Settings</li>
<li>Tap your name at the top</li>
<li>Tap Subscriptions</li>
<li>Select this app and tap Cancel</li>
</ol>
<p>Or manage directly in the App Store app.</p>
<Button onClick={openSubscriptionManagement}>
Manage Subscription in Settings
</Button>
</div>
);
}
async function openSubscriptionManagement() {
// Direct link to iOS subscription management
await NativePurchases.showManageSubscriptions();
}

Apple 在 2025 年大幅收紧了隐私合规要求。

针对每项权限:

  1. 为何需要该权限 (具体使用场景)
  2. 何时会使用该权限
  3. 数据如何存储/共享
  4. 是可选还是必选
async function requestCameraPermission() {
// Show explanation BEFORE requesting
await showDialog({
title: 'Camera Access',
message: 'We need camera access to let you scan barcodes for quick product lookup. Your photos are never uploaded or stored.',
buttons: ['Not Now', 'Allow']
});
// Then request permission
const result = await Camera.requestPermissions();
return result.camera === 'granted';
}

请确保您的 App Store 隐私标签准确反映了:

  • 收集购买历史记录
  • 邮箱地址(用于收据)
  • 设备 ID(用于防欺诈)
  • 使用数据(用于分析)

隐私标签不准确是 2025 年常见的审核拒绝原因。请仔细审计您的数据收集情况。

提交前检查清单

  1. 测试所有购买流程

    • 购买各级订阅方案
    • 测试免费试用
    • 验证推介优惠是否正确生效
    • 测试恢复购买
    • 验证家人共享(如已启用)
    • 在多台设备上测试
  2. 验证价格一致性

    • 检查 App Store 元数据是否与应用内价格一致
    • 验证所有货币金额是否正确
    • 确认免费试用时长与描述一致
    • 检查推介优惠条款是否准确
  3. 审核所有文案

    • 移除占位文本
    • 验证功能描述是否可测试
    • 检查语法和拼写
    • 确保描述与当前 build 一致
    • 移除竞品提及
  4. 测试权限

    • 仅请求必要的权限
    • 在请求权限前显示清晰说明
    • 测试“拒绝”流程(App 应仍能正常运行)
    • 验证 Info.plist 描述是否清晰
  5. 准备测试账号

    • 创建一个在审核期间持续有效的审核账号
    • 在 App Review 信息中记录登录凭据
    • 验证审核人员能否进入付费墙并完成购买流程
    • 如有需要,在 Notes 字段中附上额外账号或应用专属开关
  6. 检查元数据

    • 截图与当前 UI 一致
    • Support URL 需包含真实的联系方式
    • 填写隐私政策 URL
    • 年龄分级与 Build 中的内容相符
    • App 预览视频(如有)需展示当前版本
    • 描述需准确反映功能特性
    • 隐私政策在 App 内及商店详情页均可访问
  7. 撰写详细的审核备注

    Contact:
    Name: Jane Developer
    Email: review@yourapp.com
    Phone: +1 555-0100
    Test Account:
    Email: reviewer@test.com
    Password: TestPass123!
    This account does not expire during review.
    Testing Instructions:
    1. Log in with test account above
    2. Tap "Upgrade to Premium" button
    3. Select "Monthly Premium" subscription
    4. Complete purchase (no charge in sandbox)
    5. Verify premium features unlock
    Note: Subscription pricing is clearly shown before purchase.
    Cancellation instructions are in Settings > Account.

App Store 审核时间线

标准审核: 24-48 小时 高峰期: 3-5 天(App Store 节假日发布) 周末: 不处理审核 加急审核: 可用于修复严重 Bug(需通过 App Store Connect 申请)

您在 App Store Connect 中会看到的常见状态:

  • Waiting for Review
  • In Review
  • Pending Developer Release
  • Rejected

1. 订阅清晰度

  • 需要提供并排的套餐对比
  • 严禁使用隐藏低价选项的“暗黑模式”
  • 明确降级/升级路径

2. 元数据准确性

  • 截图必须与正在审核的版本一致
  • 如果启用了 iPad 支持,则必须提供 iPad 截图
  • 提交前应确保支持 URL 和隐私政策已上线

3. 隐私与审核详情质量

  • 隐私披露必须与 SDK 实际收集的数据一致
  • 首次提交时应完善 App Review 联系信息和备注
  • 演示账号在整个审核期间必须保持有效

4. 提交准备情况

  • Apple 会定期更新 SDK 的最低要求,因此在上传 release build 前请确认当前的截止日期
  • 在正式提交前,使用 TestFlight 是验证审核流程最安全的方式
import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases';
async function handlePurchase(productId: string) {
try {
const transaction = await NativePurchases.purchaseProduct({
productIdentifier: productId,
productType: PURCHASE_TYPE.SUBS,
});
// Success
await validateReceiptOnServer(transaction.receipt);
showSuccess('Subscription activated!');
unlockFeatures();
} catch (error: any) {
// Handle specific error cases
if (error.code === 'USER_CANCELLED') {
// User cancelled - don't show error
console.log('Purchase cancelled by user');
} else if (error.code === 'PAYMENT_PENDING') {
showInfo('Payment is pending. Please check back later.');
} else if (error.code === 'PRODUCT_ALREADY_PURCHASED') {
// Restore instead
await NativePurchases.restorePurchases();
} else {
// Show user-friendly error
showError('Unable to complete purchase. Please try again.');
}
}
}
function PurchaseButton({ productId }: { productId: string }) {
const [loading, setLoading] = useState(false);
const handlePurchase = async () => {
setLoading(true);
try {
await NativePurchases.purchaseProduct({ productIdentifier: productId });
} finally {
setLoading(false);
}
};
return (
<button onClick={handlePurchase} disabled={loading}>
{loading ? 'Processing...' : 'Subscribe Now'}
</button>
);
}
function SubscriptionTerms() {
return (
<div className="terms">
<p>
Subscription automatically renews unless cancelled at least 24 hours
before the end of the current period.
</p>
<p>
Your account will be charged for renewal within 24 hours prior to
the end of the current period.
</p>
<p>
Subscriptions may be managed by the user and auto-renewal may be
turned off in Account Settings after purchase.
</p>
<p>
<a href="/terms">Terms of Service</a> |
<a href="/privacy/">Privacy Policy</a>
</p>
</div>
);
}

如果您的 App 被拒绝

“如果您的 App 被拒绝”章节
  1. 仔细阅读拒审通知

    • 记下引用的具体准则(例如 3.1.1、5.1.1)
    • 准确理解 Apple 指出的问题
  2. 彻底修复问题

    • 不要只打补丁,要解决根本原因
    • 充分测试修复效果
    • 记录您做了哪些更改
  3. 在 Resolution Center 中回复

    Thank you for your feedback. I have addressed the issue:
    Issue: Subscription pricing not clear upfront
    Fix: Added explicit pricing display on subscription selection
    screen showing "$9.99/month" before purchase button. Also added
    cancellation instructions on the same screen.
    The changes are in this submission and can be tested using the
    provided test account.
  4. 尽快重新提交

    • 重新提交通常审核更快
    • 通常在 24 小时内

如果你认为拒审有误:

App Store 澄清流程

  1. 在 App Store Connect 中点击“申诉”
  2. 提供明确证据:
    • 证明符合规范的截图
    • 引用具体的审核指南
    • 说明你如何满足要求
  3. 保持专业且陈述事实
  4. 若功能较难查找,请提供测试账号

提交文档示例

如果仍有问题:

应用审核遇到困难,或需要个性化帮助? 与我们的团队预约咨询通话 获取以下方面的专属支持:

  • IAP 实现审查与优化
  • App Store 审核准备与策略
  • 提交清单检查
  • 被拒处理与申诉
  • 完成测试与验证

我们的专家已成功帮助数百款 App 通过审核!

继续阅读 iOS App Store 审核指南中关于 IAP 的内容

章节标题:“继续阅读 iOS App Store IAP 审核指南”

如果你正在使用 iOS App Store 内购 (IAP) 审核指南 要规划商店审核与分发,请将其与 使用 @capgo/native-purchases 关于“使用 @capgo/native-purchases”中的原生能力, @capgo/capacitor-in-app-review 有关 @capgo/capacitor-in-app-review 中的实现细节, 使用 @capgo/capacitor-in-app-review 有关《使用 @capgo/capacitor-in-app-review》中的原生能力, @capgo/capacitor-native-market 有关 @capgo/capacitor-native-market 的实现细节,以及 使用 @capgo/capacitor-native-market 有关使用 @capgo/capacitor-native-market. 时的原生能力