16、Android版本适配:Android 6.0-14.0指纹API变化、行为变更、兼容性库使用、版本检测策略

做指纹认证开发,最头疼的是什么?

我个人觉得,不是算法难,也不是UI复杂。而是版本适配。Android从6.0到14.0,指纹相关的API改了至少三轮。你想想看,一个项目要兼容到Android 6.0,又要支持最新的Android 14.0,代码里全是版本判断,稍不留神就崩了。

我在项目中遇到过好几次,用户反馈「指纹用不了」,结果一查,是API调用方式在新版本上废弃了。嗯,今天我们就来彻底捋清楚这件事。

16.1 指纹API的三大阶段

Android指纹API的演进,说白了可以分为三个阶段:

阶段 Android版本 核心API 状态
第一阶段 6.0 - 8.1 FingerprintManager 已废弃
第二阶段 9.0 - 10.0 BiometricPrompt(无被动指纹) 过渡期
第三阶段 11.0+ BiometricPrompt(完整版) 推荐使用

为什么会这样?因为Google发现,指纹只是生物识别的一种。人脸、虹膜、甚至声纹,都需要统一的认证入口。所以从Android 9.0开始,BiometricPrompt逐渐取代了FingerprintManager。

核心原则:如果你的minSdkVersion >= 28(Android 9.0),请直接使用BiometricPrompt。不要再用FingerprintManager了。

16.2 各版本关键变更点

我们一个一个版本来看。我挑重点说,那些不痛不痒的变更就不提了。

Android 6.0(API 23)

指纹认证的起点。FingerprintManager首次出现。注意,这时候还没有加密对象的概念,直接回调认证结果。安全性其实一般。

Android 7.0(API 24)

没有重大API变更。但有个行为变化:系统级指纹录入界面改版了。嗯,这个跟开发者关系不大。

Android 8.0(API 26)

增加了FingerprintManager的加密对象支持。你可以把指纹认证和CryptoObject绑定,提升安全性。我在项目中遇到过,如果不绑定CryptoObject,某些厂商的定制ROM会直接拒绝认证。

Android 9.0(API 28)

重大转折点。BiometricPrompt来了,但注意——这时候的BiometricPrompt不支持被动指纹(也就是屏幕下指纹)。如果你要做屏下指纹,还得用FingerprintManager。这很尴尬,对吧?

Android 10.0(API 29)

BiometricPrompt增加了被动指纹支持。但有个坑:部分厂商的屏下指纹实现仍然不走BiometricPrompt,而是走厂商私有API。我曾经被这个坑过,用户说「我手机支持屏下指纹,但App用不了」,一查是厂商没适配。

Android 11.0(API 30)

FingerprintManager正式废弃。所有指纹认证都应该走BiometricPrompt。同时,BiometricPrompt增加了安全性等级的概念:BIOMETRIC_STRONG和BIOMETRIC_WEAK。

Android 12.0(API 31)

增加了BIOMETRIC_STRONG_OR_BETTER?没有,还是那两个等级。但行为上有变化:系统会弹出一个更统一的认证对话框,开发者自定义UI的空间被压缩了。

Android 13.0(API 33)

增加了对多生物识别传感器的支持。比如手机既有指纹又有人脸,系统可以自动选择。开发者不需要额外处理。

Android 14.0(API 34)

主要是安全增强。BiometricPrompt现在要求必须显示认证原因。你不能默默地在后台认证了。嗯,这个对用户体验有影响,需要注意。

警告:Android 14.0开始,如果不在BiometricPrompt.Builder中设置setAllowedAuthenticators(),默认行为会发生变化。请务必显式设置。

16.3 兼容性库的使用

说了这么多版本差异,怎么统一处理?答案是:用AndroidX Biometric库。

我个人习惯,只要项目minSdkVersion <= 28,就引入androidx.biometric。它帮你封装了所有版本差异。

// build.gradle
implementation 'androidx.biometric:biometric:1.2.0-alpha05'

使用方式也很统一:

BiometricPrompt biometricPrompt = new BiometricPrompt(
    activity,
    executor,
    new BiometricPrompt.AuthenticationCallback() {
        @Override
        public void onAuthenticationSucceeded(
            @NonNull BiometricPrompt.AuthenticationResult result) {
            // 认证成功
        }
    }
);

BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
    .setTitle("指纹认证")
    .setSubtitle("请验证您的指纹")
    .setNegativeButtonText("取消")
    .build();

biometricPrompt.authenticate(promptInfo);

你看,代码很简洁。兼容性库帮你处理了:

  • Android 6.0-8.1:内部使用FingerprintManager
  • Android 9.0-10.0:内部使用BiometricPrompt(旧版)
  • Android 11.0+:内部使用BiometricPrompt(新版)

提示:兼容性库的1.2.0版本开始,支持了被动指纹的检测。如果你需要判断设备是否支持屏下指纹,可以用BiometricManager.canAuthenticate()。

16.4 版本检测策略

版本检测,说白了就是两件事:

  1. 判断当前Android版本
  2. 根据版本选择不同的API调用方式

我建议用Build.VERSION.SDK_INT来做判断,不要用Build.VERSION.RELEASE。为什么?因为RELEASE是字符串,解析起来麻烦,而且某些厂商会篡改。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    // Android 11.0+,直接使用BiometricPrompt
    useBiometricPrompt();
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    // Android 9.0-10.0,使用BiometricPrompt但注意被动指纹
    if (isUnderDisplayFingerprint()) {
        useFingerprintManager();
    } else {
        useBiometricPrompt();
    }
} else {
    // Android 6.0-8.1,使用FingerprintManager
    useFingerprintManager();
}

这段代码看起来简单,但实际项目中要复杂得多。我曾经在一个项目中,因为没判断屏下指纹的情况,导致某款小米手机的用户无法使用指纹。后来加上了isUnderDisplayFingerprint()的判断才解决。

避坑指南:我曾经在Android 12.0上遇到一个bug——BiometricPrompt的authenticate()方法在某些定制ROM上会直接返回onAuthenticationError,错误码是5(ERROR_LOCKOUT)。后来发现是厂商的指纹驱动没适配。解决方案是:在onAuthenticationError中判断错误码,如果是5,就提示用户稍后再试,而不是直接报错。

16.5 知识体系总览

下面这张图,是我整理的Android指纹版本适配的核心逻辑。你看一遍就能记住:

Android指纹版本适配核心逻辑 Android 6.0-8.1 Android 9.0-10.0 Android 11.0+ FingerprintManager BiometricPrompt(旧) BiometricPrompt(新) AndroidX Biometric 兼容性库 版本检测 + 特性检测 核心思路:统一入口 + 版本分支 + 兼容库兜底

16.6 总结

版本适配这件事,没有捷径。我的经验是:

  • 能用兼容性库,就别自己写版本判断
  • 必须自己写版本判断时,用SDK_INT,别用RELEASE
  • Android 11.0以上,忘掉FingerprintManager
  • Android 9.0-10.0,注意屏下指纹的特殊处理
  • Android 14.0,别忘了setAllowedAuthenticators()

嗯,这些坑我都踩过。希望你能一次避开。