如何取消android上的应用内测试购买?

如何取消android上的应用内测试购买?,android,billing,in-app,Android,Billing,In App,直到2016年6月20日,我才能够取消在我的应用程序中完成的测试购买。 从同一个测试帐户进行多个应用程序内购买(非消耗性购买)可以轻松地开发和测试代码,而不会有太多的混淆 2016年6月20日之后,我的商户账户和 我无法从我的测试帐户进行1次以上的购买。我得到的只是“你已经拥有这件物品”的信息 我向谷歌开发者支持小组记录了一个请求,答案是: 从2016年6月20日开始,我们将测试购买更改为一次性应用内购买(IAP)。 以前,测试一次性IAPs生成的订单ID的购买。从2016年6月20日开始,一次

直到2016年6月20日,我才能够取消在我的应用程序中完成的测试购买。 从同一个测试帐户进行多个应用程序内购买(非消耗性购买)可以轻松地开发和测试代码,而不会有太多的混淆

2016年6月20日之后,我的商户账户和 我无法从我的测试帐户进行1次以上的购买。我得到的只是“你已经拥有这件物品”的信息

我向谷歌开发者支持小组记录了一个请求,答案是:

从2016年6月20日开始,我们将测试购买更改为一次性应用内购买(IAP)。 以前,测试一次性IAPs生成的订单ID的购买。从2016年6月20日开始,一次性IAP不会生成正式订单ID(如果有),也不会出现在商户中心。此行为已应用于订阅IAP。 您可以在Android开发者帮助中心了解更多关于测试应用内计费的信息:

好吧。。所以我转到上面提到的链接,这里有一个部分: 取消已完成的测试购买 其中指出:

Google Play为每个用户累计完成的测试购买,但不将其传递给财务处理。 在某些情况下,您可能希望手动取消测试购买以继续测试。为此,请在Play Store中打开应用程序页面。如果要取消的测试购买是订阅,还可以使用Purchases.subscriptions API的cancel()方法。 重要提示:Purchases.subscriptions API的return()和revoke()方法不支持测试购买。

所以我去play store的应用程序页面…具体做什么?该网页没有说明我应该在那里做什么。有人知道吗

它确实说:您还可以使用Purchases.subscriptions API的cancel()方法。

这表明使用cancel()方法不是唯一的方法


如何在不在我的应用程序中添加额外代码的情况下解决此问题?

我找到了一个不太方便但有效的解决方案。看起来你可以消费不合算的产品,这样你就可以再次购买。我正在使用phonegap,因此我只有cordova插件购买插件的示例代码:

store.when("your.product.id").updated(product => {
    if(product.owned) {
        var transaction = product.transaction;
        product.transaction = null;
        store.inappbilling.consumePurchase(
            function() { // success
                alert("consume success");
            },
            function(err, code) { // error
                alert("consume error " + err)
            },
            product.id,
            transaction.id
        );
    }
});
当您调用
store.refresh()
或购买产品时,将调用更新的回调函数。因此,根据您的用例,您希望实现一种额外的检查何时使用产品的方法

我没有使用原生安卓应用内支付的经验,但显然你也可以在那里消费产品


编辑:对不起,我刚读到你不想在你的项目中包含额外的代码。我认为目前还不可能,但我想把我的答案保留在这里,因为这可能有助于其他人尝试测试应用内支付。

没有找到解决方案。 我的解决方法是从测试用户列表中删除当前的测试用户,进行真正的购买,然后使用商家控制台取消它

所有受管理的应用程序内产品均为耗材

如合同中所述

这意味着你可以消费自己的物品,而不是取消购买,然后重新购买。 我建议在应用程序启动时查询库存:

mIabHelper.queryInventoryAsync(this)

然后,您可以使用回调中拥有的项:

@Override
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
    Purchase purchase = inventory.getPurchase(MY_SKU);
    boolean isBought = (purchase != null && verifyDeveloperPayload(purchase));
    if (isBought) {
        mIabHelper.consumeAsync(purchase, new OnConsumeFinishedListener() {
            @Override
            public void onConsumeFinished(Purchase purchase, IabResult result) {
                //Clear the purchase info from persistent storage
            }
        });
    }
}

这对于测试IAB流是可以的,但请确保从发布版本中删除此代码。

我进入Google Play主控制台页面并单击订单管理。在这种情况下,我可以选择所有的测试购买和退款。我是这个应用程序的主要开发者,所以我有访问权限。如果您是一名测试人员,您可能需要联系支持团队,要求他们退还您的订单。

来自@mttmlllns

无需编写任何特殊的消费代码。只要使用adb 用于清除Google Play存储数据的命令:

adb shell pm clear com.android.vending
  • 在Play Console上,转到开发者帐户->帐户详细信息,设置许可证测试员(默认情况下您是一个)

  • 购买物品

  • 转到订单管理,选择这些测试订单,选择:退款,但在退款时不要忘记检查撤销。(我忘了撤销,现在找不到办法收回)


无论如何,另一个测试帐户也可以

queryPurchaseHistoryAsync方法仍然可以找到我在过去一年中所做的测试订单,尽管我很久以前已经消费、退款和撤销了这些订单。我发现一个有用的预防措施是清除Google Play Store应用程序中的数据(设置/应用程序/Google Play Store/存储/清除数据)。queryPurchaseHistoryAsync从这里提取过时的购买数据,尽管只有非联网(我发现完全不可靠)的QueryPurchaes才应该这样做。毕竟,你可能需要在你的应用程序中添加额外的代码,但不需要太多

随着对普通驱动器2的支持的下降(文档中的链接会将您带到“404页面不存在”错误,github文件被存档,更新到billing:2.1.0会在IABHeloper类中给您一个自动售货机导入编译错误),对于这个涉及IABHeloper的流行问题的答案可能会被认为是过时的。如果您遵循从这里开始的文档中的基本代码段,并且没有混乱的助手类,那么现在的计费就简单多了。一个持久的问题是“两个方法具有相同的擦除,但都没有覆盖另一个”方法冲突错误,您可能会在该实现中遇到此错误,请参见我的解决方案

一旦实现了最新的计费代码,您就可以在生产应用程序中创建一个隐藏触发器来调用QueryPurchaseHistorySync以获取purchaseHistoryRecordList。然后为此列表中的每个项目调用ConsumeAncy。以下是使用所有测试订单的基本代码,允许对非消费品进行多个测试:

billingClient.queryPurchaseHistoryAsync(BillingClient.SkuType.INAPP,
   new PurchaseHistoryResponseListener() {
      @Override
      public void onPurchaseHistoryResponse(BillingResult billingResult,
         List<PurchaseHistoryRecord> purchaseHistoryRecordList){                                            
         if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK
             && purchaseHistoryRecordList != null) {
             for (PurchaseHistoryRecord purchaserecord : purchaseHistoryRecordList) {
                 if(purchaserecord!=null){
                 ConsumeParams consumeParams =
                     ConsumeParams.newBuilder()
                    .setPurchaseToken(purchaserecord.getPurchaseToken())
                    .setDeveloperPayload(purchaserecord.getDeveloperPayload())
                    .build();                                                                 
                     billingClient.consumeAsync(consumeParams, consumelistener);
}}}}});
handleConsumablePurchasesAsync
val CONSUMABLE_SKUS = listOf(GAS, PREMIUM_CAR)