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 版本检测策略
版本检测,说白了就是两件事:
- 判断当前Android版本
- 根据版本选择不同的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指纹版本适配的核心逻辑。你看一遍就能记住:
16.6 总结
版本适配这件事,没有捷径。我的经验是:
- 能用兼容性库,就别自己写版本判断
- 必须自己写版本判断时,用SDK_INT,别用RELEASE
- Android 11.0以上,忘掉FingerprintManager
- Android 9.0-10.0,注意屏下指纹的特殊处理
- Android 14.0,别忘了setAllowedAuthenticators()
嗯,这些坑我都踩过。希望你能一次避开。