跳过内容

Android Play Store IAP审查指南

GitHub

在 Google Play 上获得 Android 应用程序批准需要遵守 Google 的政策,特别是具有内购和订阅功能的应用程序。这份指南涵盖了您需要通过审核成功的所有内容。

Release Path That Works

Release Path That Works
  1. Build a Signed Android App Bundle

    新 Google Play 应用程序应以 Android App Bundle 的形式上传(.aab),而不是 sideloaded debug APK。

    Keep your versionCode 每次上传都会

    Android App Bundle 流程

  2. 在 Play Console 中创建 App 记录

    如果您尚未注册开发者账户,请先 Play Console 注册然后在 首页 > 创建应用选择语言、应用/游戏类型、免费/付费状态、支持邮箱和接受所需的声明。

    选择免费/付费设置时要小心。Google允许您将付费应用切换为免费应用,但一旦应用被免费提供后,就无法切换为付费。

    在Play Console中创建应用

  3. 完成应用内容和商店列表

    在生产预览之前,完成所需的Play Console声明:

    • 隐私政策
    • 广告
    • 应用访问
    • 目标受众和内容
    • 内容评级
    • 数据安全
    • 如果适用,请注意敏感权限声明
  4. 运行一个Play-安装的测试轨迹

    内部测试 进行快速QA。如果您的开发者帐户是创建于2023年11月13日之后的个人帐户,则您还必须完成一个 封闭测试 至少有12名已同意的测试者参与14天的测试后才能获得生产访问权限。

    Play控制台中的内部测试

  5. 验证结算端到端

    从Google Play安装应用,而不是从本地导出的APK。然后确认:

    • 产品从Play正确加载
    • 购买单据显示 test purchase 测试版购买
    • Entitlements unlock after purchase
    • 购买后解锁特权

Restore and subscription management flows work

恢复和订阅管理流程正常工作

Google Play Billing Requirements

Google PlayBilling要求

Section titled “Google Play Billing Requirements” Google PlayBilling要求 Mandatory Billing System

强制付款系统

  • 高级功能的订阅
  • 应用内货币或积分
  • 数字内容(电子书,音乐,视频)
  • 游戏升级和强化
  • 应用解锁和高级等级

实物商品(无法使用Play Billing):

  • 实物商品
  • 现实世界服务
  • 非营利组织一次性捐赠

:::note 订阅设置 在Play Console中,使用当前的 订阅->基础计划->offer 模型在Android订阅中配置。 native-purchases请传递 Base 计划 ID planIdentifier. :::

原生购买的实施

原生购买的实施
import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases';
// Ensure billing is available on the device
const { isBillingSupported } = await NativePurchases.isBillingSupported();
if (!isBillingSupported) throw new Error('Google Play Billing not available');
// Fetch subscription products (Store data is required—never hardcode pricing)
const { products } = await NativePurchases.getProducts({
productIdentifiers: ['premium_monthly', 'premium_yearly'],
productType: PURCHASE_TYPE.SUBS,
});
// Plan identifiers are the Base Plan IDs you create in Google Play Console
const transaction = await NativePurchases.purchaseProduct({
productIdentifier: 'premium_monthly',
planIdentifier: 'monthly-plan', // REQUIRED on Android, ignored on iOS
productType: PURCHASE_TYPE.SUBS,
});
console.log('Purchase token for server validation:', transaction.purchaseToken);

透明度和披露要求

透明度和披露要求

预付费定价披露

预付费定价披露

Google Play 需要在购买前清晰披露所有费用:

必需元素:

  • 用户本地货币的精确价格
  • 计费频率(每月、每年等)
  • 订阅包含哪些内容
  • 初期优惠的总费用
  • 收费将在何时发生

UI 设计最佳实践

符合要求的 UI 示例:

function SubscriptionCard({ product }) {
return (
<div className="subscription-card">
<h3>{product.title}</h3>
{/* Show intro offer if available */}
{product.introductoryPrice && (
<div className="intro-offer">
<p className="intro-price">{product.introductoryPriceString}</p>
<p className="intro-period">
for {product.introductoryPricePeriod}
</p>
</div>
)}
{/* Regular price */}
<div className="regular-price">
<p className="price">{product.priceString}</p>
<p className="period">per {product.subscriptionPeriod}</p>
</div>
{/* Clear description */}
<p>{product.description}</p>
{/* Renewal terms */}
<p className="terms">
Renews automatically. Cancel anytime in Google Play.
</p>
<button onClick={() => handlePurchase(product)}>
Subscribe Now
</button>
</div>
);
}

