【问题标题】:In-App Billing test: android.test.purchased already owned应用内结算测试:android.test.purchased 已拥有
【发布时间】:2012-12-03 12:23:24
【问题描述】:

我目前正在为未来的应用测试应用内结算,在我第一次成功“购买”测试项目“android.test.purchased”后,我现在每次尝试购买时都会收到响应代码 7再说一遍,这意味着我已经拥有了这件物品。

12-15 23:02:14.149:E/IabHelper(19829):应用内计费错误:无法 购买商品,错误响应:7:商品已拥有

据我了解,这种购买应该总是可以的,对吧?以便开发者可以测试他/她的应用?

如果没有,我如何将其状态“重置”为不拥有?我正在使用 Google In-App Billing Sample 中的 util 包。

【问题讨论】:

  • 我的招聘是虎钳..我需要已经拥有但每次允许购买的消息

标签: android in-app-billing


【解决方案1】:

转到 Google Play 开发者控制台,打开左侧的Order Management 菜单项,然后选择您要退款的订单。还要确保删除权利。

【讨论】:

  • 我同意这一点。根据 Google,To perform multiple test purchases for the same non-consumable product, you can refund and revoke purchases using Google Play Console.developer.android.com/google/play/billing/test 的更多详细信息。
  • 我想这应该是当今公认的答案。退款时,请确保同时删除测试买家的权利,否则该商品仍将归您所有。见stackoverflow.com/a/67633608/5369519
  • 如果我忘记删除权利,我该怎么办
【解决方案2】:

版本 3 - 最快的解决方法:清除 Google Play 商店的缓存将使“android.test.purchased”再次可用。

【讨论】:

  • 这不会影响系统上安装的其他应用程序吗?
  • @IgorGanapolsky,没有。只有模拟购买会受到影响。 “真正的”购买存储在 Google 的服务器上,不会被修改。
  • 我已经清除了 Google Play 应用数据,但它不起作用。测试购买详情仍然存在。
  • @Richard 通过“设置/应用程序管理器/”或将 Google Play 商店图标从菜单拖到“信息”按钮(在屏幕顶部)。最后,只需点击“清除缓存”按钮。
  • 对我来说最好的答案。其他都不错,但是这个绝对是最快的解决方法
【解决方案3】:

将此代码添加到线程以发起消费请求。

int response = mService.consumePurchase(3, getPackageName(), purchaseToken);

这里为购买测试,purchaseToken为

purchaseToken = "inapp:" + getPackageName() + ":android.test.purchased";

if (response == 0)

则消费成功。

也别忘了在中公开 mService

IabHelper.Java

那么就可以这样访问了:

int response = mHelper.mService.consumePurchase(3, getPackageName(), purchaseToken);

【讨论】:

  • 传说这行得通,@psykhi 真的应该给你积分。我试图消费它,但无法计算出购买令牌。谢谢
  • 这是一个巨大的节省时间。完美的。谢谢。
  • 什么是mService?帮手?但我找不到 consumePurchase()
  • mService是IInAppBillingService.aidl接口的对象,绑定了inapp购买发起的购买服务。
  • 我还想指出,如果您使用具有安全性的 IABHelper,您可能需要更新 verifyPurchase 以返回 true。就我而言,它失败了,默认情况下只需要返回 true。
【解决方案4】:

主要问题是您必须使用 android.test.purchased 项目。但此商品在您的查询库存中不可用,因此您无法使用正常流程消费。

因此,如果您使用的是 IabHelper,在 IabHelper 类中,您可以暂时将 IInAppBillingService mService 更改为 public,以便可以从您的 IabHelper 访问它。

那么在你的课堂上,你可以这样消费,

int response = mHelper.mService.consumePurchase(3, getPackageName(), "inapp:"+getPackageName()+":android.test.purchased");

如果成功,则响应为 0。

希望这会有所帮助。

【讨论】:

  • Tangent:您能否为托管项目退款(使用测试帐户 - 它似乎没有显示在仪表板中)?
  • 您可以在 android.test.purchased 上致电 consumeAsync()。没有问题。
  • 对于简单的测试,如果使用 IabHelper,这是最好的方法。帮助了我。
【解决方案5】:

出于测试目的,我还建议您在调用初始化 gp 购买流程的方法之前插入一段代码,该代码将清除您购买的所有产品。当您目前只测试一个项目时,这尤其舒适。例如。像这样:

PurchasesResult purchasesResult = mBillingClient.queryPurchases(BillingClient.SkuType.INAPP);
    for (Purchase sourcePurchase : purchasesResult.getPurchasesList()) {
        if(sourcePurchase != null){

            ConsumeResponseListener listener = new ConsumeResponseListener() {
                @Override
                public void onConsumeResponse(String outToken, @BillingResponse int responseCode) {

                    System.out.println("all consumed");
                }
            };
            mBillingClient.consumeAsync(sourcePurchase.getPurchaseToken(), listener);
        }else{
            System.out.println("null");
        }
    }

