Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In-App Billing test: android.test.purchased already owned

I am currently testing In-App Billing for a future app, and after I successfully "bought" the test item "android.test.purchased" the first time, I now receive the response code 7 every time I try to buy it again, which means that I already own this item.

12-15 23:02:14.149: E/IabHelper(19829): In-app billing error: Unable to buy item, Error response: 7:Item Already Owned

From what I understand, this purchase is supposed to always be possible, right? So that the developer can test his/her app?

If not, how can I "reset" its state to not owned? I am using the util package from the Google In-App Billing Sample.

like image 739
psykhi Avatar asked Dec 15 '12 22:12

psykhi


People also ask

How can I check my Android subscription?

Open the Google Play app. Choose Account -> Subscriptions & Payments -> Subscriptions. Click your test subscription and change the payment method to “Test card, always declines.” After five minutes, payment should be declined.

How do I check my Google Play Billing Library?

To test your Google Play Billing Library integration using test tracks, do the following: Publish your app to a test track. Note that after you publish an app to a testing track, it can take a few hours for the app to be available for testers. Ensure each tester opts-in to your app's test.


11 Answers

Add this code to a thread to initiate consume request.

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

Here for the purchase test, purchaseToken is

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

And

if (response == 0)

then the consumption is successful.

also don't forget to make mService public in

IabHelper.Java

then it would be possible to access like this:

int response = mHelper.mService.consumePurchase(3, getPackageName(), purchaseToken);
like image 132
Aashutosh Sharma Avatar answered Oct 05 '22 23:10

Aashutosh Sharma


No need to write any special consumption code. Just use the adb command for clearing the Google Play Store data:

adb shell pm clear com.android.vending
like image 25
mttmllns Avatar answered Oct 06 '22 00:10

mttmllns


It turns out that the android.test.purchased item behaves like a regular ID. It means that if you want be able to buy it again, you have to consume it somewhere in your code. I think that the Google documentation is misleading on this matter, and that they should add another static ID that you can buy endlessly for test purposes.

like image 21
psykhi Avatar answered Oct 06 '22 00:10

psykhi


In-app version 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);
        }
    }
};
like image 41
embo Avatar answered Oct 05 '22 23:10

embo


Version 3 - Fastest way to solve : Clearing the cache of Google Play Store will let "android.test.purchased" available again.

like image 41
Denis Avatar answered Oct 05 '22 22:10

Denis


This is how we can consume the Item

 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();
        }
    });
like image 34
Shivaraj Patil Avatar answered Oct 05 '22 23:10

Shivaraj Patil


In my opinion if your program is not designed to consume the item you do not need to tweak the code in order to clear the memory of an outside vendor. This will make your code more fragile and you will have then to spend a lot of time to add and remove code that does not belong to your software so it is a bad design to implement a solution like that.

The best solution that worked for me to clear android.test.purchased was

adb uninstall com.yourapp.name

and then

adb shell pm clear com.android.vending

I did not need to clear cash and to browse my apps setting or to change code for that. I did need to add the adb to path variables of windows system which was pretty straight forward. So yes you need to use adb which you probably need anyway so..

You just add your C:\ ...\android-sdk\platform-tools; in windows path in environment variables, and I imagine that it is pretty simple in mac and linux os as well. Hope it helps someone to spend few days less with implementing android in app billings.

like image 24
sivi Avatar answered Oct 06 '22 00:10

sivi


Go to the Google Play Developer Console, open Order Management menu item from the left side and select the order you want to refund. Also make sure to remove the entitlement.

like image 20
Sai Nadh Avatar answered Oct 05 '22 22:10

Sai Nadh


The main issue is you have to consume the android.test.purchased item. But this item won't be available in your query inventory, so you can't consume using the normal flow.

So, if you are using IabHelper, in IabHelper class, you can temporarily change the IInAppBillingService mService to public so that it is accessible from your IabHelper.

Then in your class, you can consume like this,

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

If success, the response is going to be 0.

Hope this helps.

like image 32
Tang Tung Ai Avatar answered Oct 05 '22 22:10

Tang Tung Ai


For testing purposes I also suggest you to insert a piece of code that will be clearing all the products that you've bought before calling a method that initializes gp purchase flow. That is especially comfortable, when you test just one item at the moment. E.g. like this:

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);
like image 34
sodiumnitrat Avatar answered Oct 05 '22 22:10

sodiumnitrat


If you are in test environment

1) In the case of android.test.purchased, I can reset the fake payment by restarting android device(consumed the inventory).

2) In InApp util there is a file called Security.java make it as following, for temporary. Since the testing payment(fake) always return false due to security exception.

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

Then in your OnIabPurchaseFinishedListener call 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

            }

        }
    };

The fechInvForconsumeItem() is

    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);
        }


    }
};

Consume Listener is

    IabHelper.OnConsumeFinishedListener mConsumeFinishedListener =
        new IabHelper.OnConsumeFinishedListener() {
            public void onConsumeFinished(Purchase purchase,
                                          IabResult result) {

                if (result.isSuccess()) {
                } else {
                    // handle error
                    Log.e("11","sucConsume");
                }
            }
        };
like image 33
Ebin Joy Avatar answered Oct 05 '22 23:10

Ebin Joy