android: Inapp billing: Error response: 7:Item Already Owned

前端 未结 5 1030
面向向阳花
面向向阳花 2021-01-31 09:09

I am learning to implement an in-app billing for my app such that people can for example, donate $ when press the donate button.

The user is allowed to donate more than

相关标签:
5条回答
  • 2021-01-31 09:21

    I'm using: implementation 'com.android.billingclient:billing:2.0.0' and had the same error on purchase process.

    • the point is: before of launching the purchase we should consume the pending purchases.
    • please see the code snippet below:

          List<String> skuList = new ArrayList();
          skuList.add(THE_IAP_ID);
          BillingClient.Builder billingClientBuilder = BillingClient.newBuilder(context).setListener(new PurchasesUpdatedListener() {
              @Override
              public void onPurchasesUpdated(BillingResult billingResult, @Nullable List<Purchase> purchases) {
                   // here we have to check the result ...
      
              });
      
              billingClientBuilder.enablePendingPurchases();
              billingClient = billingClientBuilder.build();
              billingClient.startConnection(new BillingClientStateListener() {
              @Override
              public void onBillingSetupFinished(BillingResult billingResult) {
                  if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
                      // The BillingClient is ready - query purchases.
      
                      Purchase.PurchasesResult pr = billingClient.queryPurchases(BillingClient.SkuType.INAPP);
                      List<Purchase> pList = pr.getPurchasesList();
                      for (Purchase iitem : pList) {
                          ConsumeParams consumeParams = ConsumeParams.newBuilder()
                                  .setPurchaseToken(iitem.getPurchaseToken())
                                  .build();
                          billingClient.consumeAsync(consumeParams, consumeResponseListener);
                      }
      
                      // process the purchase
                  } else {
                      // cancelled or s.e. 
                      ...
                  }
              }
      

    Best Regards, Have you fun :)

    0 讨论(0)
  • 2021-01-31 09:35

    Check my below code here:

    I don't understand in your code why have you used query inventory in purchase finish listener. ConsumeAsync() method should be call while you getting the sku same as your requested sku.

    // Callback for when a purchase is finished
        IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
            public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
                Log.d(TAG, "Purchase finished: " + result + ", purchase: "
                        + purchase);
                if (result.isFailure()) {
                    complain("Error purchasing: " + result);
                    return;
                }
                if (!verifyDeveloperPayload(purchase)) {
                    complain("Error purchasing. Authenticity verification failed.");
                    return;
                }
    
                Log.d(TAG, "Purchase successful.");
    
                if (purchase.getSku().equals(SKU_GAS)) {
    
                     // remove query inventory method from here and put consumeAsync() directly
                    mHelper.consumeAsync(purchase, mConsumeFinishedListener);
    
                }
    
            }
        };
    

    startSetup method

    // you have forgot to call query inventory method in startSetup method.

     mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
                    public void onIabSetupFinished(IabResult result) {
                        Log.d(TAG, "Setup finished.");
    
                        if (!result.isSuccess()) {
                            // Oh noes, there was a problem.
                            complain("Problem setting up in-app billing: " + result);
                            return;
                        }
    
                        // Hooray, IAB is fully set up. Now, let's get an inventory of
                        // stuff we own.
                        Log.d(TAG, "Setup successful. Querying inventory.");
                        mHelper.queryInventoryAsync(mGotInventoryListener);
                    }
                });
    

    QueryInventoryFinishedListener

    And also check if condition purchase is same as you are requested is not equals to null and developer payload is also same in your query inventory finish listener.

    if (gasPurchase != null && verifyDeveloperPayload(gasPurchase)){
        //code
    }
    
    // Listener that's called when we finish querying the items and
            // subscriptions we own
            IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
                public void onQueryInventoryFinished(IabResult result,
                        Inventory inventory) {
                    Log.d(TAG, "Query inventory finished.");
                    if (result.isFailure()) {
                        complain("Failed to query inventory: " + result);
                        return;
                    }
    
                    Log.d(TAG, "Query inventory was successful.");
    
                    /*
                     * Check for items we own. Notice that for each purchase, we check
                     * the developer payload to see if it's correct! See
                     * verifyDeveloperPayload().
                     */
    
                    // // Check for gas delivery -- if we own gas, we should fill up the
                    // tank immediately
                    Purchase gasPurchase = inventory.getPurchase(SKU_GAS);
                    if (gasPurchase != null && verifyDeveloperPayload(gasPurchase)) {
                        Log.d(TAG, "We have gas. Consuming it.");
                        mHelper.consumeAsync(inventory.getPurchase(SKU_GAS),
                                mConsumeFinishedListener);
                        return;
                    }
                }
            };
    

    Explaination why it happends:

    Whenever you purchased consumable item google play store will not be managed it's product purchased detail and other things in the Google play console. That's why we have to call consumeAsync() method. when we purchased item, Google play store keep record item has been purchased for the one time and allow you to purchased second time.

    Hope it will solve your problem.

    0 讨论(0)
  • 2021-01-31 09:35

    I managed to "consume the purchase" simply by restarting the device.

    0 讨论(0)
  • 2021-01-31 09:38

    You purchased "android.test.purchased" but did not consume it. However, if you forgot to consume it immediately, it is not easy to consume it again. We can wait for 14 days. The fake purchase will be cleared automatically. But it is not acceptable.

    I spent a lot of time finding the solution:

    Add this line to get debug info.

    _iabHelper.enableDebugLogging(true, "TAG");
    

    Run the app. In LogCat, you will see a json string like

    {"packageName":"com.example","orderId":"transactionId.android.test.purchased","productId":"android.test.purchased","developerPayload":"123","purchaseTime":0,"purchaseState":0,"purchaseToken":"inapp:com.example:android.test.purchased"}
    

    Consume it manually (Replace THAT_JSON_STRING with your json string)

        Purchase purchase;
        try {
            purchase = new Purchase("inapp", THAT_JSON_STRING, "");
            _iabHelper.consumeAsync(purchase, new OnConsumeFinishedListener() {
    
                @Override
                public void onConsumeFinished(Purchase purchase, IabResult result) {
                    Log.d("TAG", "Result: " + result);
                }
            });
        } catch (JSONException e) {
            e.printStackTrace();
        }
    

    _iabHelper is mHelper.

    0 讨论(0)
  • 2021-01-31 09:41

    You can use Google Play "FINANCIAL REPORTS"->"Visit your merchant account for more details"->"Orders" to View and Cancel any order to "consume it". Then you need to restart your device. =)

    0 讨论(0)
提交回复
热议问题