5、BiometricPrompt高级配置:设置标题与副标题、设置描述信息、设置允许设备凭证回退
好,咱们接着聊。上一章我们把BiometricPrompt的基本调用跑通了,但说实话,那种默认弹窗太素了,像个毛坯房。今天我们就来给它精装修一下——标题、副标题、描述信息,还有那个关键的“允许设备凭证回退”。
我个人习惯,在讲配置之前,先搞清楚一件事:你希望用户看到什么,以及当生物识别失败时,你希望发生什么。这直接决定了用户体验的流畅度。
5.1 标题与副标题:别让用户一脸懵
默认的弹窗标题是“人脸识别”或“指纹识别”,副标题是空的。但你想啊,用户打开你的App,突然弹个“人脸识别”,他可能不知道你要干嘛。所以,标题要说明意图。
比如我做支付模块时,标题写的是“验证身份以完成支付”,副标题写的是“请正视手机,保持光线充足”。用户一看就明白,哦,要付钱了,我得配合一下。
代码上怎么配?很简单,在BiometricPrompt.PromptInfo的Builder里直接设置:
BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
.setTitle("验证身份以完成支付") // 必填
.setSubtitle("请正视手机,保持光线充足") // 可选,但强烈建议
.setDescription("我们将使用人脸识别验证您的身份") // 可选
.setAllowedAuthenticators(BIOMETRIC_STRONG | DEVICE_CREDENTIAL)
.build();
嗯,这里要注意:setTitle是必填的,不填会直接崩溃。我见过有新手直接不设标题,结果一调用就闪退,查了半天日志才发现是这里抛了IllegalArgumentException。
5.2 描述信息:给用户一个“为什么”
描述信息不是必填的,但我建议你加上。为什么?因为有些用户会犹豫:“为什么又要我刷脸?你们是不是在偷我隐私?”
描述信息就是用来打消这个疑虑的。你可以写“仅用于本次登录验证,不会存储您的面部数据”。用户看到这个,心里会踏实很多。
我在项目中遇到过一件事:有个用户反馈说每次支付都要刷脸,很烦。后来我在描述里加了“每次支付均需独立验证,确保资金安全”,反馈就少了。说白了,用户需要被尊重,也需要被理解。
5.3 允许设备凭证回退:最后的救命稻草
这是今天最核心的部分。什么叫“设备凭证回退”?简单说,就是当人脸识别失败(比如光线太暗、你戴了口罩、或者手机不支持人脸),系统允许用户用PIN码、图案或密码来替代。
你想想看,如果你只开了人脸识别,用户在大太阳底下死活刷不过去,又没有回退方案,那他就永远进不了你的App了。这体验,直接归零。
所以,我建议所有生产环境的App都开启设备凭证回退。除非你的App只用于演示,或者你有特殊的安保要求(比如某些金融App强制只能用生物识别)。
开启方式就是上面代码里的那一行:
.setAllowedAuthenticators(BIOMETRIC_STRONG | DEVICE_CREDENTIAL)
这里BIOMETRIC_STRONG代表强生物识别(比如3D人脸、指纹),DEVICE_CREDENTIAL代表设备凭证(PIN/图案/密码)。两个用“或”操作符连起来,意思就是:优先用生物识别,不行就让你输密码。
BIOMETRIC_STRONG,没加DEVICE_CREDENTIAL。结果测试时发现,在模拟器上人脸识别永远失败,而且没有回退按钮,整个App卡死在验证界面。用户只能强杀进程。从那以后,我再也不敢省略这个配置了。
5.4 完整配置示例与流程
好,我们把上面所有配置整合起来,看看一个完整的、生产级别的BiometricPrompt长什么样:
// 1. 构建PromptInfo
BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
.setTitle("验证身份以完成支付")
.setSubtitle("请正视手机,保持光线充足")
.setDescription("仅用于本次支付验证,不会存储您的面部数据")
.setAllowedAuthenticators(BIOMETRIC_STRONG | DEVICE_CREDENTIAL)
.build();
// 2. 创建BiometricPrompt实例(需要传入Activity和回调)
BiometricPrompt biometricPrompt = new BiometricPrompt(
this,
Executors.newSingleThreadExecutor(),
new BiometricPrompt.AuthenticationCallback() {
@Override
public void onAuthenticationSucceeded(
@NonNull BiometricPrompt.AuthenticationResult result) {
// 验证成功,放行
runOnUiThread(() -> Toast.makeText(MainActivity.this, "验证通过", Toast.LENGTH_SHORT).show());
}
@Override
public void onAuthenticationFailed() {
// 验证失败(非致命,可继续尝试)
runOnUiThread(() -> Toast.makeText(MainActivity.this, "人脸识别失败,请重试", Toast.LENGTH_SHORT).show());
}
@Override
public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
// 致命错误(如硬件不可用、用户取消等)
runOnUiThread(() -> Toast.makeText(MainActivity.this, "错误: " + errString, Toast.LENGTH_LONG).show());
}
});
// 3. 启动验证
biometricPrompt.authenticate(promptInfo);
这个流程,说白了就是三步:配信息 → 建实例 → 调验证。但每一步都有细节,尤其是回调里的onAuthenticationFailed和onAuthenticationError的区别,很多人搞混。
我简单解释一下:onAuthenticationFailed是“这次没匹配上,但你可以再试一次”;onAuthenticationError是“系统出问题了,或者用户主动取消了,你别再试了”。前者是软失败,后者是硬失败。
5.5 知识体系一览
为了让你更直观地理解这些配置之间的关系,我画了一张图:
从图上可以看得很清楚:标题和副标题解决“是什么”,描述信息解决“为什么”,设备凭证回退解决“怎么办”。三者缺一不可。
5.6 避坑指南
最后,分享几个我实际踩过的坑,你遇到了可以直接跳过:
- setTitle不能为空字符串——哪怕你传一个空格,系统也会报错。我习惯用“验证身份”作为保底标题。
- 设备凭证回退需要用户已设置锁屏——如果用户手机没设PIN/图案/密码,回退按钮会显示,但点击后会跳转到设置界面。你需要在回调里处理这种情况,别让用户卡住。
- 描述信息不要写“请放心”之类的空话——用户不信这个。写具体一点,比如“仅用于本次操作,不记录面部数据”。
- 副标题不要和描述信息重复——副标题是操作指引,描述是隐私说明。混在一起会让用户觉得啰嗦。
好了,这一章的内容就这些。配置虽然简单,但每个字段背后都是用户体验的考量。下一章我们会聊更进阶的东西——如何处理加密与CryptoObject,让生物识别不仅仅是“刷脸”,还能真正保护你的敏感数据。