Android In-App Billing v3: «Невозможно выполнить операцию: queryInventory»

У меня есть настройка In-App Billing в первый раз с использованием нового API v3. Он работает правильно на моих устройствах, но я получил множество отчетов об ошибках от других пользователей.

Один из них является:

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) 

И еще один:

 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 только внутри onIabSetupFinished , возможно ли, что mHelper имеет значение null или что mHelper не настроен?

Кто-нибудь знает решение этого?

Solutions Collecting From Web of "Android In-App Billing v3: «Невозможно выполнить операцию: queryInventory»"

Как пояснил @Martin, в примере Google In-App Billing произошла ошибка, вызвавшая это.

Однако после исправления я все еще получал некоторые ошибки во внутренних вызовах ( 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, например 🙂

Спасибо за все ваши комментарии.

В IABHelper есть ошибка. Линия возврата в обработчике исключений отсутствует, что означает, что она проваливается и вызывает успех hanlder – однако mSetupDone не был установлен, поэтому дальнейшие вызовы API не выполняются. Добавьте оператор возврата, как показано ниже: это будет по-прежнему не работать, но сообщение об ошибке будет сообщено вашему приложению, чтобы вы могли предпринять соответствующие действия.

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

Я считаю, что в коде Android все еще есть две ошибки, что объясняет, почему вы все еще видите ошибку. Обратите внимание, что стек вызовов находится в автономном потоке. Но код, который устанавливает mSetupDone (IabHelper) в true, выполняется в основном потоке пользовательского интерфейса. Java не гарантирует, что данные, измененные одним потоком, будут видны другому потоку из-за кэширования ЦП, если вы не объявите переменную с ключевым словом volatile. Таким образом, возможно, что он был настроен (mSetupDone == true), но новое значение mSetupDone кэшируется в потоке пользовательского интерфейса, еще не видимое этому потоку в вашем стеке вызовов. Таким образом, поток все еще видит mSetupDone == false.

Я попытался исправить это, объявив mSetupDone нестабильным, а также любое другое не конечное поле IabHelper, чтобы быть в безопасности.

Другая проблема – это функция .dispose (). Он не останавливает текущие потоки. Это означает, что он может установить mSetupDone в false, пока выполняется один из рабочих потоков. Если вы посмотрите на queryInventoryAsync (), вы увидите, что он проверяет, что mSetupDone является истинным. И, основываясь на вашем стеке вызовов, это прошло. Затем он разбился позже с mSetupDone == false. Только способ, который может произойти, – это вызывать dispose (), пока ваш поток находится в полете. Исправление состоит в том, что dispose () должен сигнализировать потоки, чтобы просто молча выручить, а не продолжать и бросать ошибки, когда видит mSetupDone == false. Это также предотвращает еще одну проблему с IabHelper, когда установленные экземпляры вызывают обратные вызовы прослушивателя даже после их удаления! Это немного сложно объяснить по строкам здесь, но мы надеемся, таким образом, заставим вас указать в правильном направлении.

Я выяснил! Речь идет о версии приложения Google Play Store от пользователя. Биллинг V3 для приложений требует 3,9.16 или выше ( http://developer.android.com/google/play/billing/versions.html ). Я использовал более старую версию, и я получил эту ошибку, теперь на 4.4.21 это нормально!

Убедитесь, что вы реализуете метод IabHelper.han.handleActivityResult(requestCode, resultCode, data) в ваших действиях onActivityResult методу 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."); } } 

Я получаю эту ТОЧНУЮ ту же ошибку с почти таким же кодом.

Кажется, что происходит только на некоторых телефонах (на самом деле это почти исключительно Acer Iconia Tablet в последних отчетах об ошибках!) – и я обрабатываю onActivityResult …

В Google V3 Billing Sample есть ряд ошибок, которые могут вызывать ANR / FC. Я подозреваю, что это просто еще один (дрянной код и дрянные документы становятся товарным знаком Google – к сожалению).

Мое предположение – на данный момент – нам нужно разрешить либо mHelper, либо mGotInventoryListener быть нулевым и просто отключить In-App Billing в этом случае (как если бы result.isSuccess () был ложным, в основном)

Ps, добавленный для добавления – возможно, только что пользователь имеет устаревшую версию Play Маркета – это только автообновление, если они позволяют ему работать !?

Вы можете быть в курсе разработки API inapp v3 на странице https://code.google.com/p/marketbilling/

Код там новее, чем тот, который доступен через Android SDK Manager.

В дополнение к @DavidM и @Ereza.

Еще одна серьезная проблема с классом IabHelpr – это плохой выбор метаданных RuntimeExcptions (IllegalStateException) несколькими способами. Бросание RuntimeExceptions из вашего собственного кода в большинстве случаев нежелательно из-за того, что они являются неконтролируемыми исключениями . Это похоже на саботаж вашего собственного приложения – если его не поймать, эти исключения будут пузыриться и разбивать ваше приложение.

Решением этого является реализация собственного проверенного исключения и изменение класса IabHelper для его броска вместо исключения IllegalStateException. Это заставит вас справиться с этим исключением везде, где оно может быть выброшено в ваш код во время компиляции.

Вот мое обычное исключение:

 public class MyIllegalStateException extends Exception { private static final long serialVersionUID = 1L; //Parameterless Constructor public MyIllegalStateException() {} //Constructor that accepts a message public MyIllegalStateException(String message) { super(message); } } 

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

 try { setUpBilling(targetActivityInstance.allData.getAll()); } catch (MyIllegalStateException ex) { ex.printStackTrace(); } 

Если все вышеперечисленное не поможет вам, попробуйте немного проанализировать свой код – действительно ли ваш 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 helper is not setup», так как пока ваше приложение пытается выполнить m_iabHelper.queryInventoryAsync() , IabHelper еще не настроен. Рассмотрите возможность использования этих функций в onIabSetupFinished() или где-нибудь после onIabSetupFinished() этой функции (например, вне onCreate() )

Я получаю те же ошибки. Я также столкнулся с другими проблемами …

Имея несколько учетных записей google на устройстве, отключенное в приложении для биллинга на моем вкладке Galaxy 7. Удалите одну учетную запись повторно включив ее.

Я видел проблемы с примером кода биллинга приложений на GT-P5110, LGL75C и GT-S5839i и другие.

(Я использую код в приложении с установленным ACRA … поэтому каждый раз он падает, я получаю информацию)

Устройства Android версии от 2.3.3 до 4.0.4.

Это очень раздражает.

Было много проблем с IABHelper.java.

Во-первых – версия, загружаемая диспетчером SDK, не обновляется. Используйте версию, найденную здесь: https://code.google.com/p/marketbilling/source/detail?r=15946261ec9ae5f7c664d720f392f7787e3ee6c7. Это самая актуальная версия для публикации этого ответа. Многие проблемы, похоже, были исправлены с этой версией по сравнению с первоначальной версией, которая поступает из SDK Manager.

Единственное, что мне пришлось изменить в этой версии, – добавить flagEndAsync(); После строки 404, которая исправляет исключение IllegalStateException, когда две быстрые покупки IAB запускаются быстро.

С этой версией вам не нужно управлять использованием flagEndAsync(); В ваших файлах и может оставить этот метод недоступным.