应用内结算:"查询可供购买的商品"返回0项

时间:2014-05-13 10:48:27

标签: android google-play in-app-billing

我正在尝试为我的应用实施应用内结算 我正在关注谷歌的TriviaDrive示例应用程序中使用的实现,以及开发人员网站上的相关文档 我的代码按预期工作,但是当我尝试"Query Items Available for Purchase"时,生成的Inventory对象包含0个对象,即使我已经创建了一个产品。

我使用Google Play开发者控制台创建了一个ID为paid_version的托管产品,如下图所示: In-App Products - Screenshot

文档指出“要检索产品详细信息,请在IabHelper实例上调用queryInventoryAsync(boolean, List, QueryInventoryFinishedListener)。”

在我自己的代码中,我称之为 mHelper.queryInventoryAsync(true, iabItemSkus, mQueryFinishedListener)
其中:
mHelper是我的IabHelper实例 iabItemSkus是一个包含值为“paid_version”的单个项目的列表 mQueryFinishedListener是我的听众定义如下。

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());
        }
    };

但是在调试时我可以看到Inventory中传回的QueryInventoryFinishedListener对象包含0项,因此inv.getSkuDetails(SKU_PAID).getTitle()之类的调用会给出空指针异常。

我无法解决我出错的地方。我希望Inventory对象包含我的paid_version应用内商品的详细信息。

以下是我的代码部分和我认为与此问题相关的LogCat(试图避免给你代码重载!),但是如果代码的其他部分的更多细节会有所帮助,请告诉我。

来自我的活动:

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

来自我的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:我刚刚更新了我的代码,以突出显示第266行。


附加

我在上传APK后12小时遇到此问题,正如您在LogCat中看到的那样,它表示我的应用为"In-app billing version 3 supported"
无论我是否将IN-APP PRODUCT的状态设置为活动或非活动状态,问题仍然存在。

现在24小时后它神奇地决定正常工作。

由此我只能确定这是Google Play的问题,而不是我的代码。

6 个答案:

答案 0 :(得分:2)

我在同一条船上。我等着看看会发生什么。

在Google文档http://developer.android.com/training/in-app-billing/test-iab-app.html

有一个警告,也许这就是问题所在:

  

警告:上传APK for Google Play后可能需要2-3小时才能识别您更新的APK版本。如果您在Google Play识别上传的APK之前尝试测试您的应用程序,您的应用程序将收到“已取消购买”的回复,并显示错误消息“此版本的应用程序未启用应用内结算。”

答案 1 :(得分:1)

我遇到了同样的问题。如果你看看IabHelper代码,我认为问题是:

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

但是后面的几行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));

注意最后一行用所有拥有的 skus填充skuList。并非所有可用的。

所以答案是IabHelper并不真正支持查询可用的购买。

答案 2 :(得分:1)

要获取包含价格的可用购买列表,您需要使用参数调用queryInventoryAsync - 购物标识符列表:

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

答案 3 :(得分:1)

我已经尝试过上述解决方案,但是它对我不起作用,我从另一个代码中获得了解决方案,所以我只想分享一下,以便其他人可以得到帮助。有关Google应用内代码,请检查此google github project

区别在于调用queryInventoryAsync()时需要传递更多参数,并确保在onIabSetupFinished()成功初始化后在IabHelper内部调用以下方法。

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

准备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);
}

下面是您收到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();
            }
        }
    };

答案 4 :(得分:0)

要使应用内结算工作,请按以下步骤操作:

  • <uses-permission android:name="com.android.vending.BILLING" />权限添加到 AndroidManifest.xml
  • 创建已签名的APK并将其上传到开发者控制台,如alpha,beta或production。
  • 发布APK或create a google group and add an alpha list of testers
  • 您需要等待几个小时才能在应用中看到应用内购买

答案 5 :(得分:0)

迟到回答,我也遇到了同样的问题。在阅读了整整3天的文档后,我终于找到了罪魁祸首。

根据documentation

  

不再支持草稿应用程序。

     

以前,您可以发布&#34;草案&#34;你的应用版本   测试。不再支持此功能。相反,有   您可以通过两种方式测试预发布应用在Google上的运作方式   Play商店:

     

您可以将应用发布到Alpha或Beta分发渠道。   这使得该应用在Google Play商店中可用,但仅适用于   测试人员你戴上了&#34;白名单&#34;。在少数情况下,您可以测试Google   使用未发布的应用程序播放功能。例如,您可以测试   通过使用静态响应,未发布应用的应用内结算支持,   始终返回特定结果的特殊保留产品ID   (例如&#34;购买&#34;或&#34;退款&#34;)。

Google应该简化此过程。