Google Play 支付配置
本指南介绍如何为 Android 应用配置 Google Play 应用内购买和订阅。
前置条件
- Google Play 开发者账号(一次性费用 $25)
- 已在 Google Play Console 中发布或保存草稿的应用
- 可访问 Google Play Console
- 用于 API 访问的 Google Cloud 项目
步骤一:设置 Google Play Console
- 前往 Google Play Console
- 选择您的应用或创建新应用
- 完成应用列表和内容分级
- 至少上传一个内部测试 APK
步骤二:创建应用内商品
一次性商品(托管商品)
- 前往 变现 > 商品 > 应用内商品
- 点击 创建商品
- 填写商品详情:
| 字段 | 说明 | 示例 |
|---|---|---|
| 商品 ID | 唯一标识符 | premium_upgrade |
| 名称 | 显示名称 | 高级升级 |
| 描述 | 商品描述 | 解锁所有功能 |
| 默认价格 | 基础价格 | $9.99 |
- 点击 保存 然后 激活
订阅
- 前往 变现 > 商品 > 订阅
- 点击 创建订阅
- 填写订阅详情:
| 字段 | 说明 | 示例 |
|---|---|---|
| 商品 ID | 唯一标识符 | pro_monthly |
| 名称 | 订阅名称 | Pro 月度版 |
| 描述 | 包含内容 | 每月 Pro 访问权限 |
- 添加基础方案:
- 方案 ID:
monthly-plan - 计费周期:每月
- 价格:$9.99/月
- 免费试用:可选
- 宽限期:建议 3 天
- 点击 保存 然后 激活
定价模板
设置跨区域的统一定价:
- 前往 变现 > 定价模板
- 为您的定价策略创建模板
- 应用于商品以实现自动货币转换
步骤三:设置实时开发者通知(RTDN)
RTDN 将购买更新发送到您的服务器。
- 前往 变现 > 变现设置
- 找到 实时开发者通知
- 输入您的 Cloud Pub/Sub 主题:
projects/your-project/topics/play-billing-notifications
创建 Pub/Sub 主题
- 前往 Google Cloud 控制台
- 导航到 Pub/Sub > 主题
- 点击 创建主题
- 主题名称:
play-billing-notifications - 为您的 Webhook 端点添加订阅
步骤四:配置服务账号
用于服务器端验证:
- 前往 Google Cloud 控制台
- 导航到 IAM 和管理 > 服务账号
- 点击 创建服务账号
- 名称:
play-billing-verifier - 点击 创建并继续
授予权限
在 Google Play Console 中:
- 前往 用户和权限 > 邀请新用户
- 添加您的服务账号邮箱
- 授予权限:
- 财务数据、订单和取消调查回复(查看)
- 管理订单和订阅
下载密钥文件
- 在 Google Cloud 控制台中,前往您的服务账号
- 点击 密钥 > 添加密钥 > 创建新密钥
- 选择 JSON 格式
- 下载并妥善保管密钥文件
步骤五:在 OpenDev 中配置
- 登录 OpenDev 平台
- 前往应用的 支付配置
- 添加 Google Play 配置:
{
"platform": "google_play",
"enabled": true,
"config": {
"packageName": "com.yourcompany.myapp",
"serviceAccountKey": {
"type": "service_account",
"project_id": "your-project",
"private_key_id": "xxx",
"private_key": "-----BEGIN PRIVATE KEY-----\n...",
"client_email": "xxx@xxx.iam.gserviceaccount.com"
},
"pubsubTopic": "projects/your-project/topics/play-billing-notifications"
}
}
配置字段
| 字段 | 必填 | 说明 |
|---|---|---|
| 包名 | 是 | 您应用的包名 |
| 服务账号密钥 | 是 | JSON 密钥内容 |
| Pub/Sub 主题 | 是 | RTDN 通知主题 |
步骤六:配置商品档位
关联 Google Play 商品 ID:
- 前往 OpenDev 中的 商品档位
- 为每个档位添加 Google Play 商品 ID:
{
"productId": "pro_monthly",
"name": "Pro Monthly",
"platformProductIds": {
"google_play": "pro_monthly_subscription"
}
}
步骤七:在 Android 中实现计费
添加计费库
dependencies {
implementation 'com.android.billingclient:billing:6.0.1'
}
初始化计费客户端
class BillingManager(private val context: Context) {
private lateinit var billingClient: BillingClient
fun initialize() {
billingClient = BillingClient.newBuilder(context)
.setListener(purchasesUpdatedListener)
.enablePendingPurchases()
.build()
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(result: BillingResult) {
if (result.responseCode == BillingClient.BillingResponseCode.OK) {
// 准备就绪,可查询购买
}
}
override fun onBillingServiceDisconnected() {
// 重新连接
}
})
}
}
查询商品
suspend fun queryProducts() {
val productList = listOf(
QueryProductDetailsParams.Product.newBuilder()
.setProductId("pro_monthly")
.setProductType(BillingClient.ProductType.SUBS)
.build()
)
val params = QueryProductDetailsParams.newBuilder()
.setProductList(productList)
.build()
val result = billingClient.queryProductDetails(params)
// 处理商品详情
}
发起购买流程
fun launchPurchase(productDetails: ProductDetails) {
val offerToken = productDetails.subscriptionOfferDetails?.get(0)?.offerToken
val productDetailsParams = BillingFlowParams.ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.setOfferToken(offerToken!!)
.build()
val flowParams = BillingFlowParams.newBuilder()
.setProductDetailsParamsList(listOf(productDetailsParams))
.build()
billingClient.launchBillingFlow(activity, flowParams)
}
处理购买更新
private val purchasesUpdatedListener = PurchasesUpdatedListener { result, purchases ->
if (result.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
for (purchase in purchases) {
handlePurchase(purchase)
}
}
}
private fun handlePurchase(purchase: Purchase) {
if (purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
// 发送到服务器验证
verifyPurchaseOnServer(purchase.purchaseToken)
// 确认购买
if (!purchase.isAcknowledged) {
val params = AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchase.purchaseToken)
.build()
billingClient.acknowledgePurchase(params) { }
}
}
}
步骤八:服务器端验证
// 后端验证
const { google } = require('googleapis');
async function verifyPurchase(packageName, productId, purchaseToken) {
const auth = new google.auth.GoogleAuth({
keyFile: 'service-account-key.json',
scopes: ['https://www.googleapis.com/auth/androidpublisher'],
});
const androidpublisher = google.androidpublisher({ version: 'v3', auth });
// 订阅验证
const result = await androidpublisher.purchases.subscriptions.get({
packageName,
subscriptionId: productId,
token: purchaseToken,
});
return result.data;
}
步骤九:测试集成
许可证测试
- 前往 设置 > 许可证测试
- 添加测试账号邮箱
- 测试账号在沙盒中可免费购买
测试流程
- 从内部测试轨道安装应用
- 使用许可证测试账号登录
- 完成购买(沙盒模式)
- 验证 Webhook 收到通知
- 在 Play Console 中检查购买记录
测试场景
| 场景 | 测试方法 |
|---|---|
| 购买成功 | 完成正常流程 |
| 订阅续费 | 等待或使用测试时间控制 |
| 取消订阅 | 从 Play 商店取消 |
| 付款失败 | 使用拒绝的测试卡 |
故障排查
错误:商品不可用
解决方案:
- 商品必须在 Play Console 中激活
- 应用必须至少发布到内部测试
- 用户必须使用 Google 账号登录
错误:服务不可用
解决方案:
- 检查计费客户端是否已连接
- 使用指数退避重试
- 验证 Google Play 服务是否为最新版本
购买记录未在服务器显示
解决方案:
- 验证 Pub/Sub 订阅是否处于活动状态
- 检查服务账号权限
- 验证 Webhook 端点是否可访问
安全最佳实践
- 始终在服务器端验证 — 不要信任客户端验证
- 及时确认购买 — 未确认的购买会自动退款
- 处理待处理购买 — 支持延迟付款方式
- 保护服务账号密钥 — 切勿在应用代码中暴露
- 实现重试逻辑 — 网络问题很常见