I am trying to implement in-app-billing for my app.
I am following the implementation used in google's TriviaDrive sample app, and the relevant documentation on the Developer website.
My code is working as expected but when I try to "Query Items Available for Purchase", the resulting Inventory object contains 0 objects, even though I have created a product.
I have created a Managed Product with the id paid_version
using the Google Play Developer Console, as shown in the image below:
The documentation indicates that "To retrieve the product details, call queryInventoryAsync(boolean, List, QueryInventoryFinishedListener)
on your IabHelper instance."
In my own code I call
mHelper.queryInventoryAsync(true, iabItemSkus, mQueryFinishedListener)
where:
mHelper
is my IabHelper instance
iabItemSkus
is a List containing a single item with the value "paid_version"
mQueryFinishedListener
is my listener defined below.
IabHelper.QueryInventoryFinishedListener mQueryFinishedListener = new IabHelper.QueryInventoryFinishedListener() {
@Override
public void onQueryInventoryFinished(IabResult result, Inventory inv) {
if (result.isFailure()) {
Log.d(TAG, "Querying Inventory Failed: " + result);
return;
}
Log.d(TAG, "Title: " + inv.getSkuDetails(SKU_PAID).getTitle());
Log.d(TAG, "Description: " + inv.getSkuDetails(SKU_PAID).getDescription());
Log.d(TAG, "Price = " + inv.getSkuDetails(SKU_PAID).getPrice());
}
};
But on debugging I can see that the Inventory
object passed back in the QueryInventoryFinishedListener
contains 0 items, and so calls like inv.getSkuDetails(SKU_PAID).getTitle()
give a null pointer exception.
I can't work out where I'm going wrong. I was expecting the Inventory
object to contain the details for my paid_version
in-app product.
Below are just the parts of my code and LogCat I think are relevant to this problem (trying to avoid giving you code overload!), but if more detail on some other part of the code would be helpful, let me know.
From my activity:
...
private static final String SKU_PAID = "paid_version";
private static final String TAG = "MyActivity";
private IabHelper mHelper;
...
IabHelper.QueryInventoryFinishedListener mQueryFinishedListener = new IabHelper.QueryInventoryFinishedListener() {
@Override
public void onQueryInventoryFinished(IabResult result, Inventory inv) {
if (result.isFailure()) {
Log.d(TAG, "Querying Inventory Failed: " + result);
return;
}
Log.d(TAG, "Title: " + inv.getSkuDetails(SKU_PAID).getTitle()); // <-- Line 266 of MyActivity.java
Log.d(TAG, "Description: " + inv.getSkuDetails(SKU_PAID).getDescription());
Log.d(TAG, "Price = " + inv.getSkuDetails(SKU_PAID).getPrice());
}
};
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
final List<String> iabItemSkus = new ArrayList<String>();
iabItemSkus.add(SKU_PAID);
// In App Billing
String base64EncodedPublicKey = "... My Public Key ...";
mHelper = new IabHelper(this, base64EncodedPublicKey);
mHelper.enableDebugLogging(true);
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
@Override
public void onIabSetupFinished(IabResult result) {
if (!result.isSuccess()) {
Log.d(TAG, "Problem setting up In-app Billing: " + result);
}
// Have we been disposed of in the meantime? If so, quit.
if (mHelper == null) return;
// IAB is fully set up. Now, let's get list of available items
Log.d(TAG, "Setup successful. Querying inventory.");
mHelper.queryInventoryAsync(true, iabItemSkus, mQueryFinishedListener);
}
});
...
}
From my LogCat:
...
05-13 19:46:59.609 22390-22390/xxx.xxxxxx.xxxxxx D/IabHelper﹕ Starting in-app billing setup.
05-13 19:46:59.629 22390-22390/xxx.xxxxxx.xxxxxx D/IabHelper﹕ Billing service connected.
05-13 19:46:59.629 22390-22390/xxx.xxxxxx.xxxxxx D/IabHelper﹕ Checking for in-app billing 3 support.
05-13 19:46:59.629 22390-22390/xxx.xxxxxx.xxxxxx D/IabHelper﹕ In-app billing version 3 supported for xxx.xxxxxx.xxxxxx
05-13 19:46:59.639 22390-22390/xxx.xxxxxx.xxxxxx D/IabHelper﹕ Subscriptions AVAILABLE.
05-13 19:46:59.639 22390-22390/xxx.xxxxxx.xxxxxx D/MyActivity﹕ Setup successful. Querying inventory.
05-13 19:46:59.639 22390-22390/xxx.xxxxxx.xxxxxx D/IabHelper﹕ Starting async operation: refresh inventory
05-13 19:46:59.649 22390-22596/xxx.xxxxxx.xxxxxx D/IabHelper﹕ Querying owned items, item type: inapp
05-13 19:46:59.649 22390-22596/xxx.xxxxxx.xxxxxx D/IabHelper﹕ Package name: xxx.xxxxxx.xxxxxx
05-13 19:46:59.649 22390-22596/xxx.xxxxxx.xxxxxx D/IabHelper﹕ Calling getPurchases with continuation token: null
05-13 19:46:59.659 22390-22596/xxx.xxxxxx.xxxxxx D/IabHelper﹕ Owned items response: 0
05-13 19:46:59.659 22390-22596/xxx.xxxxxx.xxxxxx D/IabHelper﹕ Continuation token: null
05-13 19:46:59.659 22390-22596/xxx.xxxxxx.xxxxxx D/IabHelper﹕ Querying SKU details.
05-13 19:46:59.689 22390-22596/xxx.xxxxxx.xxxxxx D/IabHelper﹕ Querying owned items, item type: subs
05-13 19:46:59.689 22390-22596/xxx.xxxxxx.xxxxxx D/IabHelper﹕ Package name: xxx.xxxxxx.xxxxxx
05-13 19:46:59.689 22390-22596/xxx.xxxxxx.xxxxxx D/IabHelper﹕ Calling getPurchases with continuation token: null
05-13 19:46:59.699 22390-22596/xxx.xxxxxx.xxxxxx D/IabHelper﹕ Owned items response: 0
05-13 19:46:59.699 22390-22596/xxx.xxxxxx.xxxxxx D/IabHelper﹕ Continuation token: null
05-13 19:46:59.699 22390-22596/xxx.xxxxxx.xxxxxx D/IabHelper﹕ Querying SKU details.
05-13 19:46:59.829 22390-22596/xxx.xxxxxx.xxxxxx D/IabHelper﹕ Ending async operation: refresh inventory
05-13 19:46:59.829 22390-22390/xxx.xxxxxx.xxxxxx D/AndroidRuntime﹕ Shutting down VM
05-13 19:46:59.829 22390-22390/xxx.xxxxxx.xxxxxx W/dalvikvm﹕ threadid=1: thread exiting with uncaught exception (group=0x41b31ba8)
05-13 19:46:59.839 22390-22390/xxx.xxxxxx.xxxxxx E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: xxx.xxxxxx.xxxxxx, PID: 22390
java.lang.NullPointerException
at xxx.xxxxxx.xxxxxx.MyActivity$1.onQueryInventoryFinished(MyActivity.java:266)
at xxx.xxxxxx.xxxxxx.util.IabHelper$2$1.run(IabHelper.java:630)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5017)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
at dalvik.system.NativeStart.main(Native Method)
...
PS: I've just updated my code to highlight which is line 266.
Additional
I was experiencing this problem 12 hours after uploading my APK, and as you can see from the LogCat, it indicates "In-app billing version 3 supported"
for my app.
The problem persisted regardless of whether I set the Status of the IN-APP PRODUCT as active or inactive.
Now 24 hours later it magically decides to work correctly.
From this I can only determine that it was a problem with Google Play, not with my code.