Google Play Billing Library 5 一次性购买如何传递 token?
结论
一次性购买(ProductType.INAPP)不需要 offerToken。构造 BillingFlowParams.ProductDetailsParams 时,只需设置 ProductDetails,不要调用 setOfferToken(),也不用传入 null 或空字符串。
BillingFlowParams.ProductDetailsParams productDetailsParams =
BillingFlowParams.ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.build();
offerToken 用于指定订阅商品的基础方案或优惠,不适用于 Google Play Billing Library 5 中的一次性商品。
启动一次性购买流程
查询商品时使用 ProductType.INAPP。取得对应的 ProductDetails 后,可以直接启动购买流程:
ImmutableList<BillingFlowParams.ProductDetailsParams> productDetailsParamsList =
ImmutableList.of(
BillingFlowParams.ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.build()
);
BillingFlowParams billingFlowParams =
BillingFlowParams.newBuilder()
.setProductDetailsParamsList(productDetailsParamsList)
.build();
BillingResult billingResult =
billingClient.launchBillingFlow(activity, billingFlowParams);
同时检查同步返回的 BillingResult:
if (billingResult.getResponseCode() != BillingClient.BillingResponseCode.OK) {
Log.e(
"Billing",
"Unable to launch billing flow: "
+ billingResult.getDebugMessage()
);
}
不要为了照搬示例代码而创建 selectedOfferToken。文档中的 setOfferToken(selectedOfferToken) 是订阅购买的示例逻辑,并非所有商品类型都需要执行。
offerToken 和 purchaseToken 不是同一个值
这两种 token 容易混淆:
offerToken:发起订阅购买前,通过ProductDetails.SubscriptionOfferDetails#getOfferToken()获取,用来指定订阅基础方案或优惠。purchaseToken:购买成功后由 Google Play 返回,用于确认购买、消耗商品和服务端校验。
一次性购买不需要提前传入 offerToken,但购买成功后仍会产生 purchaseToken。可以从 Purchase 对象中获取:
PurchasesUpdatedListener purchasesUpdatedListener =
(billingResult, purchases) -> {
if (billingResult.getResponseCode()
== BillingClient.BillingResponseCode.OK
&& purchases != null) {
for (Purchase purchase : purchases) {
String purchaseToken = purchase.getPurchaseToken();
handlePurchase(purchase, purchaseToken);
}
}
};
Billing Library 使用 Purchase 表示购买结果,使用 ProductDetails 表示待售商品信息。如果 “PurchaseDetails token” 指购买成功后的凭证,实际应调用:
purchase.getPurchaseToken()
不要从 ProductDetails 中查找。
购买成功后的处理
非消耗型一次性商品应在验证购买状态后确认购买:
private void handlePurchase(Purchase purchase, String purchaseToken) {
if (purchase.getPurchaseState() != Purchase.PurchaseState.PURCHASED) {
return;
}
if (!purchase.isAcknowledged()) {
AcknowledgePurchaseParams acknowledgeParams =
AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchaseToken)
.build();
billingClient.acknowledgePurchase(
acknowledgeParams,
billingResult -> {
if (billingResult.getResponseCode()
!= BillingClient.BillingResponseCode.OK) {
Log.e(
"Billing",
"Acknowledge failed: "
+ billingResult.getDebugMessage()
);
}
}
);
}
}
如果商品是可重复购买的消耗品,应使用 consumeAsync() 消耗该购买,不能只执行确认:
ConsumeParams consumeParams =
ConsumeParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build();
billingClient.consumeAsync(
consumeParams,
(billingResult, consumedPurchaseToken) -> {
if (billingResult.getResponseCode()
!= BillingClient.BillingResponseCode.OK) {
Log.e(
"Billing",
"Consume failed: "
+ billingResult.getDebugMessage()
);
}
}
);
注意事项
不要混淆下面几种值:
ProductDetails#getProductId()是商品 ID。SubscriptionOfferDetails#getOfferToken()是订阅优惠 token。Purchase#getPurchaseToken()是购买完成后生成的购买凭证。
一次性购买的流程是:查询 INAPP 类型的 ProductDetails,构造购买参数时省略 setOfferToken(),购买成功后再从 Purchase 获取 purchaseToken。生产环境中,应先验证购买真实性,再发放商品并确认或消耗该购买。
备注:内容仅供参考。
