2、Android生物识别API概览:BiometricPrompt介绍、BiometricManager介绍、CryptoObject介绍
好,咱们直接进入正题。Android官方在Android 9(API 28)之后,把生物识别的API统一了。以前各家厂商各玩各的,指纹归指纹,人脸归人脸,代码写起来那叫一个痛苦。现在好了,一个BiometricPrompt搞定所有。
我个人习惯把这三个核心API分成三个角色来理解:检查员、执行者、保镖。你想想看,是不是很形象?
核心三件套速览:
- BiometricManager — 检查设备是否支持、是否已录入
- BiometricPrompt — 弹出系统对话框,执行认证
- CryptoObject — 加密绑定,防止中间人攻击
2.1 BiometricManager — 先问问设备行不行
说白了,BiometricManager就是你的侦察兵。在弹出认证对话框之前,你得先确认三件事:设备有没有指纹/人脸硬件?系统版本够不够?用户有没有录入生物信息?
我记得有一次在项目里,没做这个检查就直接调了BiometricPrompt,结果在模拟器上直接崩了。嗯,从那以后我再也不敢跳过这一步了。
// 获取 BiometricManager 实例
val biometricManager = BiometricManager.from(context)
// 检查设备是否支持生物识别
when (biometricManager.canAuthenticate(
BiometricManager.Authenticators.BIOMETRIC_STRONG
or BiometricManager.Authenticators.DEVICE_CREDENTIAL
)) {
BiometricManager.BIOMETRIC_SUCCESS ->
// 可以正常使用
Log.d("Biometric", "设备支持,可以认证")
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE ->
// 没有硬件
Log.e("Biometric", "设备没有生物识别硬件")
BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE ->
// 硬件暂时不可用
Log.e("Biometric", "硬件暂时不可用,稍后再试")
BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED ->
// 用户没有录入
Log.w("Biometric", "请先录入指纹或人脸")
}
💡 我的小建议:
检查结果如果是BIOMETRIC_ERROR_NONE_ENROLLED,最好引导用户去系统设置里录入。别直接弹个Toast就完事了,用户体验会很差。
2.2 BiometricPrompt — 真正的认证执行者
这个才是主角。BiometricPrompt会弹出一个系统级的对话框,风格统一,安全性高。你不需要自己画UI,系统帮你搞定。
你想想看,如果每个App都自己画一个指纹/人脸界面,那得多乱?而且很容易被钓鱼。系统对话框的好处是——用户一看就知道这是真的系统认证,不是假的。
// 创建 BiometricPrompt 实例
val biometricPrompt = BiometricPrompt(
this, // FragmentActivity 或 Fragment
ContextCompat.getMainExecutor(this),
object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
// 认证成功
Log.d("Biometric", "认证通过!")
// 可以在这里获取 CryptoObject
val cryptoObject = result.cryptoObject
}
override fun onAuthenticationFailed() {
// 认证失败(非致命,可重试)
Log.w("Biometric", "认证失败,请重试")
}
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
// 认证错误(致命,不可重试)
Log.e("Biometric", "认证错误: $errString")
}
}
)
// 配置认证参数
val promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle("验证身份")
.setSubtitle("请使用指纹或人脸认证")
.setDescription("用于登录您的账户")
.setAllowedAuthenticators(
BiometricManager.Authenticators.BIOMETRIC_STRONG
or BiometricManager.Authenticators.DEVICE_CREDENTIAL
)
.setConfirmationRequired(false) // 人脸识别是否需要眨眼确认
.build()
// 启动认证
biometricPrompt.authenticate(promptInfo)
⚠️ 避坑指南:
我曾经在onAuthenticationError里直接弹了一个Dialog,结果因为回调线程和UI线程的问题导致崩溃。记住:回调默认在主线程,但如果你用了自定义Executor,记得切回主线程再更新UI。
2.3 CryptoObject — 给认证加把锁
这个可能是初学者最容易忽略的。CryptoObject说白了就是把加密操作和生物识别绑定在一起。为什么要这么做?
假设你的App里有个功能:用户通过指纹后才能查看银行卡号。如果没有CryptoObject,黑客可以伪造一个"认证成功"的回调。但有了它,只有真正的生物识别通过后,才能拿到加密密钥去解密数据。
// 生成一个加密对象
val keyGenParameterSpec = KeyGenParameterSpec.Builder(
"my_biometric_key",
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.setUserAuthenticationRequired(true) // 必须通过生物识别才能使用
.setInvalidatedByBiometricEnrollment(true) // 新增指纹时失效
.build()
val keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"
)
keyGenerator.init(keyGenParameterSpec)
keyGenerator.generateKey()
// 创建 Cipher 对象
val cipher = Cipher.getInstance(
"${KeyProperties.KEY_ALGORITHM_AES}/${KeyProperties.BLOCK_MODE_CBC}/${KeyProperties.ENCRYPTION_PADDING_PKCS7}"
)
val keyStore = KeyStore.getInstance("AndroidKeyStore")
keyStore.load(null)
val secretKey = keyStore.getKey("my_biometric_key", null) as SecretKey
cipher.init(Cipher.ENCRYPT_MODE, secretKey)
// 创建 CryptoObject
val cryptoObject = BiometricPrompt.CryptoObject(cipher)
// 使用 CryptoObject 进行认证
biometricPrompt.authenticate(promptInfo, cryptoObject)
🔐 关键点:
setUserAuthenticationRequired(true)— 密钥必须通过生物认证才能解锁setInvalidatedByBiometricEnrollment(true)— 用户新增指纹/人脸后,旧密钥失效,防止绕过- 认证成功后,通过
AuthenticationResult.getCryptoObject()拿到已解锁的加密对象
2.4 三者如何配合?
我习惯的流程是这样的:
- 先用BiometricManager检查 — 不行就直接降级或提示
- 准备好CryptoObject — 如果需要加密操作,提前生成密钥和Cipher
- 调用BiometricPrompt.authenticate() — 传入PromptInfo和可选的CryptoObject
- 在回调中处理结果 — 成功则使用CryptoObject解密,失败则提示重试
其实说白了,这三者缺一不可。少了BiometricManager,你可能会在没硬件的设备上崩溃;少了CryptoObject,你的认证结果可能被篡改;少了BiometricPrompt,你连认证对话框都弹不出来。
📌 我的经验:
如果你只是做一个"登录时验证指纹"的功能,可以不用CryptoObject。但如果是"查看敏感信息"或"支付确认",一定要加上。我在一个金融类项目里吃过亏,后来补上了CryptoObject才过审。
公众号:蓝海资料掘金营,微信deep3321