自动续订说明

自动续订说明

在订阅自动续订之前,Google 需要:

  • 清晰的通知,续订将发生
  • 续订价格的提示
  • 取消订阅的便捷访问

跨平台定价透明度

标题:跨平台定价透明度

如果您在多个平台上出售相同的权利,保持产品命名、计费周期、包含的福利和续订语言一致,以免用户感到惊讶。

由于税收、当地货币或商店经济学,价格可以合理地不同,但购买 UI 必须永远不会隐藏这些差异或暗示 Google Play 将收取的续订成本与实际不同。

隐私政策要求

标题:隐私政策要求

强制隐私政策

标题:强制隐私政策

如果您的应用程序包含内购功能,则必须:

  1. 在Google Play商店列表中显示链接

    • 在Google Play控制台中添加隐私政策URL
    • 必须是公开可访问的
    • 必须与您的应用程序语言一致
  2. 在应用程序内显示链接

    • 在应用程序设置中显示隐私政策
    • 在收集用户数据之前显示
    • 使其容易发现

示例实现:

function SettingsScreen() {
const openPrivacyPolicy = () => {
window.open('https://yourapp.com/privacy', '_blank');
};
const openTerms = () => {
window.open('https://yourapp.com/terms', '_blank');
};
return (
<div>
<h2>Settings</h2>
<button onClick={openPrivacyPolicy}>
Privacy Policy
</button>
<button onClick={openTerms}>
Terms of Service
</button>
<button onClick={() => NativePurchases.manageSubscriptions()}>
Manage Subscriptions
</button>
</div>
);
}

Google Play 需要在数据安全部分详细说明:

对于 IAP 应用程序,声明:

  • 收集购买历史
  • 电子邮件地址(用于收据)
  • 设备 ID(用于欺诈防御)
  • 处理付款信息
  • 收集分析数据

数据安全部分是法律约束。错误的声明可能导致应用程序被移除。

Google Play 的审查不仅仅是关于二进制文件。发布之前,完成以下声明: 政策和计划 > 应用程序内容.

需要仔细审查的最小集合:

  • 隐私政策: 在 Play Console 中的公共 URL, 加上在需要时的内应用入口点
  • 广告: 声明应用是否包含广告
  • 应用访问: 提供给审查员工作凭证或清晰的测试路径, 如果有任何屏幕被锁定
  • 目标受众和内容: 匹配应用的真实受众
  • 内容评级: 完成 IARC 问卷, 以确保应用不被标记为未评级
  • 数据安全: 正确声明收集、共享和安全性实践

常见拒绝原因

标题:常见拒绝原因

1. 缺失或错误的账单实施

标题:1. 缺失或错误的账单实施

为什么会失败:

  • 未使用 Google Play Billing 购买数字商品
  • 使用过时的计费API
  • 为订阅实现自定义支付解决方案

预防措施:

// ✅ Correct: Use native-purchases (uses Google Play Billing)
await NativePurchases.purchaseProduct({
productIdentifier: 'premium_monthly',
planIdentifier: 'monthly-plan',
productType: PURCHASE_TYPE.SUBS,
});
// ❌ Wrong: Custom payment processor for subscriptions
// await CustomPayment.charge(user, 9.99);

2. 价格不明确或隐含费用

标题:2. 价格不明确或隐含费用

为什么会失败:

  • 仅在点击购买后显示价格
  • 未在订购前公开额外费用
  • 订阅条款不明确

预防措施:

function PurchaseScreen({ product }) {
return (
<div>
{/* Show ALL costs upfront */}
<h2>Premium Subscription</h2>
<div className="pricing">
<p className="price">{product.priceString}/month</p>
<p className="taxes">Taxes may apply based on location</p>
</div>
<div className="features">
<h3>Includes:</h3>
<ul>
<li>Ad-free experience</li>
<li>Unlimited cloud storage</li>
<li>Priority support</li>
</ul>
</div>
<div className="terms">
<p>
Subscription renews automatically unless cancelled at least
24 hours before the end of the current period.
</p>
<p>
Manage or cancel in Google Play Subscriptions.
</p>
</div>
<button onClick={handlePurchase}>
Start Subscription
</button>
</div>
);
}

3. 欺骗性订阅模式

订阅模式欺骗性模式

为什么会失败:

  • 预先选择高级选项
  • 隐藏更便宜的替代方案
  • 使取消订阅变得困难
  • 假的紧迫性(‘仅剩 3 个位置!’)

订阅说明最佳实践

营销指南

