IabHelper.startSetup的java.lang.NullPointerException(IabHelper.java:266)

时间:2015-01-27 18:53:01

标签: android in-app-purchase

任何人都知道如何在IabHelper设置开始时修复此NullPointerException

java.lang.NullPointerException
       at android.app.ApplicationPackageManager.queryIntentServicesAsUser(ApplicationPackageManager.java:559)
       at android.app.ApplicationPackageManager.queryIntentServices(ApplicationPackageManager.java:571)
       at IabHelper.startSetup(IabHelper.java:266)
       at MyApplication.createIABHelper(MyApplication.java:256)
       at MyApplication.onCreate(MyApplication.java:156)
       at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1000)
       at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4391)
       at android.app.ActivityThread.access$1300(ActivityThread.java:141)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1294)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loop(Looper.java:137)
       at android.app.ActivityThread.main(ActivityThread.java:5041)
       at java.lang.reflect.Method.invokeNative(Method.java)
       at java.lang.reflect.Method.invoke(Method.java:511)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:816)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:582)
       at dalvik.system.NativeStart.main(NativeStart.java)

由于其他问题,我的IabHelper代码略有修改,所以这里是startSetup方法:

public void startSetup(final OnIabSetupFinishedListener listener) {
        // If already set up, can't do it again.
        checkNotDisposed();
        if (mSetupDone) throw new IllegalStateException("IAB helper is already set up.");

        // Connection to IAB service
        logDebug("Starting in-app billing setup.");
        mServiceConn = new ServiceConnection() {
            @Override
            public void onServiceDisconnected(ComponentName name) {
                logDebug("Billing service disconnected.");
                mService = null;
            }

            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                if (mDisposed) return;
                logDebug("Billing service connected.");
                mService = IInAppBillingService.Stub.asInterface(service);
                String packageName = mContext.getPackageName();
                try {
                    logDebug("Checking for in-app billing 3 support.");

                    // check for in-app billing v3 support
                    int response = mService.isBillingSupported(3, packageName, ITEM_TYPE_INAPP);
                    if (response != BILLING_RESPONSE_RESULT_OK) {
                        if (listener != null) listener.onIabSetupFinished(new IabResult(response,
                                "Error checking for billing v3 support."));

                        // if in-app purchases aren't supported, neither are subscriptions.
                        mSubscriptionsSupported = false;
                        return;
                    }
                    logDebug("In-app billing version 3 supported for " + packageName);

                    // check for v3 subscriptions support
                    response = mService.isBillingSupported(3, packageName, ITEM_TYPE_SUBS);
                    if (response == BILLING_RESPONSE_RESULT_OK) {
                        logDebug("Subscriptions AVAILABLE.");
                        mSubscriptionsSupported = true;
                    } else {
                        logDebug("Subscriptions NOT AVAILABLE. Response: " + response);
                    }

                    mSetupDone = true;
                } catch (RemoteException e) {
                    if (listener != null) {
                        listener.onIabSetupFinished(new IabResult(IABHELPER_REMOTE_EXCEPTION,
                                "RemoteException while setting up in-app billing."));
                    }
                    e.printStackTrace();
                    return;
                }

                if (listener != null) {
                    listener.onIabSetupFinished(new IabResult(BILLING_RESPONSE_RESULT_OK, "Setup successful."));
                }
            }
        };

        Intent serviceIntent = getExplicitIapIntent();
        PackageManager pm = mContext.getPackageManager();
        List<ResolveInfo> intentServices = pm.queryIntentServices(serviceIntent, 0);
        if (intentServices != null && !intentServices.isEmpty()) {
            //this was replaced per this comment http://stackoverflow.com/a/24202135/704836
            //if (!mContext.getPackageManager().queryIntentServices(serviceIntent, 0).isEmpty()) {
            // service available to handle that Intent
            mContext.bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
        } else {
            // no service available to handle that Intent
            if (listener != null) {
                listener.onIabSetupFinished(
                        new IabResult(BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE,
                                "Billing service unavailable on device."));
            }
        }
    }

NullPointerException发生在List<ResolveInfo> intentServices = pm.queryIntentServices(serviceIntent, 0);

有什么想法吗?

感谢。

编辑:这是getExplicitIapIntent的代码:

 /**
     * From http://stackoverflow.com/a/26318757/704836
     * @return
     */
    private Intent getExplicitIapIntent() {
        PackageManager pm = mContext.getPackageManager();
        Intent implicitIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
        implicitIntent.setPackage("com.android.vending");
        List<ResolveInfo> resolveInfos = pm.queryIntentServices(implicitIntent, 0);

        // Is somebody else trying to intercept our IAP call?
        if (resolveInfos == null || resolveInfos.size() != 1) {
            return null;
        }

        ResolveInfo serviceInfo = resolveInfos.get(0);
        String packageName = serviceInfo.serviceInfo.packageName;
        String className = serviceInfo.serviceInfo.name;
        ComponentName component = new ComponentName(packageName, className);
        Intent iapIntent = new Intent();
        iapIntent.setComponent(component);
        return iapIntent;
    }

编辑:我还应该指出,根据crashlytics,100%发出此错误的设备都是根深蒂固的。所以也许这与试图绕过必须支付功能的人有关。

编辑:我尝试传递null而非serviceIntent并获得以下例外:

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Intent.resolveTypeIfNeeded(android.content.ContentResolver)' on a null object reference
            at android.app.ApplicationPackageManager.queryIntentServicesAsUser(ApplicationPackageManager.java:644)
            at android.app.ApplicationPackageManager.queryIntentServices(ApplicationPackageManager.java:656)
            at IabHelper.startSetup(IabHelper.java:266)

在该例外情况下,行号与我收到的报告不同,所以我不确定它是否相同。

编辑:我认为上次编辑时遇到的异常可能与我为5.0.2设备获得的异常几乎相同。以下是5.0.2报告之一:

 java.lang.NullPointerException
Attempt to invoke virtual method 'java.lang.String android.content.Intent.resolveTypeIfNeeded(android.content.ContentResolver)' on a null object reference

android.app.ApplicationPackageManager.queryIntentServicesAsUser (ApplicationPackageManager.java:645)

android.app.ApplicationPackageManager.queryIntentServices (ApplicationPackageManager.java:657)

IabHelper.startSetup (IabHelper.java:266)

编辑:我继续修改代码,以便在serviceIntent为空时抛出异常并且我已经从我的Beta版测试人员那里收到了一些报告。所有100%根设备,所以我猜他们的设备没有正确的com.android.vending.billing.InAppBillingService.BIND。

编辑:一旦代码发布,100%的根设备就会下降到80%左右。无论如何我有机会对用户进行故障排除,事实证明getExplicitIntent方法有时可以在kitkat下返回null(不知道哪个其他版本)所以我继续并添加了一个答案,我如何更改代码。

3 个答案:

答案 0 :(得分:0)

你有方法queryIntentServicesAsUser()的代码吗?仔细研究后,看起来你发送queryIntentServices的变量之一可能是导致NullPointer。

答案 1 :(得分:0)

那么最后解决这个问题的正确方法是什么? serviceIntent为null - 这意味着有人想破解?我们让ap​​p在这种情况下崩溃了吗?

答案 2 :(得分:0)

我终于发现一个用户获得了一个空的意图,他没有对应用内购买做任何狡猾的事情。他在kitkat。修复是这样的:

if (OSUtils.lollipopOrHigher) {
            serviceIntent = getExplicitIapIntent();
        } else {
            serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
            serviceIntent.setPackage("com.android.vending");
        }

另一种选择是检查null然后尝试非棒棒糖方法。