Google Play 应用内购最佳实践
Google Play 应用内购最佳实践
在出海应用开发过程中,通常会接入 Google Play支付,而常见的三个覆盖场景:即新购、恢复和异常处理,是构建一个稳健支付系统所必须的。下面我将基于Google Play Billing Library,对这三个场景的实现细节、关键API和最佳实践进行详细拆解。
场景一:用户新购买流程 (New Purchase Flow)
这是最基础的“快乐路径”,流程的每一步都至关重要。
详细步骤:
初始化BillingClient
- 在onCreate中创建并连接BillingClient。这是所有操作的起点。
查询商品信息 (ProductDetails)
- 在展示购买按钮前,使用 billingClient.queryProductDetailsAsync() 从Google Play获取商品信息(价格、标题、描述等)。不要在客户端硬编码价格。
发起购买 (Launch Billing Flow)
- 用户点击购买按钮后,构建BillingFlowParams,并调用 billingClient.launchBillingFlow()。
- 最佳实践:在BillingFlowParams中,使用 setObfuscatedAccountId() 传递你的用户系统中的唯一ID。这有助于Google检测欺诈行为,并将购买与你的用户关联起来。
处理购买结果 (onPurchasesUpdated)
- 这是PurchasesUpdatedListener中的核心回调方法。
- 当responseCode == BillingResponseCode.OK 且 purchases 列表不为空时,表示用户已成功支付(或进入PENDING状态)。
- 关键操作:从Purchase对象中获取purchaseToken(originalJson和signature等信息)。立即将此其发送到你的服务端进行验证。
- 注意:此时不要在客户端直接发放权益,因为客户端可能被篡改。
服务端验单入账 (Server-Side Verification)
- 你的服务端收到purchaseToken后,必须使用 Google Play Developer API 进行验证。
- 对于订阅,调用 purchases.subscriptions.get。
- 对于一次性商品,调用 purchases.products.get。
- 验证关键字段:
- purchaseState: 必须为 1 (Purchased)。如果是 2 (Pending),则不应发货,等待后续状态更新。
- acknowledgementState: 确认交易是否已被确认。
- 入账逻辑:
- 验证通过后,将订单信息(orderId, purchaseToken, 用户ID等)存入你的数据库。
- 必须做好幂等性处理:使用orderId或purchaseToken作为唯一键,防止同一笔交易被重复入账。
- 在你的系统中为用户发放相应的权益(如VIP、金币等)。
- 向客户端返回一个成功或失败的响应。
完成交易 (Acknowledge/Consume)
- 客户端在收到你的服务端的成功响应后,必须完成Google Play的交易。
- 对于订阅或非消耗型商品(如去广告),调用 billingClient.acknowledgePurchase()。
- 对于消耗型商品(如金币、宝石),调用 billingClient.consumeAsync()。
- 为什么必须做? 如果一个PURCHASED状态的交易在3天内没有被acknowledge或consume,Google Play会自动退款,并可能认为你的应用存在问题。
场景二:恢复购买 (Restore Purchases)
这个场景主要针对已订阅用户,确保他们在更换设备或重装应用后,权益能自动恢复。
详细步骤:
触发时机
- 自动恢复:在应用启动时(如Activity的onResume)调用。这是最佳实践,用户无需任何操作。
- 手动恢复:提供一个“恢复购买”按钮,用户点击时调用。
查询历史交易 (Query Purchases)
- 调用 billingClient.queryPurchasesAsync()。这个API会返回当前Google账户在该应用下所有有效的购买记录(即,有效的订阅和未消耗的一次性商品)。
- 注意:它不会返回已过期、已取消或已消耗的交易。
处理查询结果
- 遍历返回的Purchase列表。
- 对于列表中的每一个Purchase对象:
- 执行与“新购”类似的服务器验证流程:将purchaseToken发送到你的服务器。
- 服务器逻辑:服务器查询数据库。 如果这笔交易已经存在于你的数据库中,说明是老用户,直接告诉客户端“验证成功”。 如果这笔交易不存在(可能是掉单或新设备首次同步),则执行完整的验单入账流程。
- 客户端逻辑:根据服务器的响应,在UI上为用户解锁相应权益。
- 补确认:在遍历时,检查 purchase.isAcknowledged()。如果返回false,说明上次购买流程中客户端确认步骤失败了。在服务器验证成功后,客户端应立即调用 acknowledgePurchase() 进行“补确认”,防止该笔交易被退款。
场景三:处理未完成的交易 (Handling Pending/Unfinished Transactions)
这是保证系统稳健性的关键,国内称之为“补单”逻辑。它处理两种情况:1. 支付后应用崩溃导致未上报;2. 用户使用了需要延迟确认的支付方式(如便利店现金支付)。
详细步骤
在应用启动时处理
- 这个逻辑和“恢复购买”逻辑完全重合,都依赖于在onResume中调用 queryPurchasesAsync()。
- 当你从 queryPurchasesAsync() 的结果中找到一个purchaseState为 PURCHASED 但 isAcknowledged() 为 false 的交易时,就意味着这是一笔“未完成”的交易。
- 处理流程:严格按照 场景二(恢复购买) 的第3步进行处理:发到服务端验证 -> 服务端入账 -> 客户端确认(Acknowledge)。
处理待处理交易 (Pending Purchases)
- 当用户选择某些支付方式时,onPurchasesUpdated回调会返回一个purchaseState为 PENDING 的Purchase对象。
- 客户端操作:
- 不要发货!不要授予用户任何权益。
- 可以向用户显示一个提示,例如:“您的订单正在处理中,支付成功后将自动到账。”
- 必须确认这笔“待处理”交易:对于PENDING状态的交易,同样需要调用 acknowledgePurchase()。Google官方文档指出,这也需要确认,否则可能被取消。
- 后续状态变化:
- 当用户完成支付后,onPurchasesUpdated会再次被调用,此时同一个purchaseToken对应的Purchase对象,其purchaseState会变为 PURCHASED。
- 这时,你就按照场景一(新购)的流程处理这笔交易:发到服务端验单 -> 入账 -> 发放权益。
- 服务端最佳实践:使用 Real-Time Developer Notifications (RTDN)。当一笔交易从PENDING变为PURCHASED时,Google会主动向你的服务器发送一个通知。这比依赖客户端上报更及时、更可靠。
本文由作者按照 CC BY 4.0 进行授权