Google应用内结算导致异常 [英] Google In-App Billing causing Exception

查看:251
本文介绍了Google应用内结算导致异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的一个Android应用程序中,我正在尝试从Google的应用内结算中轻松获取广告资源,但是它不断地向我发送错误。

  mHelper.queryInventoryAsync(mGotInventoryListener); 

其中包含


IabHelper未设置。无法执行操作:queryInventory


这是所有的IabHelper代码。

  mHelper = new IabHelper(this,base64EncodedPublicKey); 
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener(){
public void onIabSetupFinished(IabResult result){
if(!result.isSuccess()){
// Oh noes,有一个问题
Log.d(TAG,设置应用内结算中的问题+结果);
}
// Hooray,IAB完全设置!
}
});
//检查广告是否已被删除(已购买)
IabHelper.QueryInventoryFinishedListener mGotInventoryListener
= new IabHelper.QueryInventoryFinishedListener(){
public void onQueryInventoryFinished(IabResult result,
库存盘点){

if(result.isFailure()){
// handle error here
}
else {
//用户有高级升级?
if(inventory.hasPurchase(REMOVE_ADS))removeAdsPurchased = true;
//相应地更新UI
}
}
};
mHelper.queryInventoryAsync(mGotInventoryListener);


解决方案

简而言之,您的queryInventoryAsync()调用应该由你的onIabSetupFinished()方法制成。这是一个异步调用,因此您不能继续使用IabHelper实例,直到调用该回调来告诉您帮助者与计费服务的通信已经建立。您的代码当前编写的方式,您有竞争条件,并且您的queryInventoryAsync()调用将赢得该比赛,并尝试在设置之前使用IabHelper对象,这是您的问题的原因。 p>

此外,依赖于此对象的UI处理程序中的任何其他代码(例如,启动购买的按钮的处理程序)应测试完全设置的IabHelper对象,并且不允许用户使用该UI元素,直到在onCreate()中创建的IabHelper实例已成功完成安装。处理这种情况的最简单的方法是简单地禁用这样的UI元素,直到调用安装程序回调来指示安装程序已经成功完成。



这是很容易的部分。当您的onCreate()方法运行后(即不在用户控制之下)出现紧急操作时,会出现更严重的问题,这些操作需要使用完全设置的IabHelper实例。这通常是由于活动生命周期调用而发生的,特别是onResume()(如果有一些需要IabHelper实例的东西,每当您的应用程序进入前台时,必须执行此操作,而不在 当onCreate ()被调用),最值得注意的是在onActivityResult()(当用户完成或中止与计费界面的交互时调用,例如作为应用内付款的一部分)。



问题是您的应用程序可能被操作系统停止(例如,在用户启动购买时为帐单界面本身腾出空间),导致您的IabHelper实例与您的应用程序一起销毁,并且当您的onCreate()被下一次调用时,该实例将必须重新生成,并且安装程序将再次在onCreate()中启动,并且再次需要等待安装程序完成对该对象做任何其他事情。