预防措施:

  • 显示所有订阅等级
  • 使取消订阅清晰和易于访问
  • 避免倒计时计时器或假的稀缺性
  • 不要使用暗模式来推广贵重的选项

4. 测试不完整

标题:4. 测试不完整

为什么会失败:

  • 应用程序在购买时会崩溃
  • 产品无法加载
  • 购买确认信息不显示
  • 购买后高级功能无法解锁
  • 测试仅在侧载构建上进行,而不是在Play安装的测试跟踪上

预防措施:

import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases';
// Comprehensive testing before submission
async function testPurchaseFlow() {
try {
// 1. Test product loading
const { products } = await NativePurchases.getProducts({
productIdentifiers: ['premium_monthly', 'premium_yearly'],
productType: PURCHASE_TYPE.SUBS,
});
console.log('✓ Products loaded:', products.length);
// 2. Test purchase flow
const transaction = await NativePurchases.purchaseProduct({
productIdentifier: 'premium_monthly',
planIdentifier: 'monthly-plan',
productType: PURCHASE_TYPE.SUBS,
});
console.log('✓ Purchase completed', transaction.transactionId);
// 3. Verify entitlements
const { purchases } = await NativePurchases.getPurchases({
productType: PURCHASE_TYPE.SUBS,
});
if (
purchases.some(
(purchase) =>
purchase.productIdentifier === 'premium_monthly' &&
['PURCHASED', '1'].includes(purchase.purchaseState ?? '') &&
purchase.isAcknowledged,
)
) {
console.log('✓ Premium features unlocked');
}
// 4. Test restore
await NativePurchases.restorePurchases();
console.log('✓ Restore works');
} catch (error) {
console.error('✗ Test failed:', error);
}
}

5. 隐私政策违反

第 5 条:隐私政策违反

为什么会失败:

  • 应用中没有隐私政策链接
  • 无法访问隐私政策
  • 未披露数据收集
  • 数据安全部分不准确

预防措施:

  • 在 Google Play 商店列表中添加隐私政策
  • 在应用设置中包含链接
  • 准确填写数据安全部分
  • 在添加新数据收集时更新政策

替代付款计划

替代付款计划

Google 的替代付款计划是地区特定的,并可能会更改。如果您想使用除标准 Google Play Billing 之外的任何付款方式,请在实施之前立即在 Play Console 中确认市场资格、所需 API 和披露语言。

订阅管理

替代付款计划

轻松查看当前订阅

  • __CAPGO_KEEP_0__
  • 取消后不联系支持
  • 了解取消生效时间

实现:

import { NativePurchases } from '@capgo/native-purchases';
function ManageSubscriptionButton() {
const openManagement = async () => {
try {
// Opens Google Play subscription management
await NativePurchases.manageSubscriptions();
} catch (error) {
// Fallback to direct URL
const playStoreUrl = 'https://play.google.com/store/account/subscriptions';
window.open(playStoreUrl, '_blank');
}
};
return (
<button onClick={openManagement}>
Manage Subscription in Google Play
</button>
);
}

取消期限

取消期限

必备披露:

  • 取消生效时间是何时?
  • 用户在期限结束前是否仍有访问权限?
  • 是否可获得部分退款?
function CancellationInfo() {
return (
<div className="cancellation-info">
<h3>Cancellation Policy</h3>
<ul>
<li>Cancel anytime in Google Play</li>
<li>Access continues until end of billing period</li>
<li>No refunds for partial periods</li>
<li>Resubscribe anytime to regain access</li>
</ul>
<button onClick={() => NativePurchases.manageSubscriptions()}>
Manage in Google Play
</button>
</div>
);
}

提交前检查清单

提交前检查清单

提交前检查清单

  1. 验证计费实施

    • 使用Google Play Billing(通过native-purchases)
    • 在Play Console中创建的所有订阅产品
    • 基础计划和优惠配置正确
    • 产品已激活并发布
    • 为所有目标国家设置了定价
  2. 测试购买流程

    • 创建许可测试账户
    • 从Play测试跟踪安装构建
    • 测试每个订阅级别
    • 正确加载产品
    • 测试购买完成
    • 确认 测试购买 广告牌出现
    • 验证高级功能解锁
    • 测试订阅恢复
    • 测试多台设备
  3. 查看所有复制

    • 价格在购买前清晰显示
    • 所有费用在订阅前公开
    • 订阅条款清晰
    • 取消流程说明
    • 不做误导性宣传
  4. 应用内容和隐私

    • 在Play Console中链接隐私政策
    • 在应用中可访问隐私政策
    • 广告声明已完成
    • 如果应用被锁定,添加应用访问说明
    • 数据安全部分准确完成
    • 权限合理化并且有文档
  5. 内容评级和受众

    • 完成内容评级问卷
    • 完成目标受众和内容部分
    • 确保评分与实际内容匹配
    • 在问卷中声明应用内购买
  6. 准备商店列表

    • 应用描述准确
    • 短描述在 80 个字符以内
    • 全描述在 4000 个字符以内
    • 至少上传 2 个手机截图
    • 上传 1024x500 的特性图标
    • 截图显示当前版本
    • 上传所有必需资产

