Я внедряю In App Billing в первый раз, и я тестирую свои первые покупки, используя статические идентификаторы SKU.
Он работал очень хорошо в первый раз. Я позвонил mHelper.launchPurchaseFlow(...)
и завершил пробную покупку. Моя активность получила onActivityResult
вызов 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
мой OnIabPurchaseFinishedListener
и я вижу, что в моем журнале ошибка покупки: «Ошибка биллинга в приложении: невозможно купить элемент, ответ об ошибке: 7: элемент уже принадлежит»
Это имеет смысл, но если я попытаюсь купить другой элемент, то мое приложение выйдет со следующей ошибкой:
Java.lang.IllegalStateException: не удается запустить асинхронную операцию (launchPurchaseFlow), поскольку выполняется другая операция async (launchPurchaseFlow).
onActivityResult
вызов onActivityResult
не возникает, когда я пытаюсь выполнить покупку, которая терпит неудачу, поэтому сбой при запуске не обрабатывается и не очищается. Поэтому, когда я пробую другую покупку, вот почему она терпит крах, потому что она все еще предположительно находится в середине последней неудавшейся транзакции.
Что я делаю не так? Как я могу убедиться, что startPurchaseFlow () очищен после сбоя?
Я считаю, что вам просто нужно получить обновленный код в классах биллинга в приложении, и вам не следует снова запускать ту же проблему.
Насколько я знаю, 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
Я знаю, что это довольно поздний вклад в этот вопрос, но сегодня я столкнулся с одной и той же проблемой, и я звонил в биллинг приложений внутри фрагмента, поэтому я посмотрел в «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); }
Надеюсь, это поможет кому-то …
Для меня лучше всего было исправить код с последним ( здесь ) и сделать то, что предлагает этот пост :
1) сделать метод
flagEndAsync
общедоступным. Он есть, просто не видно.2) у каждого слушателя вызов
iabHelper.flagEndAsync
чтобы убедиться, что процедура отмечена правильно законченной; Это кажется необходимым во всех слушателях.3)
IllegalStateException
вызовы с помощьюtry/catch
чтобы пойматьIllegalStateException
которое может произойти, и обрабатывать его таким образом.
Причина, по которой обновление кода была недостаточной, заключается в том, что я обнаружил особые случаи, когда эта ошибка все еще встречается (или хотя бы одна):
IabHelper
; У меня такая же проблема.
Я загрузил текущую версию IabHelper.java в соответствии с решением jmrmb80 , но это не сработало. (Кажется, что репо теперь устарело, и мы должны полагаться на версию, предоставленную менеджером Android SDK.) Поэтому я последовал совету Хана :
iabHelper.flagEndAsync()
перед iabHelper.launchPurchaseFlow(...)
Это похоже на вопиющий взлом! И это может иметь нежелательные побочные эффекты. Но он «работает» …
Это, похоже, известная ошибка: # 134 и # 189 .
После дальнейшего расследования, я не думаю, что описанное выше решение помогло решить мою проблему. Я думаю, что реальное решение – переопределить onActivityResult
в потоке пользовательского интерфейса.
Error response: 7:Item Already Owned
означает, что вы купили товар, но вы его еще не потребляли, и вы пытаетесь его снова купить.
Это случилось со мной, когда я установил в AndroidManifest launchMode в своей активности в приложении для singleInstance
. Приложение всегда заканчивается ошибкой, которую вы описали.
Чтобы избежать такого поведения, измените ваш startMode на любое другое значение, соответствующее вашим потребностям android:launchMode="singleInstance"
-> android:launchMode="singleTask"
Я не пытался понять, почему singleInstance не работает. Если кто-то знает, пожалуйста, предоставьте дополнительную информацию.
Поэтому я решил изменить changeMode и использовать уже принадлежащий ему товар. С тех пор IAP отлично работает для меня.
Нет необходимости в хакерских решениях. Действие или фрагмент, запрашивающий поток покупки, должен иметь следующее:
@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, попробовал его в моем проекте, и он работает.