我在我的应用程序中实现了应用内计费,现在正在测试其退款处理。
我使用测试帐户购买了应用程序的托管应用内结算项目并退款。我的应用程序按预期收到了退款广播,并且在恢复交易时看到该商品已退款,因此到目前为止一切都很好。
我的问题是我无法重新购买该物品来测试其他场景。 当我尝试购买该商品时,Google Play 界面出现并显示一条错误消息“您已经拥有该商品”。有 2 个按钮“确定”和“详细信息”。 如果我按详细信息,Google Play 就会崩溃,然后我会返回到我的应用程序。
有人有类似经历吗? 如果用户之前退款过,是否会禁止他们购买应用内商品?
我也看到了同样的问题。 GP 崩溃等等。
除了等待几个小时之外,您可能还需要打开“Google Play”应用程序信息并清除缓存和清除数据。这为我解决了这个问题。 GP 似乎会在设备上缓存购买信息,并且很少(如果有的话)只检查 Google 的服务器以获取退款信息。
更新: 您可能还想终止 Google Play 进程,因为它似乎也将购买信息保留在内存中。
我向 Google 询问了这个问题,他们告诉我,如果之前已退款,则无法在 Google Play 上重新购买应用内结算项目。 但是大约24小时后我再次尝试购买时,购买失败了......
所以看起来可以重新购买,但只能在延迟一段时间后。
我知道这是一个老问题,但我一直在寻找同一问题的答案,并最终得出了自己的结论。谷歌没有详细说明,但我相信他们希望您根据自己的逻辑决定如何处理取消和退款的购买。需要记住的另一点是,消耗性和非消耗性托管产品之间本质上没有区别。所有托管产品都是消耗品。
对我来说,当用户取消购买,或者我决定给用户退款时,我希望发生的是 1) 用户收到退款,2) 用户无法使用付费功能,3) )如果用户选择,他们可以选择再次购买该功能。
我所做的是使用应用内计费 API 在后端服务器上检查购买的购买状态。如果返回的purchaseState是1(取消)或2(退款),我会在我的应用程序中消费该购买。 Google 处理第 1 项,将钱退还给用户。我的应用程序中的逻辑处理 2,锁定对付费功能的访问。使用购买手柄 3,让用户可以选择再次购买该功能。
其基本要点是,当购买被发送到我的后端服务器进行验证时,我检查购买状态。如果购买状态是 1 或 2,我会向我的应用程序返回适当的代码。当我的应用收到指示购买已取消或退款的代码时,我的应用将消耗该购买。
我使用PHP版本的API,所以我获取购买状态的简化代码是:
$purchases = $service->purchases_products->get($packageName, $productId, $purchaseToken);
$purchaseState = $purchases->getPurchaseState();
if($purchaseState === 1){
$serverResponseCode = 3;
}
if($purchaseState === 2){
$serverResponseCode = 4;
}
...然后在我的应用程序中,我检查服务器响应代码。
if(serverResponseCode == 3 || serverResponseCode ==4 ){
lockFeatures();
ConsumeParams params = ConsumeParams.newBuilder().setPurchaseToken(purchase.getPurchaseToken()).build();
billingClient.consumeAsync(params, listener);
}
我希望这可以帮助其他人寻找这个问题的答案。
万一有人需要 android 而不是 kotlin 代码。 smitty 写的所有解释:
启动应用程序时,您必须检查 queryPurchases 并查找已退款的商品。 像这样:
if (purchase.getPurchaseState() != Purchase.PurchaseState.UNSPECIFIED_STATE)
{
handleConsumablePurchasesAsync(purchasesList);
return false;
}
比你消耗这个项目。 smitty1 是个天才
private void handleConsumablePurchasesAsync(List<Purchase> consumables) {
Log.d(TAG, "handleConsumablePurchasesAsync");
for (Purchase purchase : consumables) {
ConsumeParams params = ConsumeParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build();
billingClient.consumeAsync(params, (billingResult, purchaseToken) -> {
if (billingResult.getResponseCode() == OK) {
Log.d(TAG, "Consumed the old purchase that hasn't already been acknowledged");
} else {
Log.d(TAG, "Error consume the old purchase that hasn't already been acknowledged -> %s" + String.valueOf(billingResult.getResponseCode()));
}
});
}
}