跳过内容

Android Play Store Review Guidelines for IAP

GitHub

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

  1. 构建一个已签名的 Android 应用程序包

    新应用程序应以 Android 应用程序包 (.aab) 的形式上传,而不是使用调试 APK 进行侧载。

    保持您的 versionCode 每次上传都会增加,并且如果您使用 Play App Signing,请安全地存储您的上传密钥。

    Android 应用程序包流程

  2. 在 Play Console 中创建应用程序记录

    If you do not have a developer account yet, start with Play Console signup. Then, in Home > Create app, choose the language, app/game type, free/paid status, support email, and accept the required declarations.

    Choose the free/paid setting carefully. Google lets you change a paid app to free later, but once an app has been offered for free, it cannot be switched to paid.

    Create app in Play Console

  3. Complete App Content and Store Listing

    Before production review, finish the required Play Console declarations:

    • Privacy policy
    • Ads
    • App access
    • 目标受众和内容
    • 内容评级
    • 数据安全
    • 如果适用,敏感权限申明
  4. 在Play-安装测试跟踪中运行

    开始 内部测试 用于快速QA。 如果您的开发者帐户是创建于2023年11月13日之后的个人帐户,则您还必须完成一个 封闭测试 至少有12名已同意的测试者参与14个连续的日子

    内部测试在Play控制台

  5. 验证结算端到端

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

    • 产品从Play正确加载
    • 购买单据显示一个 测试购买 许可测试者的广告牌
    • 购买后激活
    • 恢复和订阅管理流程正常

Google Play Billing Requirements

标题:Google Play Billing Requirements

强制性付款系统

标题:强制性付款系统

对于数字商品和服务,您 必须 必须使用Google Play的付款系统:

数字商品(必须使用Play Billing):

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

实物商品(不能使用Play Billing):

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

:::note 订阅设置 在 Play Console 中,使用当前的 订阅 -> 基础计划 -> 优惠 模型。在 native-purchases, 将 Base Plan 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商店列表中添加链接

    • 在Play Console中添加隐私政策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(用于欺诈防御)
  • 处理付款信息
  • 分析数据收集

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

应用内容声明

App 内容申报

Google Play 的评论不仅仅是关于二进制文件。 在发布生产版本之前,完成以下申报: 政策和计划 > App 内容.

需要仔细检查的最小设置:

  • 隐私政策: 在 Google Play 控制台中提供公共 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. 价格不明确或隐藏费用

为什么会失败:

价格只有在点击购买后才显示

  • 额外费用没有在事前透露
  • Section titled “2. Unclear Pricing or Hidden Costs”
  • 模糊的订阅条款

预防措施:

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. 欺骗性订阅模式

为什么会失败:

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

订阅描述最佳实践

营销指南

防止措施:

  • 显示所有订阅等级
  • 使取消订阅清晰易于访问
  • 避免使用倒计时器或假的稀缺性
  • 不要使用黑客手段推广贵的选项

4. 测试不完整

标题:4. 测试不完整

为什么会失败:

  • 应用程序在购买时会崩溃
  • 产品无法加载
  • 购买确认信息不显示
  • 购买后premium功能无法解锁
  • 测试仅在侧载构建上进行,而不是在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.隐私政策违规

为什么会失败:

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

预防措施:

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

替代付款计划

标题:替代付款计划

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

用户必须能够:

  • 轻松查看当前订阅
  • 无需联系支持即可取消
  • 了解取消生效的时间

实现:

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. Copy to clipboard

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

    • 在购买前显示明确的价格
    • 所有费用在购买前都已披露
    • 订阅条款清晰
    • 取消订阅的流程已解释
    • 不做任何误导性宣传
  4. 应用内容和隐私

    • 在Play Console中链接了隐私政策
    • 在应用中可以访问隐私政策
    • 已完成广告声明
    • 如果应用被限制访问,则已添加应用访问说明
    • 已准确完成数据安全部分
    • 已对权限进行了说明和文档
  5. 内容评级和受众

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

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

新个人帐户的生产访问: 通常在申请后7天或更短时间内 首次生产审查: 上下文:Capgo Builder / 原生云构建产品页面。角色:短的UI标签或导航项。消息键`native_build_builder_credit_first` (原生构建构建者信用第一) 通常几天,偶尔更长,如果涉及账单或政策问题 更新: 通常比首次发布快,但仍需要审查 申诉:

计划几天并提供准确的修复和审查员指示

测试前提交

测试前提交

许可测试

许可测试
  1. 添加测试账户:

    • 前往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名测试者保留在关闭测试中

使用Google Play Billing进行验证时,侧载调试构建不是Play安装的测试构建的替代品

原生购买最佳实践

原生购买最佳实践

处理所有购买状态

处理所有购买状态
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 Console中监控状态

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

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

  • 完成Play Store审核准备
  • 测试跟踪设置和测试者招募
  • 内购实现审查
  • 数据安全和隐私合规
  • 拒绝处理和申诉
  • 完成应用提交流程

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

支持

继续从Android Play Store Review指南中进行IAP

标题:继续从Android Play Store Review指南中进行IAP

如果您正在使用 Android Play Store Review指南中的IAP 来规划安全性和合规性,连接它与 使用@capgo/native-purchases 为native能力在使用@capgo/native-purchases中 加密 加密实现细节 合规性 对于合规性中的实现细节 Capgo 安全扫描器 对于Capgo 安全扫描器中的产品工作流程,并 Capgo 安全 对于Capgo 安全中的产品工作流程。