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() 启动系统认证对话框

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 核心流程图

下面这张图,是我自己画的一个流程。你看一眼就能明白整个认证的生命周期:

BiometricPrompt 虹膜认证流程 1. 创建实例 new BiometricPrompt() 2. 设置回调 AuthenticationCallback 3. 启动认证 authenticate() 系统认证对话框 用户对准摄像头 ✅ 认证成功 onAuthenticationSucceeded() ❌ 认证失败 onAuthenticationFailed() ⚠️ 不可恢复错误 onAuthenticationError()

4.6 避坑指南

  • 我曾经遇到过:在 onAuthenticationFailed() 里直接弹Dialog,结果用户连续失败5次后系统锁定了,Dialog却还在。正确的做法是监听 onAuthenticationError() 并关闭所有认证UI。
  • 注意线程:回调默认在传入的Executor上执行。如果你传了后台线程,记得切回主线程更新UI。我建议直接用主线程Executor,省心。
  • PromptInfo的setTitle不能为空:系统要求至少设置标题,否则会抛IllegalArgumentException。嗯,这个坑我踩过两次。
调试小技巧: 在开发阶段,可以在 onAuthenticationError() 里打印errorCode。不同厂商的虹膜传感器错误码可能不一样,比如华为是5,三星是7。记录下来,方便适配。

好了,BiometricPrompt的基础用法就这些。说白了就是三步:创建实例、设置回调、启动认证。代码量不大,但细节不少。下一章我们会聊更高级的话题——如何自定义认证对话框,以及处理多设备兼容性。


公众号:蓝海资料掘金营,微信deep3321