Billing API v3 IabHelper NullPointerException Billing API v3 IabHelper NullPointerException android android

Billing API v3 IabHelper NullPointerException


edit 4/15: Catching nullpointer in IabHelper appears to have stopped this problem. I am no longer seeing the exceptions being thrown, I'm going to accept this as an answer.


edit 4/04: A little bit of a deeper dive. There are try catch blocks that handle RemoteExceptions and JSONExceptions for the queryPurchases method, but no NullPointerException handling. What I am going to try is include NullPointer Exception handling so IabHelper looks like this when trying to querySkuDetails:

    catch (NullPointerException e) {        throw new IabException(IABHELPER_UNKNOWN_ERROR, "NullPointer while refreshing inventory.", e);    }

I just filed a bug on this:

https://code.google.com/p/marketbilling/issues/detail?id=114


Change

        if (querySkuDetails) {            r = querySkuDetails(ITEM_TYPE_INAPP, inv, moreItemSkus);            if (r != BILLING_RESPONSE_RESULT_OK) {                throw new IabException(r, "Error refreshing inventory (querying prices of items).");            }        }

to

        if (querySkuDetails) {            try {                r = querySkuDetails(ITEM_TYPE_INAPP, inv, moreItemSkus);                if (r != BILLING_RESPONSE_RESULT_OK) {                    throw new IabException(r, "Error refreshing inventory (querying prices of items).");                }            } catch (NullPointerException e) {                throw new IabException(IABHELPER_UNKNOWN_ERROR, "NPE while refreshing inventory.", e);            }        }

Change

            if (querySkuDetails) {                r = querySkuDetails(ITEM_TYPE_SUBS, inv, moreSubsSkus);                if (r != BILLING_RESPONSE_RESULT_OK) {                    throw new IabException(r, "Error refreshing inventory (querying prices of subscriptions).");                }            }

to

            if (querySkuDetails) {                try {                    r = querySkuDetails(ITEM_TYPE_SUBS, inv, moreSubsSkus);                    if (r != BILLING_RESPONSE_RESULT_OK) {                        throw new IabException(r, "Error refreshing inventory (querying prices of subscriptions).");                    }                } catch (NullPointerException e) {                    throw new IabException(IABHELPER_UNKNOWN_ERROR, "NPE while refreshing inventory.", e);                }            }


You are probably using async operations. The current IabHelper is not safe in case you use the ...async methods. The problem is that in any moment an async operation is running dispose can be called on the main thread. In this case you will get NullPointerExceptions and IllegalStateExceptions.

Here is the patch fixing it:

Index: src/com/evotegra/aCoDriver/iabUtil/IabHelper.java===================================================================--- src/com/evotegra/aCoDriver/iabUtil/IabHelper.java   (revision 1162)+++ src/com/evotegra/aCoDriver/iabUtil/IabHelper.java   (working copy)@@ -86,7 +86,10 @@     // Is an asynchronous operation in progress?     // (only one at a time can be in progress)-    boolean mAsyncInProgress = false;+    volatile boolean mAsyncInProgress = false;+    +    // is set to true if dispose is called while a thread is running. Allows graceful shutdown+    volatile boolean mDisposeRequested = false;     // (for logging/debugging)     // if mAsyncInProgress == true, what asynchronous operation is in progress?@@ -285,6 +288,12 @@      * disposed of, it can't be used again.      */     public void dispose() {+       // do not dispose while an async Thread is running. Will cause all kinds of exceptions.+       // In this case dispose must be called from thread after setting mAsyncInProgress to true+       if (mAsyncInProgress) {+           mDisposeRequested = true;+           return;+       }         logDebug("Disposing.");         mSetupDone = false;         if (mServiceConn != null) {@@ -827,6 +836,7 @@         logDebug("Ending async operation: " + mAsyncOperation);         mAsyncOperation = "";         mAsyncInProgress = false;+        if (mDisposeRequested) IabHelper.this.dispose();     }

Or download the patch here.http://code.google.com/p/marketbilling/issues/detail?id=139&thanks=139&ts=1375614409


Slightly modify the beginning of the queryPurchases method to look like this:

int queryPurchases(Inventory inv, String itemType) throws JSONException, RemoteException {        // Query purchases        //logDebug("Querying owned items, item type: " + itemType);       //logDebug("Package name: " + mContext.getPackageName());       boolean verificationFailed = false;       String continueToken = null;        do {//            logDebug("Calling getPurchases with continuation token: " + continueToken);            if(mDisposed || mService==null) return IABHELPER_UNKNOWN_ERROR;            Bundle ownedItems = mService.getPurchases(3, mContext.getPackageName(),                    itemType, continueToken);

Thanks to sebastie for pointing out the cause of this.