Android 安卓应用内计费v3:“;Can';t执行操作:queryInventory“;

Android 安卓应用内计费v3:“;Can';t执行操作:queryInventory“;,android,in-app-billing,Android,In App Billing,我第一次使用新的v3 API设置了应用内计费。它在我的设备上正常工作,但我收到了许多来自其他用户的错误报告 其中之一是: java.lang.IllegalStateException: IAB helper is not set up. Can't perform operation: queryInventory at my.package.util.iab.IabHelper.checkSetupDone(IabHelper.java:673) at my.package.

我第一次使用新的v3 API设置了应用内计费。它在我的设备上正常工作,但我收到了许多来自其他用户的错误报告

其中之一是:

java.lang.IllegalStateException: IAB helper is not set up. Can't perform operation: queryInventory
    at my.package.util.iab.IabHelper.checkSetupDone(IabHelper.java:673)
    at my.package.util.iab.IabHelper.queryInventory(IabHelper.java:462)
    at my.package.util.iab.IabHelper$2.run(IabHelper.java:521)
    at java.lang.Thread.run(Thread.java:1019)
另一个是:

java.lang.NullPointerException
    at my.package.activities.MainActivity$4.onIabSetupFinished(MainActivity.java:159)
    at my.package.util.iab.IabHelper$1.onServiceConnected(IabHelper.java:242)
我的活动实现遵循Google的示例代码(所有引用的类都未从示例中触及):

我假设这两个错误都来自标记为
***(1)****

这些错误的原因是什么?如果我仅在
onIabSetupFinished
内调用
queryInventoryAsync
,怎么可能
mHelper
为空,或者
mHelper
未设置


有人知道这个问题的解决方案吗?

确保您在活动中实现了
IabHelper.han.handleActivityResult(requestCode、resultCode、data)
方法

   @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {

// Pass on the activity result to the helper for handling
  if (!mIabHelper.handleActivityResult(requestCode, resultCode, data)) {
      // not handled, so handle it ourselves (here's where you'd
      // perform any handling of activity results not related to in-app
      // billing...
      super.onActivityResult(requestCode, resultCode, data);
  } else {
      Log.i(TAG, "onActivityResult handled by IABUtil.");
  }
}

我用几乎完全相同的代码得到了完全相同的错误

这似乎只发生在某些手机上(实际上,在最近的错误报告中,似乎只有Acer Iconia平板电脑!!)-我正在处理ActivityResult

Google v3计费示例中有许多错误可能导致ANRs/FCs——我怀疑这只是另一个错误(令人遗憾的是,劣质代码和劣质文档正在成为Google的商标)

我的猜测是——就目前而言——我们需要允许mHelper或mGotInventoryListener为null,并在这种情况下禁用应用内计费(就好像result.issucess()基本上是false)


p、 这可能是因为用户的Play Store版本已经过时,只有在允许运行的情况下才会自动更新

我也会犯同样的错误。我还遇到了其他问题

在我的Galaxy Tab 7上禁用应用内计费的设备上有多个google帐户。删除一个帐户并重新启用它

我在GT-P5110、LGL75C和GT-S5839i等上看到了应用内计费示例代码的问题

(我在安装了ACRA的应用程序中使用该代码……所以每次它崩溃时,我都会得到信息)

Android版本的设备范围从2.3.3到4.0.4


这很烦人。

我的助手中有一个bug。异常处理程序中的返回行丢失,这意味着它将通过并调用success hanlder-但是,尚未设置mSetupDone,因此对API的进一步调用将失败。在中添加return语句,如下所示-此操作仍将失败,但故障将正确报告给您的应用程序,以便您可以采取适当的操作

                catch (RemoteException e) {
                if (listener != null) {
                    listener.onIabSetupFinished(new IabResult(IABHELPER_REMOTE_EXCEPTION,
                                                "RemoteException while setting up in-app billing."));
                }
                e.printStackTrace();
                return;  // This return line is missing
            }

            if (listener != null) {
                listener.onIabSetupFinished(new IabResult(BILLING_RESPONSE_RESULT_OK, "Setup successful."));
            }

正如@Martin所解释的,Google应用内计费示例中有一个bug导致了这种情况

