应用内结算无效:“IAB助手未设置”

我尝试在应用程序中包含应用程序内结算,并基于“TrivialDrive”示例中的应用程序内结算版本3的整个过程进行testing,并实现了未经修改的IAB文件版本“util”子目录),但它不适用于我 – 在LogCat上,就在应用程序终止并出现错误之前,它给出消息“应用程序内结算错误: 操作的非法状态(launchPurchaseFlow):IAB “(正好在startRegistered()函数被激发后,给我LOG消息”点击注册button,启动购买stream程升级“)…

任何想法在这里出了什么问题?

以下是我的代码的相关部分:

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) 

Solutions Collecting From Web of "应用内结算无效:“IAB助手未设置”"

执行purchaseFlow函数时遇到同样的问题。 看一下Google的例子中的Activity类,特别是在protected void onActivityResult(int requestCode, int resultCode, Intent data) 。 你可能忘了执行这个。 这个function对于整个机构无故障工作至关重要。

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

编辑:另外,当你有你的手机上的gmail帐户(今天发生在我身上)有错误的密码相关的问题也存在。 当然,所有的InApp账单function都应该在手机上进行testing,但我认为这是显而易见的。

根本的问题是直接响应UI用户单击调用startRegistered(),而IabHelper对象的设置是asynchronous触发的,所以不能被知道已经完成,直到通过onIabSetupFinished()接收到asynchronous响应。

您的startRegistered()方法由用户单击触发,并调用launchPurchaseFlow(),这又要求IabHelper对象已经完成设置,但是如果用户在收到确认之前点击触发购买(因为设置失败或者因为用户在抽奖上非常快),那么设置将不会完成,并且launchPurchaseFlow()将报告您所看到的错误。 在你的logcat的情况下,延迟是14秒,这通常是足够的时间,但是…也许不是在这种情况下。 或者,也许有什么地方出了问题,不pipe你等了多久,你都不会连接。

在你的logcat中,没有提示“账单服务已连接”,这是你的设置完成后首先要做的事情之一。 由于这种情况不会发生,您也不会从onIabSetupFinished()中看到任何消息(成功或失败)。

这是棘手的东西,因为需要asynchronous响应。 一种方法是禁用用于触发购买的button,直到onIabSetupFinished()成功返回。 这将阻止触发购买,直到IabHelper对象已成功设置。 当然,如果设置失败,你将会有一个无法正常运行的button,但是至less你可以告诉用户发生了什么事情(通过提示一个消息,表明你正在等待安装完成 – 例如,作为button文本)。

即使这样,一旦您开始购买并且付款对话框出现给用户,您的应用程序就有可能通过onStop()循环,在用户正在思考购买时从应用程序刷新应用程序(因为购买对话框是的Google Play,而不是你的应用程序的一部分,操作系统可能需要内存来运行它,而这个内存可以通过停止你的应用程序来获得)。 这将摧毁你的IabHelper()对象,然后将不得不创build并asynchronous设置。 再次,因为在onCreate()方法中asynchronous触发了这个方法,那么Google Play服务可能会调用onActivityResult()来在IabHelper对象设置完成之前报告用户的购买行为,因为在onActivityResult()要使用您的IabHelper实例,这可能会导致错误。 看来你必须为任何事情做好准备。

这应该给你你正在处理的味道。 IAB很难正是因为这些原因 – asynchronous的东西的multithreading(例如,设置与购买与Android操作系统的行动,停止您的应用程序抓取内存,很可能是用于您的应用程序的谷歌Play应用程序购买操作正在等待获得购买的结果)。 很多被实现的东西(包括TrivialDrive示例)是片状的,因为它隐含地依赖于你的应用程序停留在内存中,事实上它可能被回收,或者因为它依赖于竞争条件(例如设置)另一条腿(例如,购买发行),等等。

我刚刚完成了同样的问题。 IabHelper安装程序启动,但在此之后,没有其他事情发生。 而点击应用程序内购买返回你有完全相同的错误。

这是我想通了:我只使用eclipse的模拟器。 一旦我读到某个Google Play版本是必需的,我注意到Google Play在我的testing仿真驱动器上完全丢失了。

当我用一个真正的电话,它完美地工作! 所以如果你碰巧遇到这个问题,试着用一个真实的设备(如果你有一个可用的)。 这应该够了吧。

我遇到的另一件事 虽然您的设备上最新版本的Google Play可能支持最新版本的应用内结算,但其他用户可能不会。 虽然理论上由此造成的崩溃应该出现在开发者控制台中,但是直到我实现了Firebase之后,我才看到这些崩溃…然后我看到了很多这些崩溃。 我最终做的是使用try catch,并将没有Google Play最新版本或者在Google Play商店中遇到问题的用户链接到此页面https://support.google.com/googleplay/answer / 1050566?HL = EN

 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只是一个对话框,上面有一个链接到上面的网页。

但首先,我build议在几个朋友手机上进行应用程序购买testing,以确保它是游戏商店更新问题而不是代码问题。