5、认证回调详解:onAuthenticationSucceeded、onAuthenticationFailed、onAuthenticationError、onAuthenticationHelp、回调线程与UI更新

好,咱们接着聊。上一章我们把 BiometricPrompt 的构建和启动讲清楚了,但说实话,那只是搭了个台子。真正唱戏的,是这几个回调方法。你想想看,用户把手指按上去,系统怎么告诉你结果?就是靠这些回调。

我个人习惯把回调分成两类:成功类失败/异常类。咱们一个一个过,每个我都会结合项目里的坑来讲。

5.1 onAuthenticationSucceeded —— 最让人开心的回调

这个方法被调用,意味着指纹匹配成功,用户身份验证通过。代码很简单:

@Override
public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
    // 用户验证成功
    showMessage("指纹识别成功");
    // 解锁应用或执行敏感操作
    unlockApp();
}

这里有个细节,AuthenticationResult 对象里其实藏着一些信息。比如 result.getAuthenticationType(),它可以告诉你用户是用指纹、人脸还是虹膜验证的。我在项目中遇到过需要区分验证方式的场景——某些金融类 App 对指纹和人脸的信任等级不一样,这时候这个返回值就派上用场了。

小提示:onAuthenticationSucceeded 调用后,BiometricPrompt 会自动停止监听。如果你想继续验证(比如多指录入场景),需要重新创建并启动 BiometricPrompt 实例。

5.2 onAuthenticationFailed —— 最常见的"不匹配"

这个回调在指纹匹配失败时触发。注意,它和 onAuthenticationError 有本质区别:Failed 只是匹配不成功,系统还在继续监听;Error 是系统出问题了,监听已经停止。

@Override
public void onAuthenticationFailed() {
    // 指纹不匹配,但可以继续尝试
    showMessage("指纹不匹配,请重试");
    // 可以在这里做震动反馈
    performHapticFeedback();
}

嗯,这里要注意。onAuthenticationFailed 不会自动停止指纹传感器。用户连续按 5 次失败后,系统才会触发 onAuthenticationError,并锁定传感器一段时间。我曾经在项目里踩过这个坑——用户连续失败后,我还在界面上显示"请重试",结果传感器已经锁了,用户怎么按都没反应。后来我加了个计数器,连续失败 3 次就提示用户用备用方式登录。

避坑指南:不要依赖 onAuthenticationFailed 来做次数限制。系统内部有自己的失败计数逻辑,不同厂商的阈值可能不一样。我曾经见过某款手机连续失败 4 次就锁了,而标准 Android 是 5 次。

5.3 onAuthenticationError —— 出大事了

这个回调表示发生了不可恢复的错误,指纹传感器已经停止工作。常见的错误码有:

错误码 含义 常见原因
BIOMETRIC_ERROR_HW_UNAVAILABLE 硬件不可用 传感器被占用或损坏
BIOMETRIC_ERROR_NO_BIOMETRICS 未录入指纹 用户没在设置里录指纹
BIOMETRIC_ERROR_LOCKOUT 锁定 连续失败次数过多
BIOMETRIC_ERROR_USER_CANCELED 用户取消 用户点了取消按钮
@Override
public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
    // 传感器已停止,需要处理错误
    switch (errorCode) {
        case BiometricPrompt.BIOMETRIC_ERROR_LOCKOUT:
            showMessage("指纹已锁定,请使用密码登录");
            showPasswordLogin();
            break;
        case BiometricPrompt.BIOMETRIC_ERROR_USER_CANCELED:
            // 用户主动取消,不做特殊处理
            break;
        default:
            showMessage("指纹识别出错: " + errString);
            break;
    }
}

我个人习惯在 onAuthenticationError 里做两件事:一是给用户明确的提示,二是提供备用验证方案。你想想看,用户指纹被锁了,你总不能让他干等着吧?

5.4 onAuthenticationHelp —— 容易被忽略的"小提示"

这个回调很有意思。它表示指纹传感器还在工作,但遇到了一些小问题,需要用户调整。比如手指移动太快、传感器有污渍等。

@Override
public void onAuthenticationHelp(int helpCode, @NonNull CharSequence helpString) {
    // 传感器还在工作,但需要用户配合
    showMessage(helpString);  // 直接显示系统提供的提示文字
    // 比如:"手指移动太快"、"请覆盖整个传感器"
}

说实话,很多开发者直接忽略这个回调。但我建议你好好利用它。我在项目中遇到过用户反复失败的情况,后来发现是传感器上有汗渍。系统通过 onAuthenticationHelp 提示了"传感器不干净",但我们的 UI 没显示出来,用户就一直擦手指,越擦越油。后来我把 helpString 直接显示在界面上,问题就解决了。

核心要点:onAuthenticationHelp 的 helpString 是系统提供的本地化文字,直接显示给用户看就行,别自己瞎翻译。

5.5 回调线程与UI更新 —— 最容易出bug的地方

好,这是个大坑。所有回调方法默认在什么线程执行?答案是:取决于你创建 BiometricPrompt 时传入的 Handler

如果你没传 Handler,回调会在主线程执行。如果你传了 Handler,回调就在那个 Handler 绑定的线程执行。看代码:

// 方式一:不传 Handler,回调在主线程
BiometricPrompt prompt = new BiometricPrompt(this, executor, callback);

// 方式二:传 Handler,回调在指定线程
Handler backgroundHandler = new Handler(backgroundThread.getLooper());
BiometricPrompt prompt = new BiometricPrompt(this, backgroundHandler, callback);

我个人强烈建议:永远在主线程处理回调。为什么?因为回调里你大概率要更新 UI——显示成功/失败提示、更新指纹图标、跳转页面等。这些操作必须在主线程做。

如果你非要在后台线程处理回调,那更新 UI 时记得切回主线程:

@Override
public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) {
    // 当前在后台线程
    runOnUiThread(() -> {
        // 更新 UI
        showSuccessAnimation();
    });
}

我曾经在项目里犯过这个错——回调里直接更新 TextView,结果在 Android 7.0 上偶尔崩溃,因为某些厂商的 BiometricPrompt 实现把回调抛到了子线程。后来我统一加了个 runOnUiThread,世界清净了。

警告:不要在回调里做耗时操作!比如网络请求、数据库写入等。这些回调应该轻量、快速返回。如果你需要做耗时操作,请另开线程或使用协程。

5.6 知识体系总览

说了这么多,咱们用一张图把回调的完整流程串起来:

生物识别认证回调流程 用户触摸传感器 系统指纹匹配处理 onAuthenticationSucceeded onAuthenticationFailed onAuthenticationHelp onAuthenticationError

从图上可以看得很清楚:用户触摸后,系统开始匹配。匹配成功走绿色分支,匹配失败走红色分支,需要用户调整走黄色分支。只有 onAuthenticationError 是终点——它表示整个认证流程结束了。

好了,回调这块就讲这么多。记住一句话:成功回调要处理结果,失败回调要引导用户,错误回调要提供备选方案,帮助回调要显示提示文字。线程问题统一用主线程处理,别给自己挖坑。


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