29

新しい v3 API を使用して初めてア​​プリ内課金をセットアップしました。私のデバイスでは正しく動作していますが、他のユーザーから多くのエラー レポートを受け取りました。

それらの1つは次のとおりです。

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)

もう1つは次のとおりです。

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 のサンプル コードに従います (参照されるすべてのクラスは、サンプルから変更されていません)。

IabHelper mHelper;

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    //...

    mHelper = new IabHelper(this, IAB_PUBLIC_KEY);
    mHelper.enableDebugLogging(true);

    mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
        public void onIabSetupFinished(IabResult result) {
            if (!result.isSuccess()) {
                // Oh noes, there was a problem.
                return;
            }

            // Hooray, IAB is fully set up. Now, let's get an inventory of
            // stuff we own.
            mHelper.queryInventoryAsync(mGotInventoryListener); //***(1)***
        }
    });
}

// Listener that's called when we finish querying the items we own
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
    public void onQueryInventoryFinished(IabResult result,
            Inventory inventory) {
        if (!result.isFailure()) {
            if (inventory.hasPurchase(SoundsGlobals.IAB_SKU_PREMIUM)){
                //we are premium, do things
            }
        }
        else{
            //oops
        }
    }
};

@Override
protected void onDestroy() {
    if (mHelper != null) {
        mHelper.dispose();
        mHelper = null;
    }
    super.onDestroy();
}

両方のエラーは、次のようにマークされた行から発生していると思います***(1)***

これらのエラーの原因は何ですか? queryInventoryAsync内でのみ呼び出している場合、null である、または設定されていないonIabSetupFinished可能性はありますか?mHelpermHelper

誰もこれに対する解決策を知っていますか?

4

11 に答える 11

19

@Martin が説明したように、これを引き起こした Google アプリ内課金の例にバグがありました。

ただし、それを修正した後も、内部呼び出しでいくつかのエラーを受け取りました (まれに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 に記録することもできます。たとえば:)

コメントありがとうございます。

于 2013-03-09T13:29:07.697 に答える
14

IABHelper にバグがあります。例外ハンドラーの戻り行がありません。つまり、ドロップスルーして成功ハンドラーを呼び出します。ただし、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."));
            }
于 2013-02-06T20:01:07.203 に答える
10

Android コードにはまだ 2 つのバグが残っていると思いますが、これが原因でまだエラーが表示されるのです。コール スタックがスタンドアロン スレッド上にあることに注意してください。ただし、mSetupDone (IabHelper) を true に設定するコードは、メイン UI スレッドで実行されます。volatile キーワードを使用して変数を宣言しない限り、Java は、CPU キャッシングのために、あるスレッドによって変更されたデータが他のスレッドに表示されることを保証しません。したがって、セットアップされた (mSetupDone == true) 可能性がありますが、mSetupDone の新しい値は UI スレッドにキャッシュされ、コール スタック内のこのスレッドにはまだ表示されていません。そのスレッドはまだ mSetupDone == false を認識します。

安全のために、mSetupDone を volatile で宣言し、IabHelper の他のすべての非最終フィールドも宣言して、これを修正しようとしました。

もう 1 つの問題は .dispose() 関数です。進行中のスレッドは停止しません。これは、ワーカー スレッドの 1 つが実行されている間に、mSetupDone を false に設定できることを意味します。queryInventoryAsync() を見ると、mSetupDone が true であることを確認していることがわかります。そして、コールスタックに基づいて、それを乗り越えました. その後、mSetupDone == false でクラッシュしました。これが発生する唯一の方法は、スレッドが飛行中に dispose() が呼び出された場合です。修正は、mSetupDone == false が検出されたときに、dispose() が続行してエラーをスローするのではなく、サイレントにベイルアウトするようにスレッドに通知する必要があることです。これにより、破棄されたインスタンスが破棄された後でもリスナーのコールバックを呼び出すという IabHelper のさらに別の問題も防止できます。ここで行ごとに説明するのは少し複雑ですが、うまくいけば、正しい方向に向けることができます。

于 2013-05-25T14:09:51.310 に答える
2

IabHelper.han.handleActivityResult(requestCode, resultCode, data)アクティビティ メソッドでメソッドを実装していることを確認してくださいonActivityResult

   @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.");
  }
}
于 2013-01-02T07:36:22.980 に答える
2

ほぼ同じコードで、まったく同じエラーが発生します。

特定のハンドセットでのみ発生しているようです (実際、最近のエラー レポートでは、Acer Iconia Tablet だけで発生しているようです!!) - そして、onActivityResult を処理しています...

Google v3 Billing Sample には、ANR/FC を引き起こす可能性のあるエラーが多数あります。これは単なる別のエラーではないかと思います (残念なことに、粗雑なコードと粗雑なドキュメントは Google の商標になりつつあります)。

私の推測では、今のところ、mHelper または mGotInventoryListener のいずれかが null であることを許可し、その場合はアプリ内課金を無効にする必要があると思います (基本的に、result.isSuccess() が false であるかのように)。

psを追加して編集しました-ユーザーが古いバージョンのPlayストアを使用している可能性があります-実行を許可した場合にのみ自動更新されます!?

于 2013-01-04T12:17:05.700 に答える
1

上記のすべてが役に立たない場合は、コードを少し分析してみてくださいIabHelper。呼び出し時に本当に設定されていますか?

気づかないうちに少し間違っていることに気づきました。間違った使い方の簡単な例Activity.onCreate()

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

.

上記では、「IAB ヘルパーが設定されていません」というエラーが表示されます。これは、アプリが を実行しようとしたm_iabHelper.queryInventoryAsync()ときに IabHelper がまだ設定されていないためです。これらの関数を、その関数が呼び出された後またはどこかで使用することを検討してくださいonIabSetupFinished()(例: の外側onCreate()) 。

于 2014-11-11T22:45:37.433 に答える
1

https://code.google.com/p/marketbilling/で inapp v3 API 開発の最新情報を入手できます。

そこにあるコードは、Android SDK Manager から入手できるコードよりも新しいものです。

于 2013-04-23T07:58:50.023 に答える
0

同じエラーが発生します。また、他の問題に遭遇しました...

デバイスに複数のGoogleアカウントがあると、Galaxy Tab 7でアプリ内課金が無効になりました.1つのアカウントを削除すると、再度有効になりました.

GT-P5110、LGL75C、GT-S5839i などで、アプリ内課金のサンプル コードに問題が見られます。

(ACRAがインストールされたアプリケーションでコードを使用しています...クラッシュするたびに情報を取得します)

デバイスの Android バージョンは、2.3.3 から 4.0.4 までの範囲です。

それは非常に迷惑です。

于 2013-01-11T00:44:01.477 に答える
0

IABHelper.java には多くの問題がありました。

まず、SDK Manager によってダウンロードされるバージョンが最新に保たれていません。ここにあるバージョンを使用してください: https://code.google.com/p/marketbilling/source/detail?r=15946261ec9ae5f7c664d720f392f7787e3ee6c7この回答を投稿した時点で最新のバージョンです。SDK Manager からの最初のリリースと比較して、このバージョンでは多くの問題が修正されているようです。

このバージョンで変更しなければならなかったのはflagEndAsync();、2 つの IAB 購入フローが立て続けに開始されたときに発生する IllegalStateException を修正する 404 行の後に追加することだけです。

このバージョンでは、ファイル内での使用を管理する必要がなくflagEndAsync();、メソッドを公開しないままにしておくことができます。

于 2015-04-20T15:46:31.390 に答える