[__CAPGO_KEEP_0__] [__CAPGO_KEEP_0__] [__CAPGO_KEEP_0__] [__CAPGO_KEEP_0__] [__CAPGO_KEEP_0__] [__CAPGO_KEEP_0__] [__CAPGO_KEEP_0__] [__CAPGO_KEEP_0__]

[__CAPGO_KEEP_0__]

[__CAPGO_KEEP_0__]

[__CAPGO_KEEP_0__]

[__CAPGO_KEEP_0__]

版权测试
  1. 添加测试账户:

    • 前往 Google Play 控制台
    • 设置 > 许可证测试
    • 添加 Gmail 账户进行测试
  2. 在沙盒中测试:

import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases';
// Test purchases with license test account
async function testInSandbox() {
const { isBillingSupported } = await NativePurchases.isBillingSupported();
if (!isBillingSupported) {
console.error('Billing not supported in this environment');
return;
}
// Fetch products (returns test pricing when using a license tester)
const { products } = await NativePurchases.getProducts({
productIdentifiers: ['premium_monthly'],
productType: PURCHASE_TYPE.SUBS,
});
console.log('Test products:', products);
// Make test purchase (no charge)
const transaction = await NativePurchases.purchaseProduct({
productIdentifier: 'premium_monthly',
planIdentifier: 'monthly-plan',
productType: PURCHASE_TYPE.SUBS,
});
console.log('Test purchase complete:', transaction.transactionId);
}
  1. 验证测试横幅:
    • 使用测试账户进行购买时
    • 应该看到“测试购买”通知
    • 不会发生实际费用

内部和关闭测试轨迹

内部和封闭测试轨道

生产发布之前:

  1. 创建一个 内部测试 轨道用于快速QA或 封闭测试 轨道用于更广泛的测试
  2. 上传一个签名 .aab 并发布测试版本
  3. 添加测试者邮箱地址并分享优惠链接
  4. 让测试者从Google Play安装构建
  5. 在Play安装的构建上验证购买流程从头到尾工作
  6. 如果您的个人开发者帐户在 2023 年 11 月 13 日之后创建,请在申请生产环境前至少 14 天内为您的应用程序保留至少 12 个测试者并将其加入到一个封闭测试中

sideloaded debug build 不是用来验证 Google Play Billing 的 Play 安装测试 build 的替代品

原生购买最佳实践

原生购买最佳实践

处理所有购买状态

处理所有购买状态
import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases';
async function handlePurchase(productId: string, planIdentifier?: string) {
try {
setLoading(true);
const transaction = await NativePurchases.purchaseProduct({
productIdentifier: productId,
planIdentifier,
productType: planIdentifier ? PURCHASE_TYPE.SUBS : PURCHASE_TYPE.INAPP,
});
console.log('Purchase token:', transaction.purchaseToken ?? transaction.receipt);
// Success - check entitlements from the store
const { purchases } = await NativePurchases.getPurchases({
productType: planIdentifier ? PURCHASE_TYPE.SUBS : PURCHASE_TYPE.INAPP,
});
const isOwned = purchases.some(
(purchase) =>
purchase.productIdentifier === productId &&
(purchase.purchaseState === 'PURCHASED' || purchase.purchaseState === '1') &&
purchase.isAcknowledged,
);
if (isOwned) {
unlockPremiumFeatures();
showSuccess('Premium activated!');
}
} catch (error: any) {
// Handle specific error cases
switch (error.code) {
case 'USER_CANCELLED':
// User backed out - no error needed
console.log('Purchase cancelled');
break;
case 'ITEM_ALREADY_OWNED':
// They already own it - restore instead
showInfo('You already own this! Restoring...');
await NativePurchases.restorePurchases();
break;
case 'ITEM_UNAVAILABLE':
showError('This subscription is currently unavailable. Please try again later.');
break;
case 'NETWORK_ERROR':
showError('Network error. Please check your connection and try again.');
break;
default:
showError('Purchase failed. Please try again.');
console.error('Purchase error:', error);
}
} finally {
setLoading(false);
}
}

