应用内结算不起作用:“IAB Helper未设置”

我试图在我的应用程序中包含应用程序内结算,并且为了测试目的,基于应用程序计费版本3的“TrivialDrive”示例的整个过程(并实现IAB文件中提供的未修改版本的IAB文件)演示文稿的“util”子目录),但它对我不起作用 – 在LogCat上,就在应用程序因错误而终止之前,它会显示消息“应用程序内计费错误: 操作非法状态(launchPurchaseFlow):IAB Helper未设置。 “(在startRegistered()函数被触发后,给我LOG消息”点击注册按钮;启动购买流程进行升级。“)…

知道这里出了什么问题吗?

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

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 Helper未设置”"

执行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都应该在手机上进行测试,但我认为很明显。

基本问题是,在直接响应UI用户单击时调用startRegistered(),而异步触发IabHelper对象的设置,因此在通过onIabSetupFinished()接收到异步响应之前,不能知道它已完成。

您的startRegistered()方法由用户单击触发,并且调用launchPurchaseFlow(),这反过来要求IabHelper对象已经完成设置,但是如果用户在收到确认之前单击以触发购买(因为设置失败或因为用户在绘图时非常快,然后安装将不会完成,并且launchPurchaseFlow()将报告您看到的错误。 对于你的logcat,延迟是14秒,这通常是足够的时间,但……在这种情况下可能不是。 或者,也许出了点问题,无论你等多久,你都无法连接。

在您的logcat中,没有消息指示“已连接结算服务”,这是您要完成设置时必须首先发生的事情之一。 由于没有发生这种情况,您也无法从onIabSetupFinished()中看到任何消息(成功或失败)。

由于需要异步响应,这很棘手。 一种方法是禁用用于触发购买的按钮,直到onIabSetupFinished()成功返回。 这将阻止在成功设置IabHelper对象之前触发购买。 当然,如果设置失败,你将有一个无法正常工作的按钮,但至少你可以告诉用户怎么了正常的(通过发出一条消息,表明你正在等待设置完成 – 例如,作为一部分按钮文字)。

即使这样,一旦您的购买开始并且用户看到付款对话框,您的应用程序可能会通过onStop()循环,在用户考虑购买时从内存中刷新您的应用程序(因为购买对话框是一部分)谷歌播放,不是你的应用程序的一部分,操作系统可能需要内存来运行它,并可以通过停止你的应用程序获得该内存)。 这会破坏你的IabHelper()对象,然后必须再次创建和异步设置它。 同样,由于在onCreate()方法中异步触发,因此在IabHelper对象的设置完成之前 ,Google Play服务可以调用onActivityResult()来报告用户的购买操作,因为在onActivityResult()中,您需要要使用您的IabHelper实例,这可能会导致错误。 看来你必须为任何事情做好准备。

这应该会给你你正在处理的东西的味道。 IAB很难正是出于这些原因 – 异步内容的多个线程(例如,设置与购买相比,Android操作系统操作会阻止您的应用获取内存,很可能是您的应用的Google Play应用购买操作正在等待获得购买的结果)。 许多实现的内容(包括TrivialDrive示例)都是片状的,因为它隐含地依赖于您的应用程序保留在内存中,实际上它可能会被回收,或者因为它依赖于竞争条件的一条腿(例如设置)之前完成另一条腿(例如,购买发射)确实如此,等等。

我刚刚完成了围绕完全相同的问题。 IabHelper-Setup启动,但之后,没有其他任何事情发生。 点击应用内购买会返回完全相同的错误。

这就是我想到的:我只使用了eclipse中的模拟器。 一旦我读到需要某个Google Play版本,我就会注意到Google Play完全缺少我的测试仿真驱动器。

当我使用真正的手机时,它完美无缺! 因此,如果您碰巧仍然坚持这个问题,请尝试使用真实设备(如果您有一个可用设备)。 这应该够了吧。

我遇到的另一件事; 虽然您可能在您的设备上安装了最新版本的Google Play,该版本支持最新版本的应用内结算,但其他用户可能不会。 虽然理论上由此引起的崩溃应该出现在开发者控制台中,但在我实现firebase之前我看不到这些崩溃……然后我看到了很多这些崩溃。 我最终做的是使用try catch并链接没有最新版Google Play的用户或在google play store端遇到此问题的用户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只是一个对话框,其中包含指向上述网页的链接。

但首先我建议在几款朋友的手机上测试应用,以确保它是一个Play商店更新问题,而不是代码问题。