一、概述
在开发金融类或涉及隐私的应用时,指纹识别或 Face ID 的身份验证是必不可少的。在 Flutter 中,通常会直接使用官方维护的 local_auth 库来解决这个问题。
不过,这个插件不仅仅是简单的 pub add 那么简单——因为涉及生物识别权限,需要在 Android 和 iOS 的原生配置层做一些调整,否则运行时会直接报错或无法唤起识别界面。
二、环境准备
首先,在项目的 pubspec.yaml 文件中引入 local_auth:
YAML
dependencies:
local_auth: ^latest_version然后执行 flutter pub get 同步依赖。
三、原生配置
原生层的配置是这个插件能否跑通的关键。
1. Android 端配置
Android 端有两个地方需要动手术。
1.1 修改 MainActivity.kt
由于生物识别需要调用系统的 Fragment 机制,默认的 FlutterActivity 可能无法满足需求。需要把 MainActivity 的继承关系改掉。
找到 android/app/src/main/kotlin/.../MainActivity.kt,修改如下:
Kotlin
import io.flutter.embedding.android.FlutterFragmentActivity // 替换掉 FlutterActivity
class MainActivity: FlutterFragmentActivity() { // 替换掉 FlutterActivity
}1.2 配置权限与主题
在 android/app/src/main/AndroidManifest.xml 中,添加生物识别权限:
XML
<manifest ...>
<!-- 添加生物识别权限 -->
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<application ...>
...
</application>
</manifest>另外要注意 Android 的主题配置。如果应用需要更现代的界面交互,建议在 android/app/src/main/res/values/styles.xml 中,将 LaunchTheme 和 NormalTheme 的 parent 属性从 Theme.Light.NoTitleBar 改为 Theme.AppCompat.DayNight:
XML
<resources>
<style name="LaunchTheme" parent="Theme.AppCompat.DayNight">
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<style name="NormalTheme" parent="Theme.AppCompat.DayNight">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>2. iOS 端配置
iOS 端相对简单,但如果不配置 Face ID 的描述文案,调用时应用会直接崩溃。
打开 ios/Runner/Info.plist,在 <dict> 标签内添加以下配置:
XML
<key>NSFaceIDUsageDescription</key>
<string>我们需要使用 Face ID 来确保您的账户安全</string>注意:这里的 string 内容可以根据应用实际需求进行自定义。
四、代码实现
配置完原生环境后,就可以在 Dart 代码里封装一个 BiometricService 来进行调用了:
dart
import 'package:flutter/material.dart';
import 'package:local_auth/local_auth.dart';
import 'package:local_auth_android/local_auth_android.dart';
import 'package:local_auth_ios/local_auth_ios.dart';
class BiometricService {
static final LocalAuthentication localAuth = LocalAuthentication();
/// 执行身份验证
static Future<bool> authenticateLocally() async {
bool isAuthenticate = false;
try {
isAuthenticate = await localAuth.authenticate(
localizedReason: '我们需要验证您的身份以继续使用',
options: const AuthenticationOptions(
stickyAuth: true, // 应用切到后台再切回时,验证不中断
biometricOnly: true, // 只允许生物识别,不允许 PIN 页
sensitiveTransaction: false,
useErrorDialogs: true));
} catch (e) {
// 这里可以根据需要调用全局 Snackbar 提示错误
debugPrint('认证过程中发生错误: $e');
}
return isAuthenticate;
}
/// 检查设备是否支持生物识别
static Future<void> checkBiometrics() async {
try {
final bool canCheck = await localAuth.canCheckBiometrics;
final bool isSupported = await localAuth.isDeviceSupported();
final List<BiometricType> biometrics = await localAuth.getAvailableBiometrics();
debugPrint('================================');
debugPrint('设备支持生物识别: $canCheck');
debugPrint('硬件支持情况: $isSupported');
debugPrint('可用生物识别类型: $biometrics');
debugPrint('================================');
} catch (e) {
debugPrint('检查生物识别时报错: $e');
}
}
}