Android In App Billing: невозможно запустить launchPurchaseFlow, так как выполняется запускPurchaseFlow

Я внедряю 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 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 не происходит, когда я пытаюсь выполнить покупку, которая терпит неудачу, поэтому сбой при запуске не обрабатывается и не очищается. Поэтому, когда я пытаюсь выполнить другую покупку, это происходит потому, что она все еще предположительно находится в середине последней неудавшейся транзакции.

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

Ответ 1

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

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

Посмотрите на новые изменения кода здесь: 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

Ответ 2

Я знаю, что это довольно поздний вклад в вопрос, но сегодня я столкнулся с одной и той же проблемой, и я звонил в биллинг приложений внутри фрагмента, поэтому я посмотрел в "labHelper.java", и я увидел прямое решение Я верю в проблему, которая... Я изменил метод "void flagStartAsync (Строковая операция)" в 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);
}

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

Ответ 3

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

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

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

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

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

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

Ответ 4

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

Первая попытка: Временное решение

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

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

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

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

Вторая попытка: Fix

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

Ответ 5

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

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

Ответ 6

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

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

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

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

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