web-dev-qa-db-ja.com

Android In App Billing:launchPurchaseFlowが進行中のため、launchPurchaseFlowを開始できません

In App Billingを初めて実装し、静的SKU IDを使用して最初の購入をテストしています。

初めてうまくいきました。 mHelper.launchPurchaseFlow(...)を呼び出して、テスト購入を完了しました。私のアクティビティはonActivityResultコールバックを受け取り、mHelper.handleActivityResult(...)で処理するようにしました。すべてが素晴らしかった。

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // Pass on the activity result to the helper for handling
    log("onActivityResult");
    if (!this.mHelper.handleActivityResult(requestCode, resultCode, data)) {
        log("cleared the launch flow");
        // 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);
    }
}

ただし、次の部分をテストしたかったため、アプリを再起動し、同じSKU(静的purchased SKU)を購入しようとしました。

mHelper.launchPurchaseFlow(rootActivity, "Android.test.purchased", 10002,   
       new IabHelper.OnIabPurchaseFinishedListener() {

        @Override
        public void onIabPurchaseFinished(IabResult result, Purchase purchaseInfo) {
            if (result.isFailure()) {
                log("purchased failed");
            } else {
                log("purchase succeeded");
            }
        }
    }, "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");

2回目に商品を購入しようとすると、OnIabPurchaseFinishedListenerが呼び出され、purchase failedログ内:「アプリ内課金エラー:アイテムを購入できません、エラー応答:7:アイテムは既に所有しています」

それは理にかなっていますが、別のアイテムを購入しようとすると、アプリが次のエラーでクラッシュします。

Java.lang.IllegalStateException:別の非同期操作(launchPurchaseFlow)が進行中のため、非同期操作(launchPurchaseFlow)を開始できません。

onActivityResultコールバックは、失敗した購入を行おうとすると発生しないため、失敗した起動フローは処理されず、クリーンアップされません。そのため、別の購入を試みると、最後に失敗したトランザクションの途中にあると思われるため、クラッシュします。

私は何を間違えていますか?失敗後にlaunchPurchaseFlow()がクリーンアップされるようにするにはどうすればよいですか?

36
Kenny Wyland

アプリ内課金クラスの更新されたコードを取得する必要があるだけで、同じ問題に再び直面することはないはずです。

Googleは、私が知る限り、SDKマネージャーへの変更をまだプッシュしていません。新しいクラスを自分のクラスにコピーして貼り付けるだけで、問題が発生することはなくなります。

ここで新しいコードの変更をご覧ください: https://code.google.com/p/marketbilling/source/detail?r=7ec85a9b619fc5f85023bc8125e7e6b1ab4dd69f&path=/v3/src/com/example/Android/trivialdrivesample/MainActivity .Java

3月15日の時点で変更されたクラスは次のとおりです。IABHelper.Java、Inventory.Java、SkuDetails.Java、およびMainActivity.Javaファイルの一部

43
joelreeves

私はそれが質問に少し遅れて貢献していることを知っていますが、今日同じ問題に直面していて、フラグメント内のアプリ課金を呼び出していたので、「labHelper.Java」を見て、私が信じる直接的な解決策を見ました問題は... labHelper.Javaのメソッド「void flagStartAsync(String operation)」を次のように変更しました

void flagStartAsync(String operation) {
    if (mAsyncInProgress) {
        flagEndAsync();
    }
    if (mAsyncInProgress) throw new IllegalStateException("Can't start async operation (" +
            operation + ") because another async operation(" + mAsyncOperation + ") is in progress.");
    mAsyncOperation = operation;
    mAsyncInProgress = true;
    logDebug("Starting async operation: " + operation);
}

私はこれがそこに誰かを助けることを願っています...

29
alazmi95

私にとって最良の解決策は、コードを最新のものに更新することです( here )、そして何をするか- この投稿 提案:

1)メソッドflagEndAsyncをパブリックにします。そこにあり、見えないだけです。

2)すべてのリスナーがiabHelper.flagEndAsyncを呼び出して、プロシージャが適切に終了とマークされていることを確認します。すべてのリスナーで必要なようです。

3)呼び出しをtry/catchで囲んで、発生する可能性のあるIllegalStateExceptionをキャッチし、そのように処理します。

コードの更新が十分ではなかった理由は、このバグがまだ発生する(または少なくとも1つの)特別なケースを見つけたからです。

  • インターネットから切断します。
  • アプリを入力してください。
  • IabHelperを初期化しましょう。
  • インターネットに接続します。
  • デバイスが接続されたら、購入を試みます。
10

私は同じ問題を抱えています。

最初の試行:回避策

jmrmb80のソリューション に従って、現在の IabHelper.Java をダウンロードしましたが、うまくいきませんでした。 (レポジトリは現在 非推奨 であり、Android SDKマネージャー)が提供するバージョンに依存する必要があるようです。)私は カーンのアドバイス =:

  • iabHelper.flagEndAsync()をパブリックとして定義し、
  • iabHelper.flagEndAsync()の前にiabHelper.launchPurchaseFlow(...)を追加します

これは露骨なハックのようです!そして、それは望ましくない副作用があるかもしれません。しかし、それは「働きます」...

これは既知のバグのようです: #134 および #189

2回目の試行:修正

さらに調査した結果、上記の回避策で問題が解決したとは思いません。 実際のソリューション は、UIスレッドでonActivityResultをオーバーライドすることだと思います。

8
user2768

ハッキングソリューションは必要ありません。購入フローをリクエストしているアクティビティまたはフラグメントには次のものが必要です。

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);
    if (billingHelper == null) return;

    // Pass on the activity result to the helper for handling
    if (!billingHelper.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.d(TAG, "onActivityResult handled by IABUtil.");
    }
}

これはGoogleのサンプルプロジェクトのもので、私のプロジェクトで試してみたところ、うまくいきました。

2
RominaV

Error response: 7:Item Already Ownedは、アイテムを購入したがまだ消費していないため、もう一度購入しようとしたことを意味します。

これは、singleInstanceへのアプリ内アシビティでAndroidManifest launchModeを設定したときに起こりました。アプリは常にあなたが説明したエラーで終了しました。

この動作を回避するには、launchModeをニーズに合った他の値に変更しますAndroid:launchMode="singleInstance"-> Android:launchMode="singleTask"

SingleInstanceが機能しない理由を深く理解しようとしませんでした。誰かが知っているなら、もっと情報を提供してください。

したがって、私の解決策は、launchModeを変更し、既に所有しているアイテムを消費することでした。その時以来、IAPは私にとってはうまく機能しています。

0
Honza Musil