Биллинг в приложении не работает: «IAB Helper не настроен»

Я попытался включить биллинг в приложении в приложение и для тестирования на основе всей процедуры на примере «TrivialDrive» для версии 3 биллинга в приложении (и реализации немодифицированных версий IAB-файлов, как указано в «Util» в демо-версии), но он не работает для меня – на LogCat, перед тем как приложение завершит с ошибкой, оно выдает сообщение «Ошибка биллинга в приложении: Незаконное состояние для работы (launchPurchaseFlow): IAB Помощник не настроен. »(Сразу после запуска функция« Зарегистр. () Была уволена, и мне было отправлено сообщение «Регистрация нажата кнопка« Регистрация », запуск потока покупок для обновления.) …

Любая идея, что здесь не так?

Вот соответствующие части моего кода:

package com.mytest; (..) import com.mytest.iab.IabHelper; // the originals from the demo example, unmodified import com.mytest.iab.IabResult; import com.mytest.iab.Inventory; import com.mytest.iab.Purchase; public class Result3 extends Activity implements OnClickListener { private static final String TAG = "BillingService"; private Context mContext; boolean mIsRegistered = false; // this has already been set up for my app at the publisher's console static final String IS_REGISTERED = "myregistered"; static final int RC_REQUEST = 10001; // The helper object IabHelper mHelper; /** Call when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.result3); mContext = this; String base64EncodedPublicKey = "[my public key]"; // (from publisher's console for my app) // Create the helper, passing it our context and the public key to verify signatures with Log.d(TAG, "Creating IAB helper."); mHelper = new IabHelper(this, base64EncodedPublicKey); // enable debug logging (for a production application, you should set this to false). mHelper.enableDebugLogging(true); // Start setup. This is asynchronous and the specified listener // will be called once setup completes. Log.d(TAG, "Starting setup."); mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() { public void onIabSetupFinished(IabResult result) { Log.d(TAG, "Setup finished."); if (!result.isSuccess()) { complain("Problem setting up in-app billing: " + result); return; } // Hooray, IAB is fully set up. Now, let's get an inventory of stuff we own. Log.d(TAG, "Setup successful. Querying inventory."); mHelper.queryInventoryAsync(mGotInventoryListener); } }); // Set the onClick listeners findViewById(R.id.btnPurchase).setOnClickListener(this); } // 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) { Log.d(TAG, "Query inventory finished."); if (result.isFailure()) { complain("Failed to query inventory: " + result); return; } Log.d(TAG, "Query inventory was successful."); // Do we have the premium upgrade? mIsRegistered = inventory.hasPurchase(IS_REGISTERED); Log.d(TAG, "User is " + (mIsRegistered ? "REGISTERED" : "NOT REGISTERED")); setWaitScreen(false); Log.d(TAG, "Initial inventory query finished; enabling main UI."); } }; // User clicked the "Register" button. private void startRegistered() { Log.d(TAG, "Register button clicked; launching purchase flow for upgrade."); setWaitScreen(true); mHelper.launchPurchaseFlow(this, IS_REGISTERED, RC_REQUEST, mPurchaseFinishedListener); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data); // Pass on the activity result to the helper for handling if (!mHelper.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."); } } // Callback for when a purchase is finished IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() { public void onIabPurchaseFinished(IabResult result, Purchase purchase) { Log.d(TAG, "Purchase finished: " + result + ", purchase: " + purchase); if (result.isFailure()) { // Oh noes! complain("Error purchasing: " + result); setWaitScreen(false); return; } Log.d(TAG, "Purchase successful."); if (purchase.getSku().equals(IS_REGISTERED)) { Log.d(TAG, "User has registered.."); alert("Thank you."); mIsRegistered = true; setWaitScreen(false); } } }; // We're being destroyed. It's important to dispose of the helper here! @Override public void onDestroy() { // very important: Log.d(TAG, "Destroying helper."); if (mHelper != null) mHelper.dispose(); mHelper = null; } void complain(String message) { Log.e(TAG, "**** Register Error: " + message); alert("Error: " + message); } void setWaitScreen(boolean set) { // just a dummy for now } void alert(String message) { AlertDialog.Builder bld = new AlertDialog.Builder(this); bld.setMessage(message); bld.setNeutralButton("OK", null); Log.d(TAG, "Showing alert dialog: " + message); bld.create().show(); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btnPurchase: startRegistered(); break; default: break; } } 

}

