EN

Google Play 支付配置

本指南介绍如何为 Android 应用配置 Google Play 应用内购买和订阅。

前置条件

  • Google Play 开发者账号(一次性费用 $25)
  • 已在 Google Play Console 中发布或保存草稿的应用
  • 可访问 Google Play Console
  • 用于 API 访问的 Google Cloud 项目

步骤一:设置 Google Play Console

  1. 前往 Google Play Console
  2. 选择您的应用或创建新应用
  3. 完成应用列表和内容分级
  4. 至少上传一个内部测试 APK

步骤二:创建应用内商品

一次性商品(托管商品)

  1. 前往 变现 > 商品 > 应用内商品
  2. 点击 创建商品
  3. 填写商品详情:
字段 说明 示例
商品 ID 唯一标识符 premium_upgrade
名称 显示名称 高级升级
描述 商品描述 解锁所有功能
默认价格 基础价格 $9.99
  1. 点击 保存 然后 激活

订阅

  1. 前往 变现 > 商品 > 订阅
  2. 点击 创建订阅
  3. 填写订阅详情:
字段 说明 示例
商品 ID 唯一标识符 pro_monthly
名称 订阅名称 Pro 月度版
描述 包含内容 每月 Pro 访问权限
  1. 添加基础方案:
  • 方案 ID:monthly-plan
  • 计费周期:每月
  • 价格:$9.99/月
  • 免费试用:可选
  • 宽限期:建议 3 天
  1. 点击 保存 然后 激活

定价模板

设置跨区域的统一定价:

  1. 前往 变现 > 定价模板
  2. 为您的定价策略创建模板
  3. 应用于商品以实现自动货币转换

步骤三:设置实时开发者通知(RTDN)

RTDN 将购买更新发送到您的服务器。

  1. 前往 变现 > 变现设置
  2. 找到 实时开发者通知
  3. 输入您的 Cloud Pub/Sub 主题:
projects/your-project/topics/play-billing-notifications

创建 Pub/Sub 主题

  1. 前往 Google Cloud 控制台
  2. 导航到 Pub/Sub > 主题
  3. 点击 创建主题
  4. 主题名称:play-billing-notifications
  5. 为您的 Webhook 端点添加订阅

步骤四:配置服务账号

用于服务器端验证:

  1. 前往 Google Cloud 控制台
  2. 导航到 IAM 和管理 > 服务账号
  3. 点击 创建服务账号
  4. 名称:play-billing-verifier
  5. 点击 创建并继续

授予权限

在 Google Play Console 中:

  1. 前往 用户和权限 > 邀请新用户
  2. 添加您的服务账号邮箱
  3. 授予权限:
  • 财务数据、订单和取消调查回复(查看)
  • 管理订单和订阅

下载密钥文件

  1. 在 Google Cloud 控制台中,前往您的服务账号
  2. 点击 密钥 > 添加密钥 > 创建新密钥
  3. 选择 JSON 格式
  4. 下载并妥善保管密钥文件

步骤五:在 OpenDev 中配置

  1. 登录 OpenDev 平台
  2. 前往应用的 支付配置
  3. 添加 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:

  1. 前往 OpenDev 中的 商品档位
  2. 为每个档位添加 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;
}

步骤九:测试集成

许可证测试

  1. 前往 设置 > 许可证测试
  2. 添加测试账号邮箱
  3. 测试账号在沙盒中可免费购买

测试流程

  1. 从内部测试轨道安装应用
  2. 使用许可证测试账号登录
  3. 完成购买(沙盒模式)
  4. 验证 Webhook 收到通知
  5. 在 Play Console 中检查购买记录

测试场景

场景 测试方法
购买成功 完成正常流程
订阅续费 等待或使用测试时间控制
取消订阅 从 Play 商店取消
付款失败 使用拒绝的测试卡

故障排查

错误:商品不可用

解决方案:

  • 商品必须在 Play Console 中激活
  • 应用必须至少发布到内部测试
  • 用户必须使用 Google 账号登录

错误:服务不可用

解决方案:

  • 检查计费客户端是否已连接
  • 使用指数退避重试
  • 验证 Google Play 服务是否为最新版本

购买记录未在服务器显示

解决方案:

  • 验证 Pub/Sub 订阅是否处于活动状态
  • 检查服务账号权限
  • 验证 Webhook 端点是否可访问

安全最佳实践

  1. 始终在服务器端验证 — 不要信任客户端验证
  2. 及时确认购买 — 未确认的购买会自动退款
  3. 处理待处理购买 — 支持延迟付款方式
  4. 保护服务账号密钥 — 切勿在应用代码中暴露
  5. 实现重试逻辑 — 网络问题很常见

相关文档