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

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

有人知道如何在 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.access00(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 
            //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 
     * @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% 已被 root。因此,这可能与人们试图绕过必须为功能付费有关。

编辑:我尝试传递 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 为 null 时抛出异常,并且我已经收到一些来自 Beta 测试人员的报告。所有 100% root 设备,所以我猜他们的设备没有正确的 com.android.vending.billing.InAppBillingService.BIND。

编辑:代码发布后,100% root 设备下降到大约 80%。无论如何,我有机会与用户进行故障排除,结果发现 getExplicitIntent 方法有时可以 return null 在 kitkat 下(不确定是哪个其他版本)所以我继续并添加了一个关于我如何更改代码的答案。

您有方法 queryIntentServicesAsUser() 的代码吗?仔细查看后,您发送 queryIntentServices 的变量之一似乎导致了 NullPointer。

那么最后解决这个问题的正确方法是什么? serviceIntent 为 null - 这意味着有人想要破解?在这种情况下我们让应用程序崩溃?

我终于找到了一个没有对应用内购买进行任何狡猾行为的用户。他在玩风筝。修复是这样的:

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

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