Android指纹识别


在Android6.0(Api23)的时候,Android系统加入了指纹识别的api接口,即FingerprintManager,定义了最基础的指纹识别接口。不过,在AndroidP(Api28)的时候,官方不再推荐使用,做了@Deprecated处理。

 

后来,在support v4库中添加了FingerprintManagerCompat类,我看了他的源码,其实就是对FingerprintManager做了一定的封装,比如做了对SDK版本的判断、对于加密部分的处理等等,其本质还是在用FingerprintManager来实现指纹识别功能。

到了AndroidP,FingerprintManager就正式退役了,系统新增了BiometricPrompt接口,从接口名字'生物识别'也能看出来,今后的安全验证功能,将不会局限于指纹了,应该还会加入面部识别等等。

下面就通过我写的一个demo,展开来介绍一下FingerprintManager以及BiometricPrompt

一、公共部分:

1、总的来说,我们写一个Manager类,类的内部通过Api版本的判断,来分别实现Api23和Api28的适配

 

分别根据Api版本来实例化两个类

2、其中,判断版本号的办法是:

 

判断版本号

3、其次,我们声明了一个接口IBiometricPromptImpl,Api28和Api23的实例都要继承他

 

接口

3、对于系统是否支持指纹识别的判断:

 

四个判断一起来做出最后的判断

 

demo中的表现

分别说明一下判断的细节:

isAboveApi23():上面已经说过了;
isHardwareDetected(): 这是用来判断系统硬件是否支持指纹识别,这里也是分情况判断,但是AndroidP还不知道用什么确切的办法来判断,所以暂时用与AndroidM一样的方式。Api23的具体实现在实现类中,后续你会看到

isHardwareDetected()

 

hasEnrolledFingerprints():这个方法是用来判断你的设备在系统设置里面是否设置了指纹。
如果用户没有设置,这时候你可以引导他去设置。不过,我查了一下,各个厂家的设置指纹的页面Activity名都不是统一的,所以这里要一一做适配能累成狗。所以如果要引导的话,引导到安全设置页面就可以了,安全设置页面系统有统一的Intent,是【Settings.ACTION_SECURITY_SETTINGS】。

hasEnrolledFingerprints()

 

isKeyguardSecure():这个方法是判断系统有没有设置锁屏。
这个方法我认为是个鸡肋,因为现在如果你设置了指纹的话,肯定要让你先设置一种密码(PIN/Password/Pattern),那么锁屏肯定也就随之设置了,不理解为啥还要判断一下这个。。。

isKeyguardSecure()

 

二、BiometricPromptApi23: 针对Api23~Api27的部分

1、authenticate()

在看BiometricPromptApi23.java里面的内容之前,我们先需要了解一下指纹识别的关键方法:authenticate()

authenticate方法


上图是google的api文档中的描述,现在我们挨个解释一下这些参数都是什么:
①. crypto这是一个加密类的对象,指纹扫描器会使用这个对象来判断认证结果的合法性。这个对象可以是null,但是这样的话,就意味这app无条件信任认证的结果,虽然从理论上这个过程可能被攻击,数据可以被篡改,这是app在这种情况下必须承担的风险。因此,建议这个参数不要置为null。这个类的实例化有点麻烦,主要使用javax的security接口实现,后面我的demo程序中会给出一个helper类(CryptoObjectHelper.java),这个类封装内部实现的逻辑,开发者可以直接使用我的类简化实例化的过程。
②. cancel这个是CancellationSignal类的一个对象,这个对象用来在指纹识别器扫描用户指纹的是时候取消当前的扫描操作,如果不取消的话,那么指纹扫描器会移植扫描直到超时(一般为30s,取决于具体的厂商实现),这样的话就会比较耗电。建议这个参数不要置为null。
③. flags 标识位,根据上图的文档描述,这个位暂时应该为0,这个标志位应该是保留将来使用的。
④.callback这个是FingerprintManager.AuthenticationCallback类的对象,这个是这个接口中除了第一个参数之外最重要的参数了,稍后我们详细来介绍。这个参数不能为NULL。
⑤. handler 这是Handler类的对象,如果这个参数不为null的话,那么FingerprintManager将会使用这个handler中的looper来处理来自指纹识别硬件的消息。通常来讲,开发这不用提供这个参数,可以直接置为null,因为FingerprintManager会默认使用app的main looper来处理。

 

2、指纹认证之后的回调方法

这里就要介绍的是上面提到的FingerprintManager.AuthenticationCallback了,因为扫描指纹和认证的过程都是在另外一个进程中完成的,所以我们需要采取异步的方式,等操作完成之后,让系统回调给我们,回调方法就是AuthenticationCallback类中的4个方法了

四个回调方法