Здесь больше строк из Logcat:

 12-20 01:06:36.701: D/dalvikvm(299): GC_FOR_MALLOC freed 4262 objects / 308592 bytes in 84ms 12-20 01:06:36.701: D/webviewglue(299): nativeDestroy view: 0x2ea718 12-20 01:06:36.771: W/webcore(299): Can't get the viewWidth after the first layout 12-20 01:07:07.111: W/webcore(299): Can't get the viewWidth after the first layout 12-20 01:07:18.510: D/webviewglue(299): nativeDestroy view: 0x2dd458 12-20 01:07:18.510: D/dalvikvm(299): GC_FOR_MALLOC freed 6042 objects / 544504 bytes in 50ms 12-20 01:07:18.530: D/webviewglue(299): nativeDestroy view: 0x2ea8d0 12-20 01:07:18.660: D/BillingService(299): Creating IAB helper. 12-20 01:07:18.660: D/BillingService(299): Starting setup. 12-20 01:07:18.660: D/IabHelper(299): Starting in-app billing setup. 12-20 01:07:19.621: W/webcore(299): Can't get the viewWidth after the first layout 12-20 01:07:20.160: W/webcore(299): Can't get the viewWidth after the first layout 12-20 01:07:32.481: D/webviewglue(299): nativeDestroy view: 0x3f88e8 12-20 01:07:32.491: D/dalvikvm(299): GC_FOR_MALLOC freed 5798 objects / 513640 bytes in 50ms 12-20 01:07:32.511: D/BillingService(299): Register button clicked; launching purchase flow for upgrade. 12-20 01:07:32.511: E/IabHelper(299): In-app billing error: Illegal state for operation (launchPurchaseFlow): IAB helper is not set up. 12-20 01:07:32.521: D/AndroidRuntime(299): Shutting down VM 12-20 01:07:32.521: W/dalvikvm(299): threadid=1: thread exiting with uncaught exception (group=0x4001d800) 12-20 01:07:32.541: E/AndroidRuntime(299): FATAL EXCEPTION: main 12-20 01:07:32.541: E/AndroidRuntime(299): java.lang.IllegalStateException: IAB helper is not set up. Can't perform operation: launchPurchaseFlow 12-20 01:07:32.541: E/AndroidRuntime(299): at com.test_ed.iab.IabHelper.checkSetupDone(IabHelper.java:673) 12-20 01:07:32.541: E/AndroidRuntime(299): at com.test_ed.iab.IabHelper.launchPurchaseFlow(IabHelper.java:315) 12-20 01:07:32.541: E/AndroidRuntime(299): at com.test_ed.iab.IabHelper.launchPurchaseFlow(IabHelper.java:294) 12-20 01:07:32.541: E/AndroidRuntime(299): at com.test_ed.Result3.startRegistered(Result3.java:157) 12-20 01:07:32.541: E/AndroidRuntime(299): at com.test_ed.Result3.onClick(Result3.java:248) 12-20 01:07:32.541: E/AndroidRuntime(299): at android.view.View.performClick(View.java:2408) 12-20 01:07:32.541: E/AndroidRuntime(299): at android.view.View$PerformClick.run(View.java:8816) 12-20 01:07:32.541: E/AndroidRuntime(299): at android.os.Handler.handleCallback(Handler.java:587) 12-20 01:07:32.541: E/AndroidRuntime(299): at android.os.Handler.dispatchMessage(Handler.java:92) 12-20 01:07:32.541: E/AndroidRuntime(299): at android.os.Looper.loop(Looper.java:123) 12-20 01:07:32.541: E/AndroidRuntime(299): at android.app.ActivityThread.main(ActivityThread.java:4627) 12-20 01:07:32.541: E/AndroidRuntime(299): at java.lang.reflect.Method.invokeNative(Native Method) 12-20 01:07:32.541: E/AndroidRuntime(299): at java.lang.reflect.Method.invoke(Method.java:521) 12-20 01:07:32.541: E/AndroidRuntime(299): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868) 12-20 01:07:32.541: E/AndroidRuntime(299): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626) 12-20 01:07:32.541: E/AndroidRuntime(299): at dalvik.system.NativeStart.main(Native Method) 