可能发生这种情况的一个显着的情况是在用户与计费界面的交互作为购买过程的一部分。该交互的结果将通过onActivityResult()传递给您的应用程序,该功能本身需要使用完全设置的IabHelper对象,因此,如果您的应用程序在内存中刷新,而用户正在与计费服务进行交互(或取消)购买,那么onActivityResult()将不得不等待IabHelper实例再次设置(在重新创建之后才能使用onCreate()。



处理这个的一种方法是设置并发布到需要IabHelper实例的待处理操作的队列,即onResume()和/或onActivityResult()代码添加到该队列中,并将该队列由您的一旦IabHelper设置(由onCreate()发起),onIabSetupFinished()方法就已经完成了。



这不是微不足道的,上次我检查了TrivialDrive示例应用程序没有处理以上情况。



测试这种用例的最好方法是使用开发人员选项不要保持Activiti es,这会导致您的应用程序在每次用户离开时被销毁,以便在需要回收内存时模拟操作系统将执行的操作,以便您可以确保您的应用程序在这些条件下正常工作。


In one of my Android apps, I'm trying to implement a simple grab of the inventory from Google's In-App billing, but it keeps giving me errors at the line of

mHelper.queryInventoryAsync(mGotInventoryListener);

with the message that

IabHelper is not setup. Can't perform operation: queryInventory

Here is all the IabHelper code.

    mHelper = new IabHelper(this, base64EncodedPublicKey);
    mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
           public void onIabSetupFinished(IabResult result) {
              if (!result.isSuccess()) {
                 // Oh noes, there was a problem.
                 Log.d(TAG, "Problem setting up In-app Billing: " + result);
              }            
                 // Hooray, IAB is fully set up!  
           }
        });
    //check to see if ads have been removed(bought)
    IabHelper.QueryInventoryFinishedListener mGotInventoryListener 
       = new IabHelper.QueryInventoryFinishedListener() {
       public void onQueryInventoryFinished(IabResult result,
          Inventory inventory) {

          if (result.isFailure()) {
            // handle error here
          }
          else {
            // does the user have the premium upgrade?
            if(inventory.hasPurchase(REMOVE_ADS)) removeAdsPurchased = true;     
            // update UI accordingly
          }
       }
    };
    mHelper.queryInventoryAsync(mGotInventoryListener);

解决方案

The short answer is that your queryInventoryAsync() call should be made from inside your onIabSetupFinished() method. This is an asynchronous call, and so you cannot just proceed with using the IabHelper instance until that callback has been invoked to tell you that the helper's communication with the billing service has been established. The way your code is presently written, you have a race condition, and your queryInventoryAsync() call is going to win that race and attempt to use the IabHelper object before it has been set up, which is the cause of your problem.

Also, any further code in UI handlers that relies upon this object (e.g., the handler for a button that initiates a purchase) should test for a fully set-up IabHelper object, and should not allow the user to use that UI element until the IabHelper instance created in onCreate() has successfully completed setup. The easiest way to handle this situation is to simply disable such UI elements until the setup callback has been invoked to indicate that setup has completed successfully.

That is the easy part. The more serious problems occur when you have actions that occur immediately after your onCreate() method runs (i.e., not under the control of the user), that require the use of a fully set-up IabHelper instance. This typically occurs as a result of activity lifecycle calls - specifically, onResume() (if there is something requiring an IabHelper instance that must be done each time your app comes to the foreground, and not just when onCreate() is called) and, most notably, in onActivityResult() (which is invoked when the user completes or aborts an interaction with the billing interface - e.g., as part of making an in-app payment).

The problem is that your app may be stopped by the OS (e.g., to make room for the billing interface itself when the user initiates a purchase), causing your IabHelper instance to be destroyed along with your app, and that instance will have to be regenerated when your onCreate() is next invoked, and setup will once again be initiated in onCreate(), and once again you will need to wait for setup to complete before doing anything else with that object.

One notable situation where this can occur is during the user's interaction with the billing interface as part of the purchase process. The result of that interaction will be communicated to your app via onActivityResult(), which itself needs to use a fully set-up IabHelper object, and so if your app gets flushed from memory while the user is interacting with the billing service to make (or cancel) a purchase, then onActivityResult() will have to wait for the IabHelper instance to get set up again (after it is re-created in onCreate() before it can use it.

One way to handle this would be to set up and post to a queue of pending actions requiring an IabHelper instance, that your onResume() and/or onActivityResult() code adds to, and have that queue processed by your onIabSetupFinished() method once the IabHelper setup (initiated by onCreate()) has completed.

It's not trivial. And last time I checked, the TrivialDrive sample app did not handle the above situation.

The best way to test this kind of use case is to use the developer option "Don't Keep Activities," which causes your app to be destroyed each time the user leaves it, to simulate what the OS will do when it needs to reclaim memory, so that you can make sure your app works under those conditions.

这篇关于Google应用内结算导致异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