14、错误码与异常处理:常见错误码列表、异常捕获、用户友好提示

做指纹识别开发,最怕什么?

不是功能实现不了,而是用户在那戳了半天,手机没反应,或者弹个莫名其妙的错误。用户直接懵了,然后给你一个差评。

我早期做的一个项目,就吃过这个亏。那时候刚接触生物识别,觉得能调通接口就万事大吉了。结果上线后,用户反馈“指纹用不了”,排查半天,原来是手机硬件不支持,但我没做任何提示。用户以为手机坏了。

所以,错误码和异常处理,不是可有可无的补充。它是用户体验的最后一道防线。今天我们就来把这套防线彻底建好。

14.1 常见错误码列表

Android 的 BiometricPrompt 在认证失败时,会通过 AuthenticationCallback 返回一个错误码。这些错误码定义在 BiometricConstants 类里。我习惯把它们分成三类:硬件问题、用户操作问题、系统内部问题。

下面这张图,是我自己整理的分类逻辑,你可以参考一下:

生物识别错误码分类 硬件/系统问题 • ERROR_HW_UNAVAILABLE • ERROR_NO_BIOMETRICS • ERROR_HW_NOT_PRESENT • ERROR_VENDOR • ERROR_UNABLE_TO_PROCESS → 提示用户检查硬件或设置 用户操作问题 • ERROR_LOCKOUT • ERROR_LOCKOUT_PERMANENT • ERROR_TIMEOUT • ERROR_USER_CANCELED • ERROR_NEGATIVE_BUTTON → 引导用户等待或重试 系统内部问题 • ERROR_CANCELED • ERROR_VENDOR (部分) • 其他未知错误 • 系统服务崩溃 → 记录日志,尝试恢复

下面我把最常用的几个错误码列出来,并附上我个人的处理建议。

错误码 含义 常见原因 我建议的处理方式
ERROR_NO_BIOMETRICS 设备没有录入任何生物特征 用户未录入指纹/人脸 引导用户去「设置」中录入
ERROR_HW_UNAVAILABLE 硬件暂时不可用 传感器被占用、正在初始化 提示稍后再试,不要频繁重试
ERROR_HW_NOT_PRESENT 设备没有指纹/人脸硬件 低端机、平板不支持 直接隐藏指纹选项,改用密码
ERROR_LOCKOUT 尝试次数过多,暂时锁定 连续失败5次左右 显示倒计时,30秒后自动解锁
ERROR_LOCKOUT_PERMANENT 永久锁定 连续失败太多次 必须用密码/PIN解锁
ERROR_TIMEOUT 操作超时 用户长时间未操作 自动关闭对话框,让用户重新触发
ERROR_USER_CANCELED 用户主动取消 用户点了「取消」或按了返回 无需额外提示,正常结束流程
ERROR_VENDOR 厂商自定义错误 各家手机特有的问题 记录日志,提示「请重试」
💡 我的小技巧: 在开发阶段,我会把 ERROR_VENDOR 的详细信息打印到日志里。因为不同厂商的错误码含义差别很大,比如华为和小米对同一个错误码的解释可能完全不同。上线前,最好找几台主流机型都测一遍。

14.2 异常捕获:别让 App 闪退

说实话,BiometricPrompt 本身不太会抛出运行时异常。但它的回调方法是在主线程执行的。如果你在回调里做了耗时操作,或者不小心抛了个 NullPointerException,那 App 直接就崩了。

我曾经就犯过这个错。在 onAuthenticationError 里更新 UI,结果那个 View 已经被销毁了,直接闪退。用户一脸懵逼。

所以,我现在的做法是:所有回调方法里,都包一层 try-catch。尤其是 onAuthenticationErroronAuthenticationFailed

来看一个我常用的模板:

