4、BiometricPrompt基础用法:创建实例、设置回调、启动认证
好,我们直接进入正题。
上一章我们聊了Android的生物识别体系,说白了就是系统帮你封装好了各种传感器。但真正跟代码打交道的,就是这个 BiometricPrompt。我个人习惯把它叫做「认证大管家」——你只管告诉它「我要认证了」,剩下的活它全包了。
4.1 创建BiometricPrompt实例
先看一段最基础的代码。嗯,别急着复制,先理解结构。
// 第一步:准备一个主线程的Executor
Executor executor = ContextCompat.getMainExecutor(this);
// 第二步:创建BiometricPrompt实例
BiometricPrompt biometricPrompt = new BiometricPrompt(
this, // Activity或Fragment
executor, // 回调执行的线程
new BiometricPrompt.AuthenticationCallback() {
// 回调方法稍后填充
}
);
这里有个细节——executor。我建议你用主线程的Executor,因为回调里通常要更新UI。如果你用后台线程,还得自己切线程,何必呢?
我的习惯: 如果项目里用了Kotlin协程,我会把executor换成Dispatchers.Main.asExecutor()。但Java项目老老实实用ContextCompat.getMainExecutor()就行。
4.2 设置认证回调
回调是核心。你想想看,用户把眼睛凑到摄像头前,系统怎么告诉你结果?就是通过这三个方法:
| 回调方法 | 触发时机 | 我踩过的坑 |
|---|---|---|
onAuthenticationSucceeded() |
认证成功 | 别忘了检查result.getUserId(),多设备场景下有用 |
onAuthenticationFailed() |
认证失败(可重试) | 别在这里直接弹「认证失败」对话框,用户可能只是没对准 |
onAuthenticationError() |
不可恢复的错误 | 比如指纹传感器被暴力尝试锁定,这时候必须停止认证 |
看一个完整的回调实现:
BiometricPrompt.AuthenticationCallback callback =
new BiometricPrompt.AuthenticationCallback() {
@Override
public void onAuthenticationSucceeded(
BiometricPrompt.AuthenticationResult result) {
// 认证成功!解锁应用或执行敏感操作
showMessage("虹膜匹配成功,欢迎回来");
// 我曾经在这里忘记记录日志,导致线上问题无法排查
Log.d("BiometricDemo", "认证成功,用户ID: " +
result.getUserId());
}
@Override
public void onAuthenticationFailed() {
// 认证失败,但可以重试
// 注意:这里不要直接finish Activity
showMessage("请重新对准摄像头");
}
@Override
public void onAuthenticationError(int errorCode,
CharSequence errString) {
// 不可恢复的错误
// 比如:BIOMETRIC_LOCKOUT = 7
showMessage("认证已锁定,请稍后再试");
// 我建议在这里停用所有认证按钮
disableBiometricButton();
}
};
注意: onAuthenticationFailed() 和 onAuthenticationError() 的区别。前者是「没匹配上,再试一次」,后者是「系统不让你试了」。我曾经在项目里把两者搞混,结果用户被锁了5分钟还在不断重试……嗯,那个版本被测试打回来了。
4.3 启动认证
实例和回调都准备好了,最后一步就是启动。这里需要构建一个 BiometricPrompt.PromptInfo 对象:
BiometricPrompt.PromptInfo promptInfo =
new BiometricPrompt.PromptInfo.Builder()
.setTitle("虹膜验证")
.setSubtitle("请将眼睛对准屏幕上方")
.setDescription("用于解锁应用内敏感数据")
.setNegativeButtonText("取消")
.build();
// 启动认证
biometricPrompt.authenticate(promptInfo);
这里有个容易忽略的点——setNegativeButtonText 是必须的。为什么?因为系统需要给用户一个「取消」的入口。如果你不设置,会直接抛异常。
核心流程总结:
1. 创建 BiometricPrompt 实例(传入Executor和Callback)
2. 构建 PromptInfo(标题、描述、取消按钮)
3. 调用 authenticate() 启动系统认证对话框
1. 创建 BiometricPrompt 实例(传入Executor和Callback)
2. 构建 PromptInfo(标题、描述、取消按钮)
3. 调用 authenticate() 启动系统认证对话框
4.4 完整代码示例
把上面三段拼起来,就是一个完整的虹膜认证流程:
public class IrisAuthActivity extends AppCompatActivity {
private BiometricPrompt biometricPrompt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_iris_auth);
Executor executor = ContextCompat.getMainExecutor(this);
biometricPrompt = new BiometricPrompt(this, executor,
new BiometricPrompt.AuthenticationCallback() {
@Override
public void onAuthenticationSucceeded(
BiometricPrompt.AuthenticationResult result) {
runOnUiThread(() ->
Toast.makeText(IrisAuthActivity.this,
"认证成功", Toast.LENGTH_SHORT).show());
}
@Override
public void onAuthenticationFailed() {
runOnUiThread(() ->
Toast.makeText(IrisAuthActivity.this,
"认证失败,请重试", Toast.LENGTH_SHORT).show());
}
@Override
public void onAuthenticationError(int errorCode,
CharSequence errString) {
runOnUiThread(() ->
Toast.makeText(IrisAuthActivity.this,
"错误: " + errString,
Toast.LENGTH_LONG).show());
}
});
}
public void startAuth(View view) {
BiometricPrompt.PromptInfo promptInfo =
new BiometricPrompt.PromptInfo.Builder()
.setTitle("虹膜验证")
.setSubtitle("请将眼睛对准屏幕上方")
.setDescription("用于解锁应用内敏感数据")
.setNegativeButtonText("取消")
.build();
biometricPrompt.authenticate(promptInfo);
}
}
4.5 核心流程图
下面这张图,是我自己画的一个流程。你看一眼就能明白整个认证的生命周期:
4.6 避坑指南
- 我曾经遇到过:在
onAuthenticationFailed()里直接弹Dialog,结果用户连续失败5次后系统锁定了,Dialog却还在。正确的做法是监听onAuthenticationError()并关闭所有认证UI。 - 注意线程:回调默认在传入的Executor上执行。如果你传了后台线程,记得切回主线程更新UI。我建议直接用主线程Executor,省心。
- PromptInfo的setTitle不能为空:系统要求至少设置标题,否则会抛IllegalArgumentException。嗯,这个坑我踩过两次。
调试小技巧: 在开发阶段,可以在
onAuthenticationError() 里打印errorCode。不同厂商的虹膜传感器错误码可能不一样,比如华为是5,三星是7。记录下来,方便适配。
好了,BiometricPrompt的基础用法就这些。说白了就是三步:创建实例、设置回调、启动认证。代码量不大,但细节不少。下一章我们会聊更高级的话题——如何自定义认证对话框,以及处理多设备兼容性。
公众号:蓝海资料掘金营,微信deep3321