how to cancel an in-app test purchase on android?

AndroidBillingIn App

Android Problem Overview


Until june 20th 2016 i was able to cancel test purchases done in my app. Doing multiple in-app purchases (not consumable) from the same test account made it easy to develop and test the code without too much hazzle.

After 20th june 2016, the purchases did not show in my merchant account and i was unable to do more than 1 purchase from my test account. All i got was the: "you already own this item" message.

I logged a request to the google developer support group and the answer was:

Beginning June 20, 2016, we changed test purchases for one-time in-app purchases (IAPs). Previously, test purchases for one-time IAPs generated order IDs. Starting June 20, 2016, one-time IAPs do not generate official order IDs (if at all) and will not appear in the Merchant Center. This behavior already applies to subscription IAPs. You can learn more about testing in-app billing in the Android Developers Help Center: https://developer.android.com/google/play/billing/billing_testing.html#testing-purchases

allright.. so i go to the mentioned link and theres a section there: Canceling completed test purchases which states:

Google Play accumulates completed test purchases for each user but does not pass them on to financial processing. In some cases, you might want to manually cancel a test purchase to continue testing. To do so, open the app page in the Play Store. If the test purchase that you want to cancel is a subscription, you can also use the cancel() method of the Purchases.subscriptions API. Important: The refund() and revoke() methods of the Purchases.subscriptions API don't support test purchases.

So I go to the app page in play store...and do what exactly? the webpage does not state what i am supposed to do there. anyone know?

it does say: you can also use the cancel() method of the Purchases.subscriptions API.

which indicates that using the cancel() method is not the only method.

How to solve this without adding additional code in my app?

Android Solutions


Solution 1 - Android

I went into the main Google Play Console page and clicked on Order Management. Under that I was able to select all test purchases and Refund them. I'm the primary developer of the app so I have access. If you are a tester you'd probably have to contact the support team and request that they refund your order.

Solution 2 - Android

> All managed in-app products are consumable.

as stated in the docs.

That means that you can consume an owned item instead of cancelling the purchase and buy it all over again. I suggest querying the inventory at the app launch time:

mIabHelper.queryInventoryAsync(this);

You can then consume the owned item in the callback:

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

This is OK for testing the IAB flow but make sure to remove this code from the release version.

Solution 3 - Android

From https://stackoverflow.com/a/30178861/326904 @mttmllns

> 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

Solution 4 - Android

  • On Play Console, go to Developer Account -> Account Details, set the license testers (you are one by default)

  • Purchase items

  • Go to Order Management, choose those test orders, select: refund, but DON'T FORGET to check REVOKE when you are refunding. (I forgot to revoke, and now can't find a way to take them back)

Anyway, another test account will do.

Solution 5 - Android

I found a solution which isn't very convenient, but works. It seems like you can consume uncomsumable products and that way you can buy them again. I'm working with phonegap so I only have example code for the cordova-plugin-purchase plugin:

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

The updated callback gets called when you call store.refresh() or buy the product. So depending on your use case you'd want to implement an additional method of checking when to consume the product.

I have no experience with the native Android in-app payments, but obviously you will be able to consume the products there as well.

Edit: Sorry, I just read that you didn't want to include additional code in your project. I don't think that's possible at the moment, but would like to keep my answer here because it might help other people trying to test in-app payments.

Solution 6 - Android

What worked for me was a combination of both:

  • Go to order management and refund
  • clear cache/data in Play Store app (as well as your app in you placed some shared prefs).

Also, in case you get an item already owned status, you can consume the purchase using the purchase token and calling billingClient.consumeAsync().

Solution 7 - Android

Didn't find a solution for this. My workaround is simply remove the current test user from the test users list, make a real purchase, then cancel it using the merchant console.

Solution 8 - Android

The queryPurchaseHistoryAsync method still finds test orders I've made over the last year, despite having long ago consumed, refunded, and revoked them. One precaution I've found helpful is clearing the data in the Google Play Store app (settings/apps/google play store/storage/clear data). queryPurchaseHistoryAsync pulls obsolete purchase data from here, although only the non-networking (and completely unreliable I've found) queryPurchases is supposed to do this. You may have to add additional code to your app after all, but it doesn't have to be much.

With the dropping of support for Trivial Drive 2 (the link in the docs takes you to a '404 page does not exist' error, the github files are archived, and updating to billing:2.1.0 will give you a vending import compile error in the IabHelper class), answers to this popular question involving IabHelper might be considered obsolete. Billing is a lot simpler now if you follow the basic code pieces in the docs starting here https://developer.android.com/google/play/billing/billing_overview with no messy helper classes. One persistent issue is a 'Both methods have same erasure, yet neither overides the other' method clash error you may run into with this implementation, see my solution here https://stackoverflow.com/questions/59707015/both-methods-have-same-erasure-yet-neither-overides-the-other-method-clash-er.

Once you have the newest billing code implemented, you can create a hidden trigger in your production app to call queryPurchaseHistoryAsync to get a purchaseHistoryRecordList. Then call consumeAsync for each item in this list. Here is the barebones code to consume all test orders, allowing multiple tests of your nonconsumables:

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

Solution 9 - Android

For people using a way based on the new TrivialDriveKotlin, consumable products are consumed during the installation of the app in the method

handleConsumablePurchasesAsync

If your purchase is not consumable, you can make it consumable by adding the corresponding sku into CONSUMABLE_SKUS in the GameSku object. Exemple:

val CONSUMABLE_SKUS = listOf(GAS, PREMIUM_CAR)

Then uninstall your app from your device and install it again, and your non consumable purchase is available again. Fast and simply. Of course, don't forget to remove your

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKennethJohansenView Question on Stackoverflow
Solution 1 - AndroidcminusView Answer on Stackoverflow
Solution 2 - Androiddev.bmaxView Answer on Stackoverflow
Solution 3 - AndroidDesolatorView Answer on Stackoverflow
Solution 4 - Androiduser2167374View Answer on Stackoverflow
Solution 5 - AndroidMoriturView Answer on Stackoverflow
Solution 6 - AndroidchitgoksView Answer on Stackoverflow
Solution 7 - AndroidEliView Answer on Stackoverflow
Solution 8 - AndroidAndroidcoderView Answer on Stackoverflow
Solution 9 - AndroidTurvyView Answer on Stackoverflow