private final BiometricPrompt.AuthenticationCallback callback =
    new BiometricPrompt.AuthenticationCallback() {

    @Override
    public void onAuthenticationError(int errorCode, CharSequence errString) {
        try {
            // 先检查 Activity 是否存活
            if (isDestroyed() || isFinishing()) {
                return;
            }
            handleError(errorCode, errString);
        } catch (Exception e) {
            // 兜底:记录日志,不要崩溃
            Log.e("Biometric", "onAuthenticationError异常", e);
        }
    }

    @Override
    public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) {
        try {
            // 处理成功逻辑
            onBiometricSuccess();
        } catch (Exception e) {
            Log.e("Biometric", "onAuthenticationSucceeded异常", e);
        }
    }

    @Override
    public void onAuthenticationFailed() {
        try {
            // 指纹不匹配,提示用户
            showFailedMessage();
        } catch (Exception e) {
            Log.e("Biometric", "onAuthenticationFailed异常", e);
        }
    }
};
⚠️ 注意: 不要在所有地方都 try-catch。比如 onAuthenticationSucceeded 里的业务逻辑,如果出错了,应该让开发者看到崩溃日志,而不是静默吞掉。我这里的 try-catch 只是为了保护 UI 操作不导致闪退。

14.3 用户友好提示:别让用户猜

错误码是给开发者看的。用户不需要知道 ERROR_LOCKOUT 是什么。他们只想知道:现在该怎么办?

我总结了一个原则:提示信息要包含「原因 + 行动」。比如:

  • ❌ 错误:ERROR_HW_UNAVAILABLE
  • ✅ 友好提示:「指纹传感器暂时不可用,请稍后再试」

再比如:

  • ❌ 错误:ERROR_NO_BIOMETRICS
  • ✅ 友好提示:「您还没有录入指纹,请前往设置添加」

下面是我项目中实际用到的提示文案,你可以直接参考:

错误码 用户提示文案 附加操作
ERROR_NO_BIOMETRICS 「未录入指纹,是否前往设置添加?」 提供「去设置」按钮,跳转指纹录入页
ERROR_HW_UNAVAILABLE 「指纹识别暂时不可用,请稍后重试」 自动关闭对话框,3秒后可重新触发
ERROR_LOCKOUT 「尝试次数过多,请30秒后再试」 显示倒计时,倒计时结束后自动恢复
ERROR_LOCKOUT_PERMANENT 「指纹已被锁定,请使用密码验证」 自动切换到密码输入界面
ERROR_TIMEOUT 「操作超时,请重新尝试」 自动关闭对话框,无额外操作
ERROR_USER_CANCELED 不提示(用户主动取消) 正常结束流程
ERROR_VENDOR 「指纹识别异常,请重试」 记录日志,方便排查
🎯 核心思路: 错误提示要「软」。不要用红色大叉,不要用刺耳的提示音。用温和的 Toast 或者 Dialog,让用户感觉「只是暂时不行,不是手机坏了」。

14.4 避坑指南:我踩过的几个坑

最后,分享几个我实际项目中遇到的坑,希望能帮你省点时间。

  • 坑一: 我曾经在 onAuthenticationError 里直接弹 Dialog,结果因为 Activity 已经 onPause,Dialog 弹不出来,还报了 WindowManager.BadTokenException。解决方案:弹 Dialog 前先检查 Activity 状态。
  • 坑二: 有些手机在 ERROR_HW_UNAVAILABLE 之后,会连续回调多次。如果你不做去重处理,用户会看到一堆提示。我习惯用一个标志位 isErrorHandled 来控制。
  • 坑三: ERROR_LOCKOUT_PERMANENT 在不同厂商手机上触发条件不一样。有的手机连续失败5次就永久锁定,有的要10次。所以,不要硬编码次数,而是根据错误码来响应。

嗯,错误码这块其实不难,但细节很多。你只要把每个错误码对应的用户提示都写好,再包一层 try-catch,基本就稳了。下次用户再遇到问题,至少不会一脸茫然地来骂你。


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