Google Play in-app billing version 3: crash on “it

2019-05-20 15:52发布

问题:

After (eventually) shipping a v2 implementation of the Google Play in-app billing, I've had nothing but problems with it post-launch. Dropped transactions, crashes, unable to restore, crazy errors like "can't download, you already own this item", and all sorts of other ridiculous things. Honestly, I've integrated IAB on iOS, Amazon App Store, Samsung Apps and Blackberry 10 now and the Google Play code has taken more time than all the others combined. Times ten. It's just terrible.

Anywayyyy, I've decided to try and implement v3 into my app. The integration process was much, much simpler, so kudos to Google for that. Also, restoring previous transactions now works as expected so that's great. However, I've got a couple of show-stopping problems:

  1. When the user dismisses the IAB dialog (i.e. tapping outside of the dialog borders), I don't receive any notification of this. I would expect to receive some kind of "user cancelled" failure event, but nothing is fired to onIabPurchaseFinished, onConsumeFinished or onQueryInventoryFinished. As a result my app doesn't respond to this and I'm left with a dirty great unused Activity on the screen. Am I missing some kind of "dialogIsFinished" event?
  2. When the user tries to purchase an item that they already own, the app crashes. Unbelievably it looks like this is the intended behaviour, as there's something alluding to this printed to the console ("In-app billing error: Unable to buy item, Error response: 7:Item Already Owned"). I understand that I'm supposed to query for restorable transactions at launch, but this isn't a solution as it's conceivable the user can navigate to the purchase flow of my UI before the restore operation finishes. Surely this should be a non-hard stop, like a dialog box or something? Am I doing something wrong here? I simply can't understand that somebody at Google thinks that this situation deserves a hard crash...

Thanks very much (in advance) for your help. I'm more than happy to share code if you think it's necessary, although my questions seem to be more about the functional design more than anything else. I'm hoping that I'm doing something wrong here, as it's inconceivable to me that a company as capable as Google would re-write this entire system and still have such massive holes all over the place... :-/

Thanks again,

Ben

回答1:

Hmm, that was my mistake. When I wrote launchPurchaseFlow(), I ended up missing some cleanup code on failure cases. Not only there, but also on a couple of catch{} clauses after that. Thanks for pointing that out! This has just been fixed in the source repository: http://code.google.com/p/marketbilling



回答2:

I had the same error, I accidentally forgot to consume the item after I purchased. But when I tried to purchase another of same item App crashed.

I dig through the Google IabHelper class and found out that this statement is not handled correctly. I made some small change and now it works. Instead of crashing send error message back with listener.

Here is the modified part of the code. It's in launchPurchaseFlow() method. I'm not sure that I did something good by changing the code it looked like needed. Hope it helps.

try {
        logDebug("Constructing buy intent for " + sku);
        Bundle buyIntentBundle = mService.getBuyIntent(3, mContext.getPackageName(), sku, ITEM_TYPE_INAPP, extraData);
        int response = getResponseCodeFromBundle(buyIntentBundle);
        if (response != BILLING_RESPONSE_RESULT_OK) {
            logError("Unable to buy item, Error response: " + getResponseDesc(response));

            result = new IabResult(response, "Unable to buy item");
            if (listener != null) listener.onIabPurchaseFinished(result, null);

            /* Finish Current Async Task*/
            flagEndAsync();

        } else {
            PendingIntent pendingIntent = buyIntentBundle.getParcelable(RESPONSE_BUY_INTENT);
            logDebug("Launching buy intent for " + sku + ". Request code: " + requestCode);
            mRequestCode = requestCode;
            mPurchaseListener = listener;
            act.startIntentSenderForResult(pendingIntent.getIntentSender(),
                                           requestCode, new Intent(),
                                           Integer.valueOf(0), Integer.valueOf(0),
                                           Integer.valueOf(0));

        }