Android指纹识别API讲解,一种更快更好的用户体验
我发现了一个比较怪的现象。在iphone上使用十分普遍的指纹认证功能,在android手机上却鲜有app使用,我简单观察了一下,发现android手机上基本上只有支付宝、微信和极少app支持指纹认证功能,就连银行和金融类的应用都基本不支持,甚至很多开发者都不知道android系统是有指纹认证的官方api的。
事实上,android从6.0系统开始就支持指纹认证功能了,但是指纹功能还需要有硬件支持才行,而android手机的硬件都是由各厂商生产的,手机档次也参差不齐,因此不能像iphone那样保证所有的手机都是支持指纹认证功能的。所以,可能很多开发者就觉得,即使做了指纹认证功能,也无法兼容所有的手机,还是要配合图案解锁或密码等功能一起使用才行,那么索性就只用图案和密码好了,一劳永逸。
看似这样解释好像也合情合理,但其实受伤的是数以亿计的android手机用户。明明有更轻松更快捷的使用方式,却因为app不予支持,最终只能使用更加原始和笨拙的方式。在国内,绝大多数android手机的指纹认证功能都仅仅只局限于用来解锁手机而已,很少有使用到app的功能逻辑当中。
其实将指纹认证功能使用到app的功能逻辑当中是有很多功能场景的,比如说金融银行类app可以使用指纹认证来快速登录,应用商店类app可以使用指纹认证来下载安装软件,股票证券类app可以使用指纹认证来操作和交易等等。
虽然有了应用场景,还有很多开发者可能会担心,指纹认证功能实现起来会不会很复杂?因为毕竟支持的设备有限,还要配合图案和密码来使用才行,如果实现起来非常复杂,又只能支持部分设备的话,那投入产出比就太低了,或许这也是很多app不肯去实现指纹认证功能的原因。这里我不得不说,android官方提供的指纹认证demo的确是挺复杂的,看着让人望而却步。但是大家不用担心,本篇文章中我会带着大家一起去实现一个最简版的指纹认证demo,直接复制粘贴本文中的代码到大家各自的项目中,即可一步集成指纹认证功能。
那么话不多说,首先新建一个fingerprinttest项目,并选择添加一个empty activity。然后修改activity_main.xml中的代码,如下所示:
<?xml version="1.0" encoding="utf-8"?> <framelayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <textview android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="已进入app主界面" android:textsize="18sp" android:layout_gravity="center" /> </framelayout>
这里我们修改了mainactivity中的布局文件,在界面上添加了一个 已进入app主界面 的textview,待会在指纹认证通过之后,就会让app跳转到此界面。
接下来我们开始编写指纹认证界面,新建fingerprint_dialog.xml,代码如下所示:
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <imageview android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:src="@drawable/ic_fp_40px" /> <textview android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margintop="20dp" android:text="请验证指纹解锁" android:textcolor="#000" android:textsize="16sp" /> <textview android:id="@+id/error_msg" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margintop="5dp" android:maxlines="1" android:textsize="12sp" android:textcolor="#f45" /> <view android:layout_width="match_parent" android:layout_height="0.5dp" android:layout_margintop="10dp" android:background="#ccc" /> <textview android:id="@+id/cancel" android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center" android:text="取消" android:textcolor="#5d7883" android:textsize="16sp" /> </linearlayout>
这是一个非常简易的指纹认证界面,相信没什么需要解释的地方。界面大致样式如下图所示:
注意,通常为了让用户清楚的知道现在需要进行指纹认证,google官方建议最好使用一个通用的指纹图标,而不应该由各app制作自己的指纹图标。为此,google也特意提供了一套指纹认证的组图。
接着我们创建一个fingerprintdialogfragment类,并让它继承自dialogfragment,用于作为提示用户进行指纹认证的对话框,代码如下所示:
@targetapi(23) public class fingerprintdialogfragment extends dialogfragment { private fingerprintmanager fingerprintmanager; private cancellationsignal mcancellationsignal; private cipher mcipher; private loginactivity mactivity; private textview errormsg; /** * 标识是否是用户主动取消的认证。 */ private boolean isselfcancelled; public void setcipher(cipher cipher) { mcipher = cipher; } @override public void onattach(context context) { super.onattach(context); mactivity = (loginactivity) getactivity(); } @override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); fingerprintmanager = getcontext().getsystemservice(fingerprintmanager.class); setstyle(dialogfragment.style_normal, android.r.style.theme_material_light_dialog); } @nullable @override public view oncreateview(layoutinflater inflater, @nullable viewgroup container, bundle savedinstancestate) { view v = inflater.inflate(r.layout.fingerprint_dialog, container, false); errormsg = v.findviewbyid(r.id.error_msg); textview cancel = v.findviewbyid(r.id.cancel); cancel.setonclicklistener(new view.onclicklistener() { @override public void onclick(view v) { dismiss(); stoplistening(); } }); return v; } @override public void onresume() { super.onresume(); // 开始指纹认证监听 startlistening(mcipher); } @override public void onpause() { super.onpause(); // 停止指纹认证监听 stoplistening(); } private void startlistening(cipher cipher) { isselfcancelled = false; mcancellationsignal = new cancellationsignal(); fingerprintmanager.authenticate(new fingerprintmanager.cryptoobject(cipher), mcancellationsignal, 0, new fingerprintmanager.authenticationcallback() { @override public void onauthenticationerror(int errorcode, charsequence errstring) { if (!isselfcancelled) { errormsg.settext(errstring); if (errorcode == fingerprintmanager.fingerprint_error_lockout) { toast.maketext(mactivity, errstring, toast.length_short).show(); dismiss(); } } } @override public void onauthenticationhelp(int helpcode, charsequence helpstring) { errormsg.settext(helpstring); } @override public void onauthenticationsucceeded(fingerprintmanager.authenticationresult result) { toast.maketext(mactivity, "指纹认证成功", toast.length_short).show(); mactivity.onauthenticated(); } @override public void onauthenticationfailed() { errormsg.settext("指纹认证失败,请再试一次"); } }, null); } private void stoplistening() { if (mcancellationsignal != null) { mcancellationsignal.cancel(); mcancellationsignal = null; isselfcancelled = true; } } }
说了是实现一个最简版的指纹认证demo,因此这里的代码也都是非常简单的,基本上就是一个fragment类的最普通实现,下面我带大家简单解析一下。
首先setcipher()方法用于接受一个cipher对象,这个参数在待会进行指纹认证的时候会用到。
接下来几个生命周期方法都很简单,在onattach()方法中获取了activity的实例,在oncreate()方法获取了fingerprintmanager的实例,在oncreateview()方法中加载了我们刚刚创建的fingerprint_dialog.xml布局,都是一些常规操作。
紧接着重点的要来了,在onresume()方法中调用了startlistening()方法开始指纹认证监听,在onpause()方法中调用了stoplistening()方法停止指纹认证监听。为什么要这么做呢?因为指纹传感器和摄像头类似,是不能多个程序同时使用的,因此任何一个程序都不应该在非前台时刻占用着指纹传感器的资源,所以需要在onpause()方法中及时释放资源。
那么,现在我们只需要把所有的目光都放在startlistening()和stoplistening()这两个方法上就可以了。在startlistening()方法中,调用了fingerprintmanager的authenticate()方法来开启指纹指纹监听。authenticate()方法接收五个参数,第一个参数是cryptoobject对象,这里我们只需要将刚才传入的cipher对象包装成cryptoobject对象就可以了。第二个参数是cancellationsignal对象,可以使用它来取消指纹认证操作。第三个参数是可选参数,官方的建议是直接传0就可以了。第四个参数用于接收指纹认证的回调,上述代码中我将所有的回调可能都进行了界面提示,方便大家观察。第五个参数用于指定处理回调的handler,这里直接传null表示回调到主线程即可。
而在stoplistening()方法中的逻辑则简单得多了,我们只需要调用cancellationsignal的cancel()方法将指纹认证操作取消就可以了。
这样我们就将fingerprintdialogfragment中的代码全部完成了,这段代码可以直接复制到任意项目当中来作为指纹认证提醒对话框。
最后,我们再来编写一个简单的登录界面,整个指纹认证过程就完整了。创建loginactivity,代码如下所示:
public class loginactivity extends appcompatactivity { private static final string default_key_name = "default_key"; keystore keystore; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_login); if (supportfingerprint()) { initkey(); initcipher(); } } public boolean supportfingerprint() { if (build.version.sdk_int < 23) { toast.maketext(this, "您的系统版本过低,不支持指纹功能", toast.length_short).show(); return false; } else { keyguardmanager keyguardmanager = getsystemservice(keyguardmanager.class); fingerprintmanager fingerprintmanager = getsystemservice(fingerprintmanager.class); if (!fingerprintmanager.ishardwaredetected()) { toast.maketext(this, "您的手机不支持指纹功能", toast.length_short).show(); return false; } else if (!keyguardmanager.iskeyguardsecure()) { toast.maketext(this, "您还未设置锁屏,请先设置锁屏并添加一个指纹", toast.length_short).show(); return false; } else if (!fingerprintmanager.hasenrolledfingerprints()) { toast.maketext(this, "您至少需要在系统设置中添加一个指纹", toast.length_short).show(); return false; } } return true; } @targetapi(23) private void initkey() { try { keystore = keystore.getinstance("androidkeystore"); keystore.load(null); keygenerator keygenerator = keygenerator.getinstance(keyproperties.key_algorithm_aes, "androidkeystore"); keygenparameterspec.builder builder = new keygenparameterspec.builder(default_key_name, keyproperties.purpose_encrypt | keyproperties.purpose_decrypt) .setblockmodes(keyproperties.block_mode_cbc) .setuserauthenticationrequired(true) .setencryptionpaddings(keyproperties.encryption_padding_pkcs7); keygenerator.init(builder.build()); keygenerator.generatekey(); } catch (exception e) { throw new runtimeexception(e); } } @targetapi(23) private void initcipher() { try { secretkey key = (secretkey) keystore.getkey(default_key_name, null); cipher cipher = cipher.getinstance(keyproperties.key_algorithm_aes + "/" + keyproperties.block_mode_cbc + "/" + keyproperties.encryption_padding_pkcs7); cipher.init(cipher.encrypt_mode, key); showfingerprintdialog(cipher); } catch (exception e) { throw new runtimeexception(e); } } private void showfingerprintdialog(cipher cipher) { fingerprintdialogfragment fragment = new fingerprintdialogfragment(); fragment.setcipher(cipher); fragment.show(getfragmentmanager(), "fingerprint"); } public void onauthenticated() { intent intent = new intent(this, mainactivity.class); startactivity(intent); finish(); } }
首先在oncreate()方法中,调用了supportfingerprint()方法来判断当前设备是否支持指纹认证功能。这一点是非常重要的,因为当设备不支持指纹认证的时候,还需要及时切换到如图案、密码等其他的认证方式。
当设备支持指纹认证的时候,再分为两步,第一步生成一个对称加密的key,第二步生成一个cipher对象,这都是android指纹认证api要求的标准用法。得到了cipher对象之后,我们创建fingerprintdialogfragment的实例,并将cipher对象传入,再将fingerprintdialogfragment显示出来就可以了。
最后的最后,当指纹认证成功之后,会在fingerprintdialogfragment的回调当中调用loginactivity的onauthenticated()方法,然后界面会跳转到mainactivity,整个指纹认证过程就此结束。
总共就这些代码了,总体来说还是相当简单的,现在我们来运行一下看看实际的效果吧。打开应用之后会立刻弹出指纹认证对话框,此时先使用错误的手指来进行认证:
可以看到,当指纹验证失败的时候,会在界面上显示相应的错误提示信息。
接下来使用正确的手指来进行认证:
ok,指纹验证成功,并自动跳转到了mainactivity界面。
这样一个最简版的指纹认证demo就此完成,大家如果想要在自己的app中集成指纹认证功能,只需要复制粘贴本文中的代码就可以轻松实现了。
在文章的结尾我还想再补充几句,虽然本文中的指纹认证demo实现过程很简单,但是切记它是不能单独使用的,必须要配合着图案或其他认证方式一起来使用,因为一定要提供一个在设备不支持指纹情况下的其他认证方式。
另外,比较遗憾的是,虽然是刚刚写出来的文章,但是fingerprintmanager在最新的android 9.0系统上已经被废弃了。因为android 9.0系统提供了更加强大的生物识别认证功能,包括指纹识别、面部识别、甚至是虹膜识别等等,因此仅仅只能用于指纹识别的fingerprintmanager已经不能满足新系统的强大需求了。不过大家也不用担心,虽然被标为废弃,但是至少在较长一段时间内,fingerprintmanager还是可以正常使用的。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。如果你想了解更多相关内容请查看下面相关链接