Android в биллинге приложений: не удается запустить launchPurchaseFlow, так как выполняется launchPurchaseFlow

Я впервые использую In App Billing и тестирую свои первые покупки, используя статические идентификаторы SKU.

Это сработало очень хорошо с первого раза. я звонил 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");

Во второй раз я пытаюсь приобрести товар, мой OnIabPurchaseFinishedListener называется и я вижу purchase failed в моем журнале: "Ошибка биллинга в приложении: невозможно купить товар, ответ об ошибке: 7: Товар уже принадлежит"

Это имеет смысл, но если я пытаюсь купить другой предмет, мое приложение вылетает со следующей ошибкой:

java.lang.IllegalStateException: Невозможно запустить асинхронную операцию (launchPurchaseFlow), потому что выполняется другая асинхронная операция (launchPurchaseFlow).

onActivityResult обратный вызов не происходит, когда я пытаюсь совершить неудачную покупку, поэтому неудачный процесс запуска не обрабатывается и не очищается. Поэтому, когда я пытаюсь сделать еще одну покупку, именно поэтому она падает, потому что она все еще находится в середине последней неудачной транзакции.

Что я делаю неправильно? Как убедиться, что launchPurchaseFlow() очищен после сбоя?

6 ответов

Решение

Я полагаю, что вам просто нужно получить обновленный код классов биллинга в приложении, и вам больше не придется сталкиваться с той же проблемой.

Насколько я знаю, Google еще не внес изменения в SDK Manager. Просто скопируйте / вставьте новые классы в свой, и вы больше не столкнетесь с проблемой.

Ознакомьтесь с новыми изменениями кода здесь: https://code.google.com/p/marketbilling/source/detail?r=7ec85a9b619fc5f85023bc8125e7e6b1ab4dd69f&path=/v3/src/com/example/android/trivialdrivesample/MainActivity.java

Классы, которые были изменены по состоянию на 15 марта: IABHelper.java, Inventory.java, SkuDetails.java и некоторые из файла MainActivity.java

Я знаю, что это своего рода поздний вклад в этот вопрос, но я столкнулся с той же проблемой сегодня, и я вызывал биллинг в приложении внутри фрагмента, поэтому я посмотрел в "labHelper.java" и увидел прямое решение, которое, как мне кажется, проблема в том, что... я изменил метод "void flagStartAsync(String operation)" в labHelper.java, чтобы он был похож на следующий

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

Я надеюсь, что это поможет кому-то там...

Для меня лучшим решением было обновить код до последнего ( здесь) и сделать то, что предлагает этот пост:

1) сделать метод flagEndAsync общественности. Это там, просто не видно.

2) иметь каждый вызов слушателя iabHelper.flagEndAsync убедиться, что процедура помечена как завершенная правильно; Кажется, это нужно всем слушателям.

3) объемные звонки с try/catch поймать IllegalStateException что может произойти, и справиться с этим таким образом.

Причина, по которой обновление кода было недостаточно, заключается в том, что я обнаружил особые случаи, когда эта ошибка все еще возникает (или хотя бы одна):

  • отключиться от интернета;
  • введите ваше приложение;
  • пусть он инициализирует IabHelper;
  • подключиться к Интернету;
  • После подключения устройства попробуйте совершить покупку.

У меня та же проблема.

Первая попытка: обходной путь

Я скачал текущий IabHelper.java, согласно решению jmrmb80, но это не сработало. (Похоже, что сейчас репо устарело, и мы должны полагаться на версию, предоставленную менеджером Android SDK.) Поэтому я последовал совету Хана:

  • определить IabHelper.flagEndAsync() как открытый и
  • добавлять iabHelper.flagEndAsync() до iabHelper.launchPurchaseFlow(...)

Это похоже на наглый хак! И это может иметь нежелательные побочные эффекты. Но это "работает"...

Это, кажется, известная ошибка: # 134 и # 189.

Вторая попытка: исправить

После дальнейшего изучения, я не думаю, что вышеупомянутый обходной путь решил мою проблему. Я думаю, что реальным решением является переопределение onActivityResult в потоке пользовательского интерфейса.

Нет необходимости в хакерских решениях. Активность или фрагмент, запрашивающий поток покупки, должен иметь следующее:

@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, попробовал его на моем проекте, и он работает.

Error response: 7:Item Already Owned означает, что вы купили товар, но еще не потребляли его и пытаетесь купить его снова.

Это случилось со мной, когда я установил в AndroidManifest launchMode в моей активности в приложении к singleInstance, Приложение всегда завершается с ошибкой, которую вы описали.

Чтобы избежать такого поведения, измените launchMode на любое другое значение, которое соответствует вашим потребностямandroid:launchMode="singleInstance" -> android:launchMode="singleTask"

Я не пытался глубоко понять, почему SingleInstance не работает. Если кто-то знает, пожалуйста, предоставьте больше информации.

Поэтому я решил изменить launchMode и использовать уже принадлежащий объект. С тех пор IAP отлично работает для меня.

Другие вопросы по тегам