Android 中指纹识别的使用
Android 中指纹识别的使用
- 前言
- 指纹登录流程
- 指纹识别在指纹登录中的作用
- 指纹登录相关流程
- 指纹识别面临的问题
- 指纹登录实现
- 指纹识别的集成
- 开启指纹登录功能
- 指纹登录功能
- 总结
前言
最近,在查看 SampleProject 这个项目的时候,就觉得吧,这个登录有点麻烦,总是要输密码,现在很多 APP 都是可以指纹登录的呀,这个必须支持一波;而且开发这么多年还没尝试过指纹识别,这可不行,学到老活到老嘛。
指纹登录流程
指纹登录 不就是简单的调用 指纹识别 的 API
然后登录账号吗,这有什么可说的?可能有人会问了。然而并非如此,一开始我也很天真的以为就这么简单,但是在网上找了很多文章之后发现,大多数的文章都只是详细的说明了怎么去调用 指纹识别 的 API
,至于怎么用于登录,怎么去实现 指纹登录 的业务确是很少提及,所以,这里我会先给大家讲清楚实现 指纹登录 的流程再去实现。
指纹识别在指纹登录中的作用
登录是我们应用中的逻辑,我们把 指纹识别 穿插在其中是需要他做什么?
实际上,我们可以把 指纹登录 简单的理解成 不用密码登录,那么为了能过 不用密码登录,我们肯定需要把用户登录需要的信息 保存到本地
,那么我们首先考虑到的就是 本地数据的安全问题,在这里,指纹识别 就为我们本地数据提供了 加密、解密
的功能。
指纹登录相关流程
如上图所示,在使用 指纹登录 功能前,我们需要先 开启指纹登录,这个步骤是为了获取登录所需要的数据,并进行加密存储,之后再 指纹登录 时,获取存储加密的数据,进行解密,然后进行登录。
指纹识别面临的问题
在实现功能之前,我们需要知道,Google 从 Android 6.0
才开始支持 指纹识别,所以,如果你想兼顾 6.0 以下的机型,那么你可能需要自己去集成不同 手机厂商 的 SDK
,当然了,现在 6.0
以下的手机已经很少了,而且我的项目只是一个自用的 DEMO,就不去做那些复杂的东西了,有需要的可以自行了解;
其次,从 Android 6.0
Google 新增了 FingerprintManager
用于指纹识别,后续又新增了 FingerprintManagerCompat
提供了一些兼容性操作,再到 Android 9.0
新增了 BiometricPrompt
API
用于生物识别,并将 FingerprintManager
添加了 @Deprecated
标记,所以在实现时我们也需要考虑版本兼容问题。
指纹登录实现
从上面,我们了解了 指纹登录 的流程以及 指纹识别 的发展及要注意的问题,接下来我们开始实现。
指纹识别的集成
首先,我们将 指纹识别 功能集成进来。
虽然 Android 6.0
就有了 指纹识别 的 API
,但显然并不是所有手机都会支持,所以,我们首先来判断当前手机是否支持 指纹识别。
/** [Build.VERSION_CODES.M] 以上指纹管理对象 */
private val fingerprintManager: FingerprintManagerCompat by lazy {FingerprintManagerCompat.from(activity)
}/** 检查指纹识别支持状态 */
fun checkBiometric(): Int {// 获取锁屏管理val km = context.getSystemService(KeyguardManager::class.java)return when {!fingerprintManager.isHardwareDetected -> {// 不支持指纹BiometricInterface.ERROR_HW_UNAVAILABLE}!km.isKeyguardSecure -> {// 未设置锁屏BiometricInterface.ERROR_NO_DEVICE_CREDENTIAL}!fingerprintManager.hasEnrolledFingerprints() -> {// 未注册有效指纹BiometricInterface.ERROR_NO_BIOMETRICS}else -> {// 支持指纹识别BiometricInterface.HW_AVAILABLE}}
}
在确定手机支持 指纹识别 后,我们就可以调用 API
拉起指纹识别功能了。
/** [Build.VERSION_CODES.M] 以上指纹管理对象 */
private val fingerprintManager: FingerprintManagerCompat by lazy {FingerprintManagerCompat.from(activity)
}/** [Build.VERSION_CODES.M] 以上拉起指纹认证 */
fun authenticateM() {fingerprintManager.authenticate(crypto, // 包装了 Cipher 对象的 FingerprintManagerCompat.CryptoObject 对象,用于加解密flags, // 可选 flag,建议为 0cancel, // CancellationSignal 对象,用于取消指纹认证,可空,但不建议为 nullcallback, // 认证回调接口handler // 回调所在 Handler,一般为 null)
}
上面只是 Android 6.0
以上的简单的 指纹认证 代码,但是 FingerprintManagerCompat
并没有提供相关提示弹窗,所以,在这基础上,我们还需要加上相关弹窗逻辑。
/** [Build.VERSION_CODES.M] 以上拉起指纹认证 */
fun authenticateM() {val cancellationSignal = CancellationSignal()cancellationSignal.setOnCancelListener {// 取消回调}val dialog = BiometricDialog.create()dialog.setOnCancelListener {// 取消指纹认证cancellationSignal.cancel()}dialog.show()fingerprintManager.authenticate(crypto, // 包装了 Cipher 对象的 FingerprintManagerCompat.CryptoObject 对象,用于加解密flags, // 可选 flag,建议为 0cancellationSignal, // CancellationSignal 对象,用于取消指纹认证,可空,但不建议为 nullobject: FingerprintManagerCompat.AuthenticationCallback() {override fun onAuthenticationSucceeded(result: FingerprintManagerCompat.AuthenticationResult?) {// 认证成功dialog.dismiss()}override fun onAuthenticationHelp(helpCode: Int, helpString: CharSequence?) {// 认证提示dialog.setHint(helpString)}override fun onAuthenticationFailed() {// 认证失败dialog.dismiss()}override fun onAuthenticationError(errorCode: Int, errString: CharSequence?) {// 认证异常dialog.dismiss()}}, // 认证回调接口null // 回调所在 Handler,一般为 null)
}
这样,我们的认证功能就完成了,而在 Android 9.0
新增的 BiometricPrompt
API
中已经提供相关提示弹窗,所以不需要我们自己手动实现弹窗。
/** [Build.VERSION_CODES.Q] 以上拉起指纹认证 */
fun authenticateQ() {val cancellationSignal = CancellationSignal()cancellationSignal.setOnCancelListener {// 取消回调}// 生成认证对象val prompt = with(BiometricPrompt.Builder(activity)) {setTitle(title)setSubtitle(subTitle)setDescription(hint)setNegativeButton(negative, activity.mainExecutor, { dialog, _ ->// 取消回调dialog?.dismiss()cancellationSignal.cancel()})build()}prompt.authenticate(crypto, // 包装了 Cipher 对象的 BiometricPrompt.CryptoObject 对象,用于加解密cancellationSignal, // CancellationSignal 对象,用于取消指纹认证,不能为空executor, // 回调 Executor,不能为空,可使用 activity.mainExecutorcallback // 认证回调)
}
那么 crypto
怎么获取呢?这个就要结合业务场景来说了,因为 Cipher
对象在用于 加密、解密 时获取的方式是不同的。
开启指纹登录功能
上文有说到过,指纹登录 功能要先提供 开启指纹登录 来保存登录需要的数据,因为 玩Android 没有单独提供相关的 API
,所以这里我们就使用 登录 接口来验证密码的正确性;
所以,首先弹窗提示,让用户输入密码,确认后调用 登录接口 验证密码正确性,确认密码正确后,将密码暂时缓存,拉起 指纹认证;
指纹认证流程在上面已经说过了,这里我们重点介绍 Cipher
对象的获取。
/** 获取 Cipher 对象 */
fun loadCipher(): Cipher {val keyStore = KeyStore.getInstance("AndroidKeyStore")keyStore.load(null)// keyAlias 为密钥别名,可自己定义,加密解密要一致if (!keyStore.containsAlias(keyAlias)) {// 不包含改别名,重新生成// 秘钥生成器val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")val builder = KeyGenParameterSpec.Builder(keyAlias,KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT).setBlockModes(KeyProperties.BLOCK_MODE_CBC).setUserAuthenticationRequired(false).setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)keyGenerator.init(builder.build())keyGenerator.generateKey()}// 根据别名获取密钥val key = keyStore.getKey(keyAlias, null)val cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"+ KeyProperties.BLOCK_MODE_CBC + "/"+ KeyProperties.ENCRYPTION_PADDING_PKCS7)// 开启登录时用于加密,使用 Cipher.ENCRYPT_MODE 初始化cipher.init(Cipher.ENCRYPT_MODE, key)return cipher
}
获取到 Cipher
对象后,调用指纹认证,不同版本 CryptoObject
的对象是不同的,直接新建对应对象,将 Cipher
对象传入即可
/** 指纹认证回调成功 */
override fun onAuthenticationSucceeded(result: AuthenticationResult?) {// 认证成功,获取 Cipher 对象val cipher = result?.cryptoObject?.cipher ?: throw RuntimeException("cipher is null!")// 使用 cipher 对登录信息进行加密并保存val encryptInfo = cipher.doFinal(loginInfo.toByteArray()).toHexString()// 保存 encryptInfo 到本地// 保存加密向量到本地save(encryptInfo)save(cipher.iv.toHexString())
}
这样 开启指纹登录 就完成了。
需要注意的有三点:
- 加密时,
Cipher
对象使用cipher.init(Cipher.ENCRYPT_MODE, key)
进行初始化; - 指纹认证成功后,使用回调返回
Cipher
对象对数据进行加密; - 指纹认证成功后,要将
Cipher
对象中的加密向量iv
保存起来。
指纹登录功能
通过上面开启了 指纹登录 之后,我们就可以在登录页进行 指纹登录 了。
进入登录页后,可以自动拉起 指纹登录 或者用户点击 指纹登录 后拉起。
/** 获取 Cipher 对象 */
fun loadCipher(): Cipher {val keyStore = KeyStore.getInstance("AndroidKeyStore")keyStore.load(null)// keyAlias 为密钥别名,可自己定义,加密解密要一致if (!keyStore.containsAlias(keyAlias)) {// 不包含改别名,重新生成// 秘钥生成器val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")val builder = KeyGenParameterSpec.Builder(keyAlias,KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT).setBlockModes(KeyProperties.BLOCK_MODE_CBC).setUserAuthenticationRequired(false).setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)keyGenerator.init(builder.build())keyGenerator.generateKey()}// 根据别名获取密钥val key = keyStore.getKey(keyAlias, null)val cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"+ KeyProperties.BLOCK_MODE_CBC + "/"+ KeyProperties.ENCRYPTION_PADDING_PKCS7)// 获取开启指纹登录时保存的加密向量数据val ivBytes = get(IV_BYTES).toHexByteArray()val iv = IvParameterSpec(ivBytes)// 使用指纹登录,使用 Cipher.DECRYPT_MODE 和 iv 进行初始化cipher.init(Cipher.DECRYPT_MODE, key, iv)return cipher
}
和上面开启一样,拉起指纹认证。
/** 指纹认证回调成功 */
override fun onAuthenticationSucceeded(result: AuthenticationResult?) {// 认证成功,获取 Cipher 对象val cipher = result?.cryptoObject?.cipher ?: throw RuntimeException("cipher is null!")// 使用 cipher 对登录信息进行解密val logintInfo = cipher.doFinal(get(encryptInfo).toHexByteArray()// 使用 loginInfo 进行登录login(loginInfo)
}
这样就完成了 指纹登录。
需要注意的有两点:
- 解密时,
Cipher
对象使用cipher.init(Cipher.DECRYPT_MODE, key, iv)
进行初始化; - 指纹认证成功后,使用回调返回
Cipher
对象对数据进行解密。
总结
看完全文,你学会怎么集成 指纹登录 功能了吗?我们需要牢记的是,指纹登录 就是一个类似于 记住密码 的功能,在这个过程中使用到了 指纹认证 来对登录信息进行加密解密,使用的都是 Cipher
对象,而用于加密和解密时 Cipher
对象的初始化方式有所不同,解密时需要使用到加密时生成的 IvParameterSpec
加密向量,而由我们初始化出来的 Cipher
对象是无法直接使用的,需要使用 指纹认证 处理之后才能用于加密解密。
想要我的源码吗?想要的话可以全部给你,去找吧!我把所有源码都放在那里!>> SampleProject <<
感谢大家的耐心观看,我是 WangJie0822 ,一个平平凡凡的程序猿,欢迎关注。
作者: WangJie0822
链接: http://www.wangjie0822.top/posts/bef2e009
来源: WangJie0822
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
Android 中指纹识别的使用相关推荐
- Android中指纹识别的使用
/ 今日科技快讯 / 近日,微软斥资75亿美元收购了游戏发行商ZeniMax Media,后者旗下的游戏工作室曾推出<毁灭战士>以及<辐射>等知名游戏.这使得微软旗下的 ...
- Android O指纹识别解析
版权声明:本文为梦想全栈程序猿原创文章,转载请附上原文出处链接和本声明 前面一片文章--Android Fingerprint完全解析(三) :Fingerprint Hal层分析 Android O ...
- android开发-指纹识别
在Android 6.0中google终于给Android系统加上了指纹识别的支持,这个功能在iPhone上早就已经实现了,并且在很多厂商的定制的ROM中也都自己内部实现这个功能了,这个功能来的有点晚 ...
- android华为指纹识别开发,华为正在研发“全屏指纹识别+屏下摄像头”共存机型...
原标题:华为正在研发"全屏指纹识别+屏下摄像头"共存机型 信息显示9月1日中兴将全球首发屏幕下摄像头机型A20 5G,此前业内传言这项技术是华为首发.从现在看来是不可能了,一来中兴 ...
- Android随笔-指纹识别
Android指纹识别在Android 6.0以下是不支持的,Android 6.0使用FingerprintManager进行指纹识别,Android 9.0建议使用BiometricPrompt进 ...
- Android使用指纹识别功能
指纹识别是在Android 6.0以后新增的功能,在使用的时候需要先判断手机的系统版本是否支持指纹识别. AndroidManifest添加权限 <uses-permission android ...
- Android 实现指纹识别demo
demo链接:https://download.csdn.net/download/meixi_android/10796468 1.指纹工具类: /*** 作者:created by meixi* ...
- 简单实现 Android M 指纹识别(附源码)
众所周知, Android阵营里的指纹兼容真可谓是一团糟, 每个厂家几乎都有一套自己的API, 直到Android M的出现, 才慢慢地走上正途. 那么今天我们就一起来探讨一下, Android M里 ...
- Android开发 指纹识别
1.添加指纹识别权限: <uses-permission android:name="android.permission.USE_FINGERPRINT"/> 2.获 ...
- android手机中指纹识别应用相关功能的讲解
现在很多手机厂商都加入了指纹芯片,相对应的就要开发一系列相配套的指纹相关功能,其中基本功能为应用锁,应用冻结,通过指纹关闭闹钟,通过指纹拍照,通过指纹接听电话,指纹作为密码对文件加密,自定义滑动指纹器 ...
最新文章
- 近期活动盘点:首届Apache Flink 极客挑战赛、2019年社会计算机国际会议
- 如何用Node调用腾讯AI图像服务
- 第十五届全国大学生智能汽车竞赛 车模检查手册
- ubuntu下qt的常见错误
- CCNA学习指南第二章
- Java基础知识Set、List、Map的区别
- 三、Java基础工具(1)_常用类——数学相关类
- 空军军医大学计算机复试线,2021空军军医大学考研国家线公布时间_国家线是多少分...
- sdut Message Flood(c++ map)
- Mac 电脑如何对文件进行批量重命名?
- C#_asp.net mvc 验证码功能的具体实现
- MacBook Pro M1 安装 VMware Fusion 及 CentOS 8
- c语言迭代埃特金加速算法,5-埃特金加速迭代算法
- linux格式化u盘保护,linux系统怎么避免u盘被写保护
- 计算机考研四门专业课是什么,2019计算机考研专业课复习问题答疑
- Material Design系列之BottomSheet详解
- QQ等级图标对应的算法
- 记事本文件管理器关联文本类
- 太阳诱电 | 汽车用金属功率电感器MCOIL™ LCEN 系列实现商品化
- 托福高频真词List19 // 附托福TPO阅读真题
热门文章
- 通过网页版邮箱的实现“联系我们”
- 光敏二极管的工作原理
- PHP显示了验证码但不能登陆,thinkphp5 登陆后台验证码无法显示
- phpnow升级php5.5版本,PHPNow156升级PHP版本至5.3.5
- C#使用System.Speech制作语音提示功能。
- 学习 MySQL 需要知道的 28 个小技巧
- Python 爬虫从入门到进阶之路(八)
- matplotlib中线宽linewidth的默认值是多少?如何查看?如何设置/设定?如何修改?
- 微信小程序大家来找茬 ,快速通过方法
- Zigbee物联网应用