Имел ту же проблему при выполнении функции покупкиFlow. Взгляните на класс Activity в примере Google и, в частности, на метод protected void onActivityResult(int requestCode, int resultCode, Intent data) . Вероятно, вы забыли реализовать это. Эта функция жизненно необходима для того, чтобы весь механизм работал без сбоев.

 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { Log.i(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data); // Pass on the activity result to the helper for handling if (!inappBillingHelper.handleActivityResult(requestCode, resultCode, data)) { super.onActivityResult(requestCode, resultCode, data); } else { Log.i(TAG, "onActivityResult handled by IABUtil."); } } 

EDIT: Кроме того, проблема также возникает, если у вас неправильный пароль, связанный с вашей учетной записью gmail на вашем телефоне (это случилось сегодня со мной). Конечно, все функции биллинга Inapp должны быть протестированы на телефоне, но я думаю, что это очевидно.

Основная проблема заключается в том, что startRegistered () вызывается в прямом ответе на клик пользователя пользовательского интерфейса, тогда как установка вашего объекта IabHelper запускается асинхронно и поэтому не может быть известно, что он был завершен до получения асинхронного ответа через onIabSetupFinished ().

Ваш метод startRegistered () запускается щелчком пользователя и вызывает вызовы launchPurchaseFlow (), которые, в свою очередь, требуют, чтобы объект IabHelper уже завершил настройку, но если пользователь нажимает кнопку для запуска покупки до получения этого подтверждения (либо из-за установки Не удалось или потому, что пользователь исключительно быстро выполнил ничью), то настройка не будет завершена, а launchPurchaseFlow () сообщит об ошибке, которую вы видите. В случае вашего логарифма задержка составляет 14 секунд, что обычно будет достаточно времени, но … возможно, не в этом случае. Или, может, что-то пошло не так, и вы никогда бы не подключились независимо от того, как долго вы ждали.

В вашем логарифме нет сообщения с сообщением «Служба биллинга подключена», что является одной из первых вещей, которые должны произойти, если ваша установка будет завершена. Так как это не происходит, вы также не видите сообщения (либо успеха, либо отказа) от onIabSetupFinished ().

Это сложный материал из-за требуемых асинхронных ответов. Один из подходов – отключить кнопку, используемую для запуска покупки, до тех пор, пока ваш onIabSetupFinished () не вернется с успехом. Это предотвратит запуск покупки до тех пор, пока объект IabHelper не будет успешно настроен. Конечно, если установка завершится неудачно, у вас будет неработающая кнопка, но, по крайней мере, вы можете сообщить пользователю, что происходит (путем размещения сообщения, которое указывает, что вы ожидаете завершения установки), например, как часть Текст кнопки).

Даже тогда, как только ваша покупка будет инициирована, и появится диалоговое окно оплаты, вы сможете использовать приложение через цикл onStop (), который сбрасывает ваше приложение из памяти, когда пользователь размышляет о ее покупке (поскольку диалог покупки является частью Google Play, а не часть вашего приложения, и для ОС может потребоваться память для ее работы, и эта память может быть получена путем остановки вашего приложения). Это уничтожит ваш объект IabHelper (), который затем должен быть создан и асинхронно настроен снова . И снова, поскольку это вызвано асинхронно в вашем методе onCreate (), функция onActivityResult () может быть вызвана службой Google Play, чтобы сообщить о действии покупки пользователя до завершения настройки объекта IabHelper, а так как в onActivityResult () вам понадобится Для использования экземпляра IabHelper это может привести к ошибке. Кажется, вы должны быть готовы ко всему.

Это должно дать вам вкус того, с чем вы имеете дело. IAB трудно по этим причинам – несколько потоков асинхронных вещей (например, установка против покупок против действий ОС Android, которые останавливают ваше приложение для захвата памяти для использования, вполне возможно, самой операцией покупки приложения в Google Play, для которой ваше приложение Ждет получения результатов покупки). Многое из того, что реализуется (в том числе по образцу TrivialDrive), является шелушащимся, потому что оно неявно полагается на ваше приложение, остающееся в памяти, когда на самом деле оно может быть переработано или потому, что оно зависит от одного этапа состояния гонки (например, установки) Другая нога (например, покупка), и т. Д.

Я только что закончил обворачивать ту же проблему. IabHelper-Setup запускается, но после этого больше ничего не происходит. И нажатие на приложение-Purchase возвращает ту же самую ошибку, что и у вас.

Вот что я понял: я использовал эмуляторы только из затмения. Как только я прочитал, что требуется определенная версия Google Play, я заметил, что Google Play полностью отсутствует на моих тестовых эмуляционных дисках.

Когда я использовал реальный телефон, он работал безупречно! Поэтому, если вы все еще застряли в этой проблеме, попробуйте использовать реальное устройство (если у вас есть один доступный). Это должно делать свое дело.

Еще одна вещь, с которой я столкнулся; В то время как у вас может быть последняя версия игры Google на вашем устройстве, которая поддерживает самую последнюю версию биллинга приложений, другие пользователи могут этого не делать. И в то время как сбои, вызванные этим теоретически, должны появиться в консоли разработчика, я не мог видеть эти сбои, пока я не реализовал firebase …, а затем я увидел их много. То, что я закончил, это использовать попытку catch и привязать пользователей, у которых не было последней версии игры Google, или возникла проблема в конце игрового магазина google на этой странице https://support.google.com/googleplay/answer / 1050566? гл = еп

 try { mHelper.launchPurchaseFlow(this, SKU_PRO_LT, RC_REQUEST, mPurchaseFinishedListener, payload); } catch (Exception e) { //with IabHelper.IabAsyncInProgressException the code still fatally crashes for some reason //complain("Error launching purchase flow. Another async operation in progress."); alert2("[error msg]"); setWaitScreen(false); } 

Alert2 – это просто диалоговое окно со ссылкой на веб-страницу выше.

Но, во-первых, я бы рекомендовал тестировать покупки приложений на нескольких телефонах друзей, чтобы убедиться, что это проблема обновления магазина, а не проблема с кодом.