// and then initiate whole process with clear "shoping basket"

BillingFlowParams.Builder builder = new BillingFlowParams.Builder()
        .setSku(itemName).setType(BillingClient.SkuType.INAPP);

【讨论】:

    【解决方案6】:

    如果你在测试环境中

    1)对于android.test.purchased,我可以通过重启android设备(消耗库存)来重置假支付。

    2) 在 InApp util 中有一个名为 Security.java 的文件,如下所示,用于临时。由于安全异常,测试支付(假)总是返回false。

    public static boolean verifyPurchase(String base64PublicKey,
                                         String signedData, String signature) {
        return true; }
    

    然后在你的 OnIabPurchaseFinishedListener 调用 fechInvForconsumeItem()

    IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener
                = new IabHelper.OnIabPurchaseFinishedListener() {
            public void onIabPurchaseFinished(IabResult result,
                                              Purchase purchase)
            {
                if (result.isFailure()) {
                    // Handle error
                    Log.e("123","Failure");
    
                    return;
                }
                else if (purchase.getSku().equals(ITEM_SKU)) {
                    Log.e("123","PURCAsed");
                    fechInvForconsumeItem(); // Restart device if not consume
    
                }
    
            }
        };
    

    fechInvForconsumeItem() 是

        public void fechInvForconsumeItem() {
        mHelper.queryInventoryAsync(mReceivedInventoryListener);
    }
    IabHelper.QueryInventoryFinishedListener mReceivedInventoryListener
            = new IabHelper.QueryInventoryFinishedListener() {
        public void onQueryInventoryFinished(IabResult result,
                                             Inventory inventory) {
    
    
            if (result.isFailure()) {
                // Handle failure
                Log.e("11","Failure");
    
    
    
            } else {
                Log.e("11","suc");
                mHelper.consumeAsync(inventory.getPurchase(ITEM_SKU),
                        mConsumeFinishedListener);
            }
    
    
        }
    };
    

    消费监听器是

        IabHelper.OnConsumeFinishedListener mConsumeFinishedListener =
            new IabHelper.OnConsumeFinishedListener() {
                public void onConsumeFinished(Purchase purchase,
                                              IabResult result) {
    
                    if (result.isSuccess()) {
                    } else {
                        // handle error
                        Log.e("11","sucConsume");
                    }
                }
            };
    

    【讨论】:

      【解决方案7】:

      就我而言,我只需要清除应用程序缓存。清除缓存后,我可以再次启动购买流程。

      从我的设备 (4.4.2),我导航到“设置->应用程序管理器”。接下来,我从“下载”选项卡中选择了该应用程序,然后选择了“清除缓存”。

      【讨论】:

        【解决方案8】:

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

        adb shell pm clear com.android.vending
        

        【讨论】:

        • 感谢它完成了我只需要清除应用程序的技巧,因此我提供了完整的答案。这对我来说是正确的方法。
        • 这对很多人来说都是正确的方法。将代码添加到您的应用并重新部署更耗时(双关语)。
        • 这对于测试设备来说是一个很好的解决方案,但要小心:它会重置您在 Google Play 商店应用中的所有设置。所以,我宁愿不在我的个人设备上这样做。
        • 不!这是个坏主意,您失去了对其他产品和其他应用程序的应用内购买,好的一个是如果您想测试您的应用内购买,您必须消费产品,场景只是创建两件东西,一件用于购买,另一件用于消费购买项目。
        • @RahulMandaliya 您的应用应该能够通过使用 getPurchases() API 了解已购买的内容来抵御缓存清除。
        【解决方案9】:

        在我看来,如果您的程序不是为使用该项目而设计的,那么您无需调整代码以清除外部供应商的内存。这将使您的代码更加脆弱,然后您将不得不花费大量时间来添加和删除不属于您的软件的代码,因此实施这样的解决方案是一个糟糕的设计。

        对我来说清除 android.test.purchased 的最佳解决方案是

        adb uninstall com.yourapp.name
        

        然后

        adb shell pm clear com.android.vending
        

        我不需要清算现金并浏览我的应用设置或更改代码。我确实需要将 adb 添加到 Windows 系统的路径变量中,这非常简单。所以是的,你需要使用你可能需要的 adb 所以..

        您只需添加您的 C:\ ...\android-sdk\platform-tools;在环境变量中的windows路径中,我想它在mac和linux os中也很简单。希望它可以帮助某人在应用计费中实现 android 少花几天的时间。

        【讨论】:

        • uninstall 不需要清除 android.test.purchased sku。
        【解决方案10】:

        就我而言,Google 似乎没有记录该商品的购买记录。相反,Google Play 服务的本地副本会缓存购买。这样,当在同一设备上发出第二个请求时,android.test.purchased already owned 就会出现。但是,使用其他设备或重置设备会清除缓存,并允许重复购买。

        【讨论】:

          【解决方案11】:
          IabHelper.QueryInventoryFinishedListener 
                 mQueryFinishedListener = new IabHelper.QueryInventoryFinishedListener() {
                 public void onQueryInventoryFinished(IabResult result, Inventory inventory)   
                 {
                    if (result.isFailure()) {
                       return;
                     }          
                    try {
          
                          if(inventory.hasPurchase("product_sku_id"))
                          {   
                               isItemEnable= true;
                               mHelper.consumeAsync(inventory.getPurchase("product_sku_id"),null);            
                          }
                          else
                          {
                                 isItemEnable = false;
                          }           
          
                      } catch (Exception e) {
                          e.printStackTrace();
                      }
                 }
          
              };
          

          【讨论】:

            【解决方案12】:

            这就是我们可以使用物品的方式

             consume.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        Thread t = new Thread(new Runnable() {
                            @Override
                            public void run() {
                                String purchaseToken = "inapp:" + getPackageName() + ":android.test.purchased";
                                try {
                                    Log.d("","Running");
                                    int response = mService.consumePurchase(3, getPackageName(), purchaseToken);
                                    if(response==0)
                                    {
                                        Log.d("Consumed","Consumed");
                                    }else {
                                        Log.d("","No"+response);
                                    }
                                }catch (RemoteException e)
                                {
                                    Log.d("Errorr",""+e);
                                }
            
                            }
                        });
                        t.start();
                    }
                });
            

            【讨论】:

            • 为我工作 - 在某些时候使用了 android.test.purchase,这导致了问题 - 应用内结算中的库存任务只是抛出了大量错误并且从未完成。一次性运行它会清除它,这样我就可以继续使用我的实际 SKU 并像以前一样继续使用它。谢谢
            • 优秀的答案。使用静态响应 = 在启用应用内结算的 apk 上传到 Google Play 之前。
            • 谢谢!为我工作。
            【解决方案13】:

            应用内版本 3:

            IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
            
                public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
            
                    .....................
            
                    if (inventory.hasPurchase(SKU_CONTENT)) {
            
                        mHelper.consumeAsync(inventory.getPurchase(SKU_CONTENT), null);
                    }
                }
            };
            

            【讨论】:

            • 一张图片值一千字,一个完整的可工作的基本代码片段值一千 '将此代码添加到线程中。 . .'.
            【解决方案14】:

            事实证明,android.test.purchased 项的行为类似于常规 ID。这意味着如果您想再次购买它,您必须在代码中的某个地方使用它。我认为 Google 文档在这个问题上具有误导性,他们应该添加另一个静态 ID,您可以无休止地购买以进行测试。

            【讨论】:

            • 使用inventory调用来获取Purchase对象,然后使用它——一旦你了解它就很容易了。
            • 看下面@mttmlins的回答,或者阅读vvse.com/blog/blog/2016/08/26/…
            • 不完全正确,我有一个案例,其中有未使用的测试项目,但billingClient.queryPurchases() 不会返回未使用的项目,所以现在我无法消费项目,因为我无法获得 purchaseToken 的它
            【解决方案15】:

            这是消耗品和非消耗品的区别;非消耗性物品(您似乎在这里处理的东西)会持续跟踪它们的状态,而消耗性物品可以多次购买。您必须进入 Play 管理控制台并取消/退款以再次测试。

            【讨论】:

            • 但问题是我对这些“假”商品没有任何“权力”,而且我不知道在哪里可以更改销售状态,因为它们不是真正的购买。 google doc 提到了 android.test.purchased :当您使用此产品 ID 提出应用内结算请求时,Google Play 会像您成功购买商品一样做出响应。所以我很漂亮困惑:/
            • 你还在做静态响应测试吗?如果是这样,您只需要更改发送的静态响应。不过,听起来您正在使用“使用您自己的产品 ID 测试应用内购买”,这可以通过可取消的订单进行真正的购买。
            • 我仍然坚持使用静态 ID。我想要的是能够使用 android.test.purchased ID 测试应用内购买。它只是第一次工作,它应该总是根据我从谷歌文档中理解的内容工作。对不起,如果我不清楚!
            • 我的误解,对不起。在那种情况下……我不知道。每次肯定都应该返回成功,我没有看到你看到的情况。对不起。
            • 睡一晚后会尝试再次查看问题 :) 感谢您的帮助!
            猜你喜欢
            • 1970-01-01
            • 2012-07-08
            • 2018-01-10
            • 2014-06-25
            • 1970-01-01
            • 1970-01-01
            • 2017-05-13
            • 2015-12-09
            • 2014-05-04
            相关资源
            最近更新 更多