解决Android指纹识别Crash异常Attempt to invoke virtual method ‘boolean FingerprintManager.isHardwareDetected()‘ on a null objec
前言
解决Android指纹识别Crash异常java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.hardware.fingerprint.FingerprintManager.isHardwareDetected()' on a null object
的问题及原因探究
问题
应用需要提交至小米应用市场,未审核通过,下图是小米审核的结果
小米给的log比较完整,整个log文件都有28M多,下载后先直接搜索关键字beginning of crash
或FATAL EXCEPTION: main
,找到异常信息如下:
--------- beginning of crash 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: FATAL EXCEPTION: main 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: Process: com.ktt.xxx, PID: 6318 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.ktt.xxx/com.ktt.smarthome.activity.MainActivityWithSlide}: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.hardware.fingerprint.FingerprintManager.isHardwareDetected()' on a null object reference 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2841) 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2919) 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: at android.app.ActivityThread.-wrap11(Unknown Source:0) 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1637) 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:106) 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: at android.os.Looper.loop(Looper.java:176) 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:6656) 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method) 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547) 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873) 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.hardware.fingerprint.FingerprintManager.isHardwareDetected()' on a null object reference 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: at com.ktt.smarthome.activity.MenuFram.isFingerPrintAvailable(MenuFram.java:105) 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: at com.ktt.smarthome.activity.MenuFram.onActivityCreated(MenuFram.java:74) 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: at android.app.Fragment.performActivityCreated(Fragment.java:2517) 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1299) 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: at android.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1562) 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1623) 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: at android.app.FragmentManagerImpl.dispatchMoveToState(FragmentManager.java:3032) 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: at android.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:2984) 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: at android.app.FragmentController.dispatchActivityCreated(FragmentController.java:178) 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: at android.app.Activity.performCreate(Activity.java:7080) 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: at android.app.Activity.performCreate(Activity.java:7065) 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214) 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2794) 07-31 00:25:17.684 10108 6318 6318 E AndroidRuntime: ... 9 more
为了发现更多问题,我有在小米云测平台对所有的小米机型进行了兼容性测试,测试结果和审核结果log一致,竟然是所有Redmi A系列都有这个问题,测试失败结果如下图所示
解决
通过上面发现,具体crash异常如下:java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.hardware.fingerprint.FingerprintManager.isHardwareDetected()' on a null object
通过异常信息NullPointerException,可以很容易看出这是个空指针异常,要解决这个问题到是很简单,定位到异常所在的文件,所在的行。异常的代码如下:
return fm.isHardwareDetected()&&fm.hasEnrolledFingerprints();
很明显就是调用fm为null导致的,对fm加上null判断即可解决,修改后的代码如下:
return fm != null && fm.isHardwareDetected() && fm.hasEnrolledFingerprints();
原因
问题虽然解决了,作为一个每遇到一个问题都要追根问底的开发,当然要知道原因咯。
- 为什么问题出在Redmi 6A、7A、8A?
通过查阅发现这几款手机都是不带指纹的,但是带面部解锁。
因为指纹解锁、指纹支付成本较高,这就是为什么红米A系列的手机性价比高的原因了。
既然不带指纹,那我猜测是因为小米将没有指纹识别机器的Rom中移除了 FingerprintManager的API
实际上这个API是在6.0才加入的。文档:
- 指纹识别API的演进
在 Android 6.0(Android M Api23),Android 系统开放了指纹识别的api,存在于 android.hardware.fingerprint包下,核心类是FingerprintManager,提供了基础的指纹识别的功能。要注意的是,FingerprintManager在 Android 9.0(Android P Api28)做了 @Deprecated 标记,将被弃用。
后来,在android.support.v4.hardware.fingerprint包和 androidx.core.hardware.fingerprint包中,FingerprintManager升级为了 FingerprintManagerCompat,对功能进行了增强,也做了一些兼容性的处理,比如增加了系统版本号的判断,对指纹支持加密处理等。实际上阅读源码会发现,他的核心功能还是调用 FingerprintManager 实现的。
再之后,在 Android 9.0(Android P Api 28),Google 对生物识别进行了进一步增强,开放了以 BiometricPrompt 为核心的新 Api,存在于 androidx.biometric 包和android.hardware.biometrics包下,Google 在开发者文档中是这样解释的:
On devices running P and above, this will show a system-provided authentication prompt, using a device’s supported biometric (fingerprint, iris, face, etc).
大意是,在 Android P 及以上版本的系统中,BiometricPrompt 将展现一个由系统提供的验证提示,用于支持设备提供的生物识别,包括指纹、虹膜、面部等。
目前来看,虹膜和面部等生物识别 Api 尚未开放,仅支持指纹识别,不过在指纹识别上进行了统一,比如要求使用统一的指纹识别 UI ,不允许开发者自定义了。
参考链接
本文地址:https://blog.csdn.net/oHaiKuoTianKong1682/article/details/107906287