9、Android Biometric API:BiometricPrompt API、BiometricManager、CryptoObject集成、兼容性处理
各位好,今天我们聊聊 Android 生物识别 API 的实战部分。说实话,指纹认证这块坑不少,尤其是 Android 碎片化严重,不同厂商、不同版本的行为差异很大。我个人习惯是把 API 分成三层来理解:能力检测层、交互层、安全层。这样思路会清晰很多。
9.1 BiometricManager:先问问系统行不行
你想想看,如果手机压根没有指纹模块,或者用户没录入指纹,你直接弹 BiometricPrompt 会怎样?嗯,大概率是崩溃或者无响应。所以第一步,用 BiometricManager 做前置检查。
BiometricManager 是 Android 10 引入的,用来替代旧版的 FingerprintManagerCompat。它的核心方法就一个:canAuthenticate()。
BiometricManager manager = BiometricManager.from(context);
int result = manager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG);
switch (result) {
case BiometricManager.BIOMETRIC_SUCCESS:
// 可以正常使用
break;
case BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE:
// 设备没有指纹硬件
break;
case BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE:
// 硬件暂时不可用
break;
case BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED:
// 用户没录入指纹
break;
}
我在项目中遇到过一种情况:某款国产手机,硬件明明支持指纹,但 canAuthenticate() 返回 BIOMETRIC_ERROR_HW_UNAVAILABLE。后来发现是系统服务被冻结了,重启一下就好。所以这个检查结果只能作为参考,不能完全依赖。
Authenticators.BIOMETRIC_WEAK 来支持人脸和指纹混合认证。但说实话,弱生物识别的安全性存疑,我一般只用 BIOMETRIC_STRONG。
9.2 BiometricPrompt:真正的认证交互
BiometricPrompt 是 Android 9 推出的统一认证对话框。它替代了旧版的 FingerprintDialog,并且支持指纹、人脸、虹膜等多种方式。说白了,你只需要调用它,系统会帮你处理 UI 和认证流程。
基本用法如下:
BiometricPrompt biometricPrompt = new BiometricPrompt(
activity,
executor,
new BiometricPrompt.AuthenticationCallback() {
@Override
public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) {
// 认证成功
}
@Override
public void onAuthenticationFailed() {
// 认证失败(指纹不匹配)
}
@Override
public void onAuthenticationError(int errorCode, CharSequence errString) {
// 认证错误(比如取消、重试次数过多)
}
}
);
BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
.setTitle("验证指纹")
.setSubtitle("请触摸指纹传感器")
.setNegativeButtonText("取消")
.build();
biometricPrompt.authenticate(promptInfo);
这里有个细节:setNegativeButtonText() 是必须的,否则会抛异常。为什么?因为系统需要给用户一个明确的取消入口。我曾经在测试时忘了加这个,结果直接崩溃,日志提示 Negative button text must be set。嗯,这个坑我替你们踩过了。
9.3 CryptoObject 集成:安全加密的基石
单纯的指纹认证其实意义不大——你只是验证了「手指是本人的」,但后续的数据保护呢?比如支付场景,你需要用指纹解锁一个密钥,然后用密钥签名交易。这时候就要用到 CryptoObject。
CryptoObject 本质上是一个加密对象的容器,可以包装 Cipher、Signature、Mac 等。它的工作流程是这样的:
- 生成一个密钥,存入 Android KeyStore(硬件安全模块)
- 设置密钥的访问条件:必须经过生物认证才能使用
- 创建 Cipher 对象,用密钥初始化
- 将 Cipher 包装成 CryptoObject,传给 BiometricPrompt
- 认证成功后,用 Cipher 加密/解密数据
代码示例:
// 1. 生成密钥
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
"my_key",
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.setUserAuthenticationRequired(true) // 必须生物认证
.setInvalidatedByBiometricEnrollment(true) // 新增指纹时失效
.build();
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
keyGenerator.init(spec);
keyGenerator.generateKey();
// 2. 创建 Cipher
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
SecretKey key = (SecretKey) keyStore.getKey("my_key", null);
cipher.init(Cipher.ENCRYPT_MODE, key);
// 3. 包装成 CryptoObject
BiometricPrompt.CryptoObject cryptoObject = new BiometricPrompt.CryptoObject(cipher);
// 4. 认证
biometricPrompt.authenticate(promptInfo, cryptoObject);
这里有个关键点:setInvalidatedByBiometricEnrollment(true)。如果用户新增了一个指纹,之前生成的密钥会立即失效。这是为了防止「旧指纹被删除后,新指纹还能用旧密钥」的安全漏洞。我在项目中见过有人把这个设为 false,结果安全审计没通过。记住,安全功能不是摆设,别偷懒。
9.4 兼容性处理:从 Android 6 到 Android 14
Android 生物识别 API 经历了三个阶段:
| Android 版本 | 推荐 API | 说明 |
|---|---|---|
| 6.0 (API 23) | FingerprintManager | 最早版本,需要自己处理 UI |
| 9.0 (API 28) | BiometricPrompt (无 CryptoObject) | 统一 UI,但加密支持有限 |
| 10.0 (API 29) | BiometricPrompt + CryptoObject | 完整功能,推荐使用 |
| 11.0+ (API 30+) | BiometricManager + 多模态 | 支持人脸、虹膜等 |
兼容性处理的核心策略是:能用新的就别用旧的。但现实是,你的 App 可能还要支持 Android 6 到 8 的设备。这时候怎么办?
我的做法是:
- 在 Android 9+ 设备上,统一使用 BiometricPrompt
- 在 Android 6-8 设备上,回退到 FingerprintManagerCompat(来自 support-v4 库)
- 在 Android 5 及以下,直接提示「设备不支持」
代码判断:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// 使用 BiometricPrompt
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// 使用 FingerprintManagerCompat
} else {
// 不支持
}
这里有个坑:某些厂商在 Android 9 上预装了 FingerprintManager,但 BiometricPrompt 可能不工作。我遇到过一加 6T 的 Android 9 版本,BiometricPrompt 弹不出来,最后发现是系统 ROM 的 bug。解决方案是加一个 try-catch,如果 BiometricPrompt 初始化失败,就降级到 FingerprintManager。
onAuthenticationError 回调在用户取消时返回的 errorCode 是 5(BIOMETRIC_ERROR_CANCELED),但小米手机上返回的是 10(BIOMETRIC_ERROR_USER_CANCELED)。所以不要硬编码 errorCode,用系统常量判断。
9.5 整体架构图
下面这张图展示了 Biometric API 的核心调用链路:
从图中可以看到,BiometricManager 负责「能不能用」,BiometricPrompt 负责「怎么交互」,CryptoObject 负责「安不安全」。三者各司其职,缺一不可。
9.6 总结
嗯,这一章内容不少。核心就三件事:
- 先检查:用 BiometricManager 确认硬件和指纹状态
- 再交互:用 BiometricPrompt 弹出系统认证对话框
- 最后加密:用 CryptoObject 保护敏感数据
兼容性方面,记住一个原则:能用 BiometricPrompt 就用,不行再降级。别为了兼容旧版本,在新设备上还用 FingerprintManager,那样用户体验会差很多。
最后说一句:指纹认证不是银弹。它只是「用户身份验证」的一个环节,真正的安全性还要靠服务端、传输层、数据存储等多方面配合。别以为加了指纹就万事大吉了。
公众号:蓝海资料掘金营,微信deep3321