但是,在修复它之后,我仍然在内部调用中收到一些错误(
queryInventory
queryInventoryAsync
中创建的线程内部,在一些罕见的情况下,报告没有设置帮助器)。我已经解决了这个问题,在这种情况下添加了一个额外的捕获:

try {
    inv = queryInventory(querySkuDetails, moreSkus);
}
catch (IabException ex) {
    result = ex.getResult();
}
catch(IllegalStateException ex){ //ADDED THIS CATCH
    result = new IabResult(BILLING_RESPONSE_RESULT_ERROR, "Helper is not setup.");
}
我还在
mHelper.dispose()
上遇到了一个崩溃,我用类似的方式修复了它:

try{
    if (mContext != null) mContext.unbindService(mServiceConn);
}
catch(IllegalArgumentException ex){ //ADDED THIS CATCH
    //IGNORE IT - somehow, the service was already unregistered
}
当然,不必忽略这些错误,您可以将它们静默地记录到ACRA,例如:)


感谢您的评论。

您可以随时了解inapp v3 API开发的最新情况,网址为


那里的代码比Android SDK管理器提供的代码更新。

我认为Android代码中仍然存在两个错误,这解释了为什么您仍然看到错误。请注意,调用堆栈位于独立线程上。但是将mSetupDone(IabHelper)设置为true的代码在主UI线程上执行。Java不保证由于CPU缓存,一个线程更改的数据对另一个线程可见,除非您使用volatile关键字声明变量。因此,它可能是设置好的(mSetupDone==true),但mSetupDone的新值被缓存在UI线程上,该线程在调用堆栈中还不可见。因此该线程仍然看到mSetupDone==false

为了安全起见,我试图通过使用volatile声明mSetupDone,以及IabHelper的每个其他非最终字段来解决这个问题


现在另一个问题是.dispose()函数。它不会停止正在进行的线程。这意味着当一个工作线程正在运行时,它可以将mSetupDone设置为false。如果查看queryInventoryAsync(),您将看到它确实检查mSetupDone是否为true。根据你的调用堆栈,它确实通过了。随后它崩溃,mSetupDone==false。唯一可能发生的方法是在线程运行时调用dispose()。修复方法是dispose()需要向线程发出信号,使其在看到mSetupDone==false时,只是静静地退出,而不是继续并抛出错误。这还可以防止IABHeloper的另一个问题,即已处理的实例即使在被处理之后也会调用侦听器回调!在这里逐行解释有点复杂,但希望能为您指明正确的方向。

我发现了!这是关于用户的Google Play Store应用程序的版本。应用内计费V3需要3.9.16或更高版本()。
我使用了一个旧版本,我收到了这个错误,现在在4.4.21它的ok

除了@DavidM和@Ereza

IabHelpr类的另一个主要问题是在多个方法中抛出RuntimeException(IllegalStateException)的选择不当。在大多数情况下,从您自己的代码中抛出RuntimeException是不可取的,因为它们是未检查的异常。这就像是在破坏你自己的应用程序——如果不被捕获,这些异常将冒泡并使你的应用程序崩溃

解决方案是实现您自己的checked异常,并将IABHeloper类更改为抛出它,而不是IllegalStateException。这将迫使您在编译时将异常抛出到代码中的任何地方都处理该异常

这是我的自定义例外
try{
    if (mContext != null) mContext.unbindService(mServiceConn);
}
catch(IllegalArgumentException ex){ //ADDED THIS CATCH
    //IGNORE IT - somehow, the service was already unregistered
}
public class MyIllegalStateException extends Exception {

    private static final long serialVersionUID = 1L;

    //Parameterless Constructor
    public MyIllegalStateException() {}

    //Constructor that accepts a message
    public MyIllegalStateException(String message)
    {
       super(message);
    }
}
try {
   setUpBilling(targetActivityInstance.allData.getAll());
} catch (MyIllegalStateException ex) {
    ex.printStackTrace();
}
m_iabHelper = new IabHelper(this, base64EncodedPublicKey); // Declare

m_iabHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() { // Setup
    public void onIabSetupFinished(IabResult result) {
        // Setup code
    }
}

// Don't do this, will produce an error
List additionalSkuList = new ArrayList(); 
additionalSkuList.add(SKU_MYSKU);
m_iabHelper.queryInventoryAsync(true, additionalSkuList, m_queryFinishedListener);
// Don't do this, will produce an error