下面我们简要介绍一下这些接口的含义:
①. OnAuthenticationError(int errorCode, ICharSequence errString) 这个接口会再系统指纹认证出现不可恢复的错误的时候才会调用,并且参数errorCode就给出了错误码,标识了错误的原因。
在AndroidP以前,这个方法回调回来之后,指纹识别sensor将会被关闭,也就是说,你再把手指放在指纹硬件上,将不会有反应了。这时候你需要提示用户关闭指纹识别弹窗,或改用密码支付等等
什么情况下会回调error错误呢?比如,连续识别错误5次指纹、指纹硬件不可用等等。
②. OnAuthenticationFailed()这个接口会在系统指纹认证失败的情况的下才会回调。注意这里的认证失败和上面的认证错误是不一样的,虽然结果都是不能认证。认证失败是指所有的信息都采集完整,并且没有任何异常,但是这个指纹和之前注册的指纹是不相符的;但是认证错误是指在采集或者认证的过程中出现了错误,比如指纹传感器工作异常等。也就是说认证失败是一个可以预期的正常情况,而认证错误是不可预期的异常情况。
③.OnAuthenticationHelp(int helpMsgId, ICharSequence helpString)上面的认证失败是认证过程中的一个异常情况,我们说那种情况是因为出现了不可恢复的错误,而我们这里的OnAuthenticationHelp方法是出现了可以回复的异常才会调用的。什么是可以恢复的异常呢?一个常见的例子就是:手指移动太快,当我们把手指放到传感器上的时候,如果我们很快地将手指移走的话,那么指纹传感器可能只采集了部分的信息,因此认证会失败。但是这个错误是可以恢复的,因此只要提示用户再次按下指纹,并且不要太快移走就可以解决。
④. OnAuthenticationSucceeded(FingerprintManagerCompati.AuthenticationResult result)这个接口会在认证成功之后回调。我们可以在这个方法中提示用户认证成功。这里需要说明一下,如果我们上面在调用authenticate的时候,我们的CryptoObject不是null的话,那么我们在这个方法中可以通过AuthenticationResult来获得Cypher对象然后调用它的doFinal方法。doFinal方法会检查结果是不是会拦截或者篡改过,如果是的话会抛出一个异常。当我们发现这些异常的时候都应该将认证当做是失败来来处理,为了安全建议大家都这么做。

 

 

好了,下面来看看我的demo里的实现

 

 

这个authenticate方法是重写了IBiometricPromptImpl接口中的方法,重要的部分我已经加了注释,剩下的应该能看懂了吧,不懂的可以在评论中问~~【手动笑脸☺】

 

实现了指纹识别的回调类

 

打开dialog,等待识别

 

识别出错了

 

识别成功,之后自动关闭dialog

下面是两个判断方法的实现

 

判断是否硬件支持和是否设置了指纹

三、BiometricPromptApi28: 针对Api28及以后的平台

在AndroidP中,原来的fingerprintManager将被BiometricPrompt类替换,Google旨在统一生物识别的方式(虽然目前api中还没有看到虹膜、面部识别等),包括UI,UI也不允许自定义了,必须使用BiometricPrompt.Builder来创建对话框,其中可以自定义title、subtitle、description和一个NegativeButton(也就是cancel键)。

AndroidP中系统对话框的表现

 

创建对话框

只有一个NegativeButton,这个很尴尬,意思是只能有button存在界面上,如果我想加个UsePassword的button,只能把这个cancel键给改掉。。。(不过,大家放心,虽然AndroidP的source还没有放出来,不过,我让老同事帮忙找了一分BiometricPrompt的源码,里面还是有一个PositiveButton的,只不过api应该还没有放出来)

下面来看看实现代码:
构造方法,创建signature对象(对于加密这块理解的不好,哪位大神可以给普及普及)

 

构造方法

 

跟Api23很像,实现authenticate方法

 

authenticate方法


回调

回调方法

附上源码:有问题可以探讨:https://github.com/gaoyangcr7/BiometricPromptDemo

常见问题:

1,报错 java.io.IOException: Failed to find byte code for android/hardware/biometrics/BiometricPrompt$AuthenticationCallback

去设置里把InstantRun关掉就好了

2,报错 java.lang.RuntimeException: java.security.InvalidAlgorithmParameterException: java.lang.IllegalStateException: At least one fingerprint must be enrolled to create keys requiring user authentication for every use at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)

  1. 这个异常不是模拟器上才出现的,真机也会,和设备无关,怀疑是谷歌 API 的坑
  2. 我的做法是catch住异常,友好提示用户暂不支持指纹,引导用户使用其他的验证方式
  3. 备用做法是:直接使用无密钥验证,但是有一定的安全风险,目前在观察线上用户出现频率,再考虑是否用备用方案。

3,小米6、6X手机上点击“Turn On Identification”的时候会先走一遍onAuthenticationHelp,helpCode=1021,helpString为空

应该是MIUI自行修改了底层时间,可以尝试晚一点调用authenticate方法(没试验过,主要手边没小米手机)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值