10

I am using Google's In-App Billing for my Android app.

I used the IabHelper class from Google's how to, as their billing seems extremely complicated.

My issue is I want to know if the purchase is successful or not. I think I'm following the process correctly, but in my logs I see a lot of users that get the upgrade, but whose purchase never shows up in my Google Play payments account. (i.e. they get the upgrade for free).

I'm logging the GP order ids, sometimes its a number like,

GPA.1234-5678-9123-1234

But sometimes its like,

1234567891234.1234567891234

Normally I think its the non GPA orders that don't get charged.

Also I think you can put an order through, then cancel it, and still get the upgrade?

How do you ensure the user really paid?

Code:

IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
    public void onIabPurchaseFinished(IabResult result, final Purchase purchase) {
        if (result.isFailure()) {
            showMessage("Google Billing Purchase Error");                   
            return;
        } else if (purchase.getSku().equals(sku)) {
            IabHelper.QueryInventoryFinishedListener mReceivedInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
                public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
                    if (result.isFailure()) {
                        showMessage("Google Billing Error");
                        return;
                    } else {
                        if (inventory.hasPurchase(sku)) {
                            showMessage("Thank you for upgrading");
                            grantUpgrade();
                            // ** This line gets call, but no payment occurs.
                        }
                    }
                }
            };
            mHelper.queryInventoryAsync(mReceivedInventoryListener);
        }
    }
};
mHelper.launchPurchaseFlow(this, sku, 10001, mPurchaseFinishedListener, "");

*** updated to check "inventory.hasPurchase(sku)" but still see users who get the upgrade but don't pay.

** maybe the users are using Freedom hack? Anyway to prevent this?

James
  • 17,965
  • 11
  • 91
  • 146
  • Do you want to review your order history in short? – KishuDroid May 11 '16 at 08:12
  • If you're going to call out a particular hack, you may need to provide a link that describes it and what exactly it is instead of assuming that everyone knows what it is :) – JoxTraex May 12 '16 at 00:14
  • See https://github.com/soomla/android-store/issues/47 or Google "Google Play in-app hack" or "Freedom hack" – James May 12 '16 at 18:14
  • Hmm, there are some solutions here I think, http://stackoverflow.com/questions/21966369/protecting-in-app-purchases-from-freedom-hack, I will try these and see if they work – James May 15 '16 at 11:26
  • Still no luck at preventing fraud on Google Play, I have tried everything, but still get fraud purchases every day – James Jun 19 '16 at 16:45

3 Answers3

3
 if (result.isFailure()) {
    //If the user aborts or any other problems it will jump here 
  }
  else {
    //The user purchased some item, check out which it is 
    mIsPremium = inventory.hasPurchase(SKU_ANY_ITEM);        
  }

So concerning your question, this code already verify whether the user really purchased the item !

Chris Sherlock
  • 931
  • 5
  • 19
  • Except is doesn't. The "Thank you" line is executed for purchases that never show up in Google payment. – James Apr 28 '16 at 02:03
  • Do you mean you have to check for "hasPurchase" in the onQueryInventoryFinished, i.e. isFailure can be false, but still no purchase? – James Apr 28 '16 at 02:08
  • If so, will "hasPurchase" always be true if they purchased the item, or is there a time lag? – James Apr 28 '16 at 02:09
  • There is no time lag, you should check for "hasPurchase" and if it Returns true, you can be pretty sure he bought the item ! – Chris Sherlock Apr 28 '16 at 09:47
  • Hmmm, that doesn't seem to fix it completely, I still see users able to get the upgrade, but who don't pay – James May 07 '16 at 19:30
  • Mh, to be honest I think this is a problem you can't fix on your own. Did you already contacted google in this case ? – Chris Sherlock May 07 '16 at 22:21
  • No, but I assume Google Payment works?? I guess you have to expect some fraud every so often, but I get many upgrades per day that do not make any payment, the transactions never have a GPA.1234-5678-9123-1234, but show 1234567891234.1234567891234, not sure what this ? master card vs google play account? – James May 08 '16 at 01:31
  • It is strange, because you even double check if the payment has been done, so there is no Problem with the Code you use. Do you know, that the Upgrades you get reported are from different users ? Maybe the grantUpgrade() method just gets called multiple times for one user ? – Chris Sherlock May 08 '16 at 09:59
  • do you know what the account numbers mean? GPA. 1234 vs 1234.5678 – James May 09 '16 at 22:03
  • @James : Check this link for understanding these numbers : http://stackoverflow.com/questions/31602234/google-play-order-id-updated-to-new-format – KishuDroid May 11 '16 at 08:19
  • Hmm, maybe the users getting the free purchases are using the Freedom hack, any way to prevent this? – James May 12 '16 at 00:10
2
Purchase premiumPurchase = inventory.getPurchase(SKU);

boolean mIsPremium = (premiumPurchase != null 
           && verifyDeveloperPayload(premiumPurchase));

if(mIsPremium){
    ...
}
Nick Cardoso
  • 20,807
  • 14
  • 73
  • 124
1

The Google Play Store keeps track of purchases for you, so you shouldn't assume that just because a purchase was successful, the item will stay purchased. It's possible for a user to get a refund for a purchase. For this reason, you need to query the user's inventory every time you launch and adjust your grants appropriately. You would need to do this check anyways in order to support users that expect to have the grant when they switch to a new device or uninstall/reinstall the app.

Jschools
  • 2,698
  • 1
  • 17
  • 18
  • For point in time purchases check if they still have the purchase in the future does not help, they already got the item. Hard to use in-app purchasing if you can't trust it. – James May 12 '16 at 00:10
  • You could consume the managed purchase, so that once it is consumed it cannot be refunded. Not sure if it supports your use case, but it may help. – Jschools May 12 '16 at 16:57