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. 备用做法是:直接使用无密钥验证,但是有一定的安全风险,目前在观察线上用户出现频率,再考虑是否用备用方案。
1,小米6、6X手机上点击“Turn On Identification”的时候会先走一遍onAuthenticationHelp,helpCode=1021,helpString为空

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容

  • 好久没写文章了,最近也比较偷懒,今天继续讨论我实际开发中遇到的需求,那就是关于APP解锁,大家都知道。现在越来越多...
    青蛙要fly阅读 3,051评论 2 26
  • 一、 指纹识别接口从Android 6.0开始,Android系统加上了对指纹识别的支持。所有指纹识别的接口都在...
    Qi0907阅读 1,416评论 0 1
  • 指纹识别-Android @(Android进阶资料)[Android, 学习, 读书笔记, Markdown]指...
    辰曦小雨阅读 1,591评论 3 6
  • 最近项目中添加了一个新的登录方式:指纹识别。好巧不巧这块分给了我,然后一顿研究。下面想把一些实现的代码贴出来做个笔...
    SHERLOCKvv阅读 23,686评论 6 28
  • 中午的时候妈妈发了一条朋友圈,是刚做好的焖面,想起来上次吃焖面还是寒假过年回家的时候,心中略数了一下大概还要三个...
    余余不吃鱼阅读 654评论 0 2