实现恢复购买

恢复购买
import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases';
function RestorePurchasesButton() {
const [loading, setLoading] = useState(false);
const handleRestore = async () => {
setLoading(true);
try {
await NativePurchases.restorePurchases();
const { purchases } = await NativePurchases.getPurchases({
productType: PURCHASE_TYPE.SUBS,
});
const hasSubscription = purchases.some(
(purchase) => purchase.productType === 'subs' && purchase.isAcknowledged,
);
if (hasSubscription) {
unlockPremiumFeatures();
showSuccess('Subscriptions restored!');
return;
}
// Check one-time unlocks if needed
const { purchases: iaps } = await NativePurchases.getPurchases({
productType: PURCHASE_TYPE.INAPP,
});
const hasInApp = iaps.some((purchase) => purchase.productIdentifier === 'premium_unlock');
if (hasInApp) {
unlockPremiumFeatures();
showSuccess('Previous purchases restored!');
return;
}
showInfo('No previous purchases found.');
} catch (error) {
showError('Failed to restore purchases. Please try again.');
} finally {
setLoading(false);
}
};
return (
<button onClick={handleRestore} disabled={loading}>
{loading ? 'Restoring...' : 'Restore Purchases'}
</button>
);
}

检查订阅状态

恢复购买最佳实践
import { NativePurchases, PURCHASE_TYPE } from '@capgo/native-purchases';
async function checkSubscriptionStatus() {
try {
const { purchases } = await NativePurchases.getPurchases({
productType: PURCHASE_TYPE.SUBS,
});
const subscription = purchases.find(
(purchase) =>
purchase.productIdentifier === 'premium_monthly' &&
(purchase.purchaseState === 'PURCHASED' || purchase.purchaseState === '1') &&
purchase.isAcknowledged,
);
if (!subscription) {
showPaywall();
return;
}
console.log('Subscription active:', {
productId: subscription.productIdentifier,
expiresAt: subscription.expirationDate,
willRenew: subscription.willCancel === false,
purchaseToken: subscription.purchaseToken,
});
unlockPremiumFeatures();
} catch (error) {
console.error('Failed to check subscription:', error);
}
}

如果您的应用被拒绝

标题:如果您的应用被拒绝

常见政策违规

标题:常见政策违规

支付政策:

  • 未使用Google Play Billing
  • 误导性订阅条款
  • 隐藏费用

用户数据政策:

  • 缺少隐私政策
  • 不准确的数据安全声明
  • 过度权限
  1. 查看违反通知

    • 阅读他们所引用具体的政策
    • 了解Google标记的内容
    • 检查他们提供的示例
  2. 修复问题

    • 解决根本原因,而不是仅仅解决症状
    • 修复后进行彻底测试
    • 记录所有所做的更改
  3. 提交申诉(如果适用)

    澄清和申诉流程

    Subject: Policy Violation Appeal - [App Name]
    Dear Google Play Review Team,
    I have received notification that my app violates [Policy X.Y].
    I have made the following changes to comply:
    1. [Specific change made]
    2. [Specific change made]
    3. [Specific change made]
    The updated version [version number] addresses all concerns raised.
    Test account for verification:
    Email: test@example.com
    Password: TestPass123
    Thank you for your consideration.

    请求文档示例

  4. 重新提交或更新

    • 上传修复版本
    • 重新提交审查
    • 在Play控制台中监控状态

导航Play Store审查可能很复杂,尤其是当您需要结合账单合规性、应用内容声明和测试跟踪设置。如果您需要个人化帮助:

与我们的团队预约电话会议 帮助:

  • 完成Play Store审查准备
  • 测试跟踪设置和测试者招募
  • IAP 实现审查
  • 数据安全性和隐私合规性
  • [__CAPGO_KEEP_0__]排除和申诉
  • [__CAPGO_KEEP_0__]应用提交流程

我们的专家已经帮助数百个应用成功通过Play商店的提交,并且可以帮助您了解当前的要求。

需要帮助实现?

继续从Android Play Store Review Guidelines for IAP

标题:继续从Android Play Store Review Guidelines for IAP

如果您正在使用 Android Play Store Review Guidelines for IAP 来规划安全性和合规性,连接它到 使用@capgo/native-purchases for the native capability in Using @capgo/native-purchases, 加密 合规 合规 __CAPGO_KEEP_0__ 安全扫描器 Capgo 安全扫描器 为产品工作流程在Capgo安全扫描器中 Capgo安全 为产品工作流程在Capgo安全