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

早过忘川 提交于 2019-12-02 17:07:45
Maulik

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.

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.

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

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. =)

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 :)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!