In-app billing: "Request items available for purchase" returns 0 points

I am trying to implement in-app-billing for my application.
I follow the implementation used in the Google TriviaDrive sample application and the related documentation on the developer's website.
My code works as expected, but when I try to "Request items available for purchase" , the resulting Inventory object contains 0 objects, although I have created a product.

I created a managed product with the paid_version ID using the Google Play Developer Console, as shown in the image below: In-App Products - Screenshot

The documentation states that "To get product details, call queryInventoryAsync(boolean, List, QueryInventoryFinishedListener) in your IabHelper instance."

In my own code, I call mHelper.queryInventoryAsync(true, iabItemSkus, mQueryFinishedListener)
Where:
mHelper - my instance of IabHelper
iabItemSkus is a list containing one 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 when debugging, I see that the Inventory object passed back to the QueryInventoryFinishedListener contains 0 elements, and therefore calls like inv.getSkuDetails(SKU_PAID).getTitle() provide a null pointer exception.

I can’t understand where I am going wrong. I expected the Inventory object to contain the details for my paid_version product in the application.

Below are only parts of my code and LogCat that I think are relevant to this problem (trying to avoid code overload!), But if more detailed information about any other part of the code is useful, 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 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 just updated my code to highlight line 266.


Additionally

I experienced this problem 12 hours after loading the APK, and as you can see from LogCat, it indicates "In-app billing version 3 supported" for my application.
The problem persisted whether I was set to IN-APP PRODUCT status active or inactive.

Now, after 24 hours, he magically decides to work correctly.

From this, I can only determine that it was a problem with Google Play, and not with my code.

+7
android google-play in-app-billing
source share
6 answers

I'm in the same boat. I'm waiting to see what happens.

In the google documentation http://developer.android.com/training/in-app-billing/test-iab-app.html

there is a warning, maybe this is the problem:

Caution: It may take 2-3 hours to download your updated version of the APK through downloading the APK for Google Play. If you try to test your application before your APK is recognized by Google Play, your application will receive a “canceled purchase response with an error message”. This version of the app is not included for In-app Billing. "

+2
source share

In order to work with In-App Billing, follow these steps:

  • Add <uses-permission android:name="com.android.vending.BILLING" /> AndroidManifest.xml permission.
  • Create a signed APK and upload it to the developer console as alpha, beta or release.
  • Publish an APK or create a google group and add an alpha list of testers .
  • You need to wait a few hours to see in-app purchases in your app
+1
source share

I have the same problem. If you look at the IabHelper code, I think the problem is this:

Inside queryInventory:

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

But then the first few lines of querySkuDetails:

 int querySkuDetails(String itemType, Inventory inv, List<String> moreSkus) throws RemoteException, JSONException { logDebug("Querying SKU details."); ArrayList<String> skuList = new ArrayList<String>(); skuList.addAll(inv.getAllOwnedSkus(itemType)); 

Notice that the last line fills the skuList with everything skus. Not all available.

So the answer is that IabHelper really does not support requests for affordable purchases.

+1
source share

I tried the solution above, but it will not work for me, and I got the solution from my other code, so I just want to share, so that others can get help. For google code in app please check this google github project

The difference lies in calling queryInventoryAsync() with another parameter that you must pass, and make sure that the method below calls the call inside onIabSetupFinished() after successfully initializing IabHelper .

 runOnUiThread(new Runnable() { @Override public void run() { refreshItemList(); } }); 

Prepare skurequest

 private void refreshItemList() { List<String> itemSku = new ArrayList<>(); List<String> subSku = new ArrayList<>(); subSku.add(AppConstant.InApp.SKU_ONE_ID); mHelper.queryInventoryAsync(true, itemSku, subSku, mQotInventoryListener); } 

Below is a listener where you get your SkuDetails

 IabHelper.QueryInventoryFinishedListener mQotInventoryListener = new IabHelper.QueryInventoryFinishedListener() { @Override public void onQueryInventoryFinished(IabResult result, Inventory inv) { try { Log.d(TAG, "mQotInventoryListener Query inventory finished."); // Have we been disposed of in the meantime? If so, quit. if (mHelper == null) return; // Is it a failure? if (result.isFailure()) { Log.e(TAG, "mQotInventoryListener Failed to query inventory: " + result); return; } Log.d(TAG, "mQotInventoryListener Query inventory was successful."); try { //Here you just pass SKU_ID that you want its detail SkuDetails skuDetails = inv.getSkuDetails(AppConstant.InApp.SKU_ONE_ID); if (skuDetails != null) { Log.d(TAG, "skuDetails are received"); } else { Log.e(TAG, "skuDetails are null"); } } catch (Exception e) { e.printStackTrace(); } } catch (Exception e) { e.printStackTrace(); } } }; 
+1
source share

Late, I also ran into the same problem. After reading all the documentation for 3 days, finally I found the culprit.

According to the documentation :

Application projects are no longer supported.

Previously, you could publish a draft version of your application for testing. This feature is no longer supported. Instead, there are two ways you can check how the application functions in the Google Play store before release:

You can publish the application for alpha channels or beta distribution channels. This makes the app available on the Google Play store, but only for testers that you whitelisted. In some cases, you may want to check out Google Listen functionality with an unpublished app. For example, you can check the unpublished billing support in the application using static responses, special reserved product identifiers that always return a specific result (for example, “bought” or “returned”).

Google should make this process easier.

0
source share

To get a list of available purchases with prices, you need to call queryInventoryAsync with parameters - lists of trade identifiers:

 ArrayList<String> skuList = new ArrayList<String> (); skuList.add("purchase1"); ArrayList<String> subsList = new ArrayList<String> (); subsList.add("subscribe1"); mHelper.queryInventoryAsync(true, skuList, subsList, mGotInventoryListener); 
0
source share

All Articles