Flutter本地身份验证插件local_auth的使用
Flutter本地身份验证插件local_auth的使用
local_auth
是一个Flutter插件,用于执行设备上的本地认证。这包括通过指纹或面部识别等生物特征进行认证。
支持平台
平台 | 版本要求 |
---|---|
Android | SDK 16+ |
iOS | 12.0+ |
macOS | 10.14+ |
Windows | Windows 10+ |
使用方法
设备能力检查
要检查设备是否支持本地认证(如果需要生物特征支持),可以调用 canCheckBiometrics
和/或 isDeviceSupported()
方法:
final LocalAuthentication auth = LocalAuthentication();
final bool canAuthenticateWithBiometrics = await auth.canCheckBiometrics;
final bool canAuthenticate =
canAuthenticateWithBiometrics || await auth.isDeviceSupported();
已注册的生物特征
canCheckBiometrics
只表示硬件支持情况,不表示设备是否有任何已注册的生物特征。要获取已注册的生物特征列表,可以调用 getAvailableBiometrics()
方法:
final List<BiometricType> availableBiometrics = await auth.getAvailableBiometrics();
if (availableBiometrics.isNotEmpty) {
// Some biometrics are enrolled.
}
if (availableBiometrics.contains(BiometricType.strong) ||
availableBiometrics.contains(BiometricType.face)) {
// Specific types of biometrics are available.
}
认证选项
authenticate()
方法在可能的情况下使用生物特征认证,但也允许回退到PIN码、图案或密码。为了仅要求生物特征认证,可以通过传递 AuthenticationOptions
并将 biometricOnly
设置为 true
来实现:
final bool didAuthenticate = await auth.authenticate(
localizedReason: 'Please authenticate to show account balance',
options: const AuthenticationOptions(biometricOnly: true));
自定义对话框消息
可以通过传递 AuthMessages
来自定义每个平台的对话框消息:
import 'package:local_auth_android/local_auth_android.dart';
import 'package:local_auth_darwin/local_auth_darwin.dart';
final bool didAuthenticate = await auth.authenticate(
localizedReason: 'Please authenticate to show account balance',
authMessages: const <AuthMessages>[
AndroidAuthMessages(
signInTitle: 'Oops! Biometric authentication required!',
cancelButton: 'No thanks',
),
IOSAuthMessages(
cancelButton: 'No thanks',
),
]);
异常处理
authenticate
在许多错误情况下会抛出 PlatformException
。可以参考 error_codes.dart
中的已知错误代码来处理特定的错误:
try {
final bool didAuthenticate = await auth.authenticate(
localizedReason: 'Please authenticate to show account balance',
options: const AuthenticationOptions(useErrorDialogs: false));
} on PlatformException catch (e) {
if (e.code == auth_error.notEnrolled) {
// Handle no hardware.
} else if (e.code == auth_error.lockedOut ||
e.code == auth_error.permanentlyLockedOut) {
// Handle lockout.
}
}
示例代码
以下是一个完整的示例应用,展示了如何使用 local_auth
插件:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:local_auth/local_auth.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final LocalAuthentication auth = LocalAuthentication();
_SupportState _supportState = _SupportState.unknown;
bool? _canCheckBiometrics;
List<BiometricType>? _availableBiometrics;
String _authorized = 'Not Authorized';
bool _isAuthenticating = false;
@override
void initState() {
super.initState();
auth.isDeviceSupported().then(
(bool isSupported) => setState(() => _supportState = isSupported
? _SupportState.supported
: _SupportState.unsupported),
);
}
Future<void> _checkBiometrics() async {
late bool canCheckBiometrics;
try {
canCheckBiometrics = await auth.canCheckBiometrics;
} on PlatformException catch (e) {
canCheckBiometrics = false;
print(e);
}
if (!mounted) {
return;
}
setState(() {
_canCheckBiometrics = canCheckBiometrics;
});
}
Future<void> _getAvailableBiometrics() async {
late List<BiometricType> availableBiometrics;
try {
availableBiometrics = await auth.getAvailableBiometrics();
} on PlatformException catch (e) {
availableBiometrics = <BiometricType>[];
print(e);
}
if (!mounted) {
return;
}
setState(() {
_availableBiometrics = availableBiometrics;
});
}
Future<void> _authenticate() async {
bool authenticated = false;
try {
setState(() {
_isAuthenticating = true;
_authorized = 'Authenticating';
});
authenticated = await auth.authenticate(
localizedReason: 'Let OS determine authentication method',
options: const AuthenticationOptions(
stickyAuth: true,
),
);
setState(() {
_isAuthenticating = false;
});
} on PlatformException catch (e) {
print(e);
setState(() {
_isAuthenticating = false;
_authorized = 'Error - ${e.message}';
});
return;
}
if (!mounted) {
return;
}
setState(
() => _authorized = authenticated ? 'Authorized' : 'Not Authorized');
}
Future<void> _authenticateWithBiometrics() async {
bool authenticated = false;
try {
setState(() {
_isAuthenticating = true;
_authorized = 'Authenticating';
});
authenticated = await auth.authenticate(
localizedReason:
'Scan your fingerprint (or face or whatever) to authenticate',
options: const AuthenticationOptions(
stickyAuth: true,
biometricOnly: true,
),
);
setState(() {
_isAuthenticating = false;
_authorized = 'Authenticating';
});
} on PlatformException catch (e) {
print(e);
setState(() {
_isAuthenticating = false;
_authorized = 'Error - ${e.message}';
});
return;
}
if (!mounted) {
return;
}
final String message = authenticated ? 'Authorized' : 'Not Authorized';
setState(() {
_authorized = message;
});
}
Future<void> _cancelAuthentication() async {
await auth.stopAuthentication();
setState(() => _isAuthenticating = false);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: ListView(
padding: const EdgeInsets.only(top: 30),
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
if (_supportState == _SupportState.unknown)
const CircularProgressIndicator()
else if (_supportState == _SupportState.supported)
const Text('This device is supported')
else
const Text('This device is not supported'),
const Divider(height: 100),
Text('Can check biometrics: $_canCheckBiometrics\n'),
ElevatedButton(
onPressed: _checkBiometrics,
child: const Text('Check biometrics'),
),
const Divider(height: 100),
Text('Available biometrics: $_availableBiometrics\n'),
ElevatedButton(
onPressed: _getAvailableBiometrics,
child: const Text('Get available biometrics'),
),
const Divider(height: 100),
Text('Current State: $_authorized\n'),
if (_isAuthenticating)
ElevatedButton(
onPressed: _cancelAuthentication,
child: const Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text('Cancel Authentication'),
Icon(Icons.cancel),
],
),
)
else
Column(
children: <Widget>[
ElevatedButton(
onPressed: _authenticate,
child: const Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text('Authenticate'),
Icon(Icons.perm_device_information),
],
),
),
ElevatedButton(
onPressed: _authenticateWithBiometrics,
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(_isAuthenticating
? 'Cancel'
: 'Authenticate: biometrics only'),
const Icon(Icons.fingerprint),
],
),
),
],
),
],
),
],
),
),
);
}
}
enum _SupportState {
unknown,
supported,
unsupported,
}
平台集成
iOS 集成
如果要使用 Face ID,需要在 Info.plist
文件中添加以下内容:
<key>NSFaceIDUsageDescription</key>
<string>Why is my app authenticating using face id?</string>
Android 集成
活动更改
local_auth
要求使用 FragmentActivity
而不是 Activity
。更新你的应用程序:
- 如果你直接使用
FlutterActivity
,请将其更改为FlutterFragmentActivity
。 - 如果你使用自定义活动,请更新
MainActivity.java
或MainActivity.kt
继承自FlutterFragmentActivity
。
权限
在项目的 AndroidManifest.xml
文件中添加 USE_BIOMETRIC
权限:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.app">
<uses-permission android:name="android.permission.USE_BIOMETRIC"/>
</manifest>
兼容性
对于低于 Android Q 的版本,不要调用 getAvailableBiometrics
。而是调用 authenticate
并设置 biometricOnly: true
。
Android 主题
确保 LaunchTheme
的父级是有效的 Theme.AppCompat
主题,以防止 Android 8 及以下版本崩溃。例如,使用 Theme.AppCompat.DayNight
启用浅色/深色模式。
<style name="LaunchTheme" parent="Theme.AppCompat.DayNight">
...
</style>
Sticky Auth
你可以将 stickyAuth
选项设置为 true
,以便插件在应用程序被系统置于后台时不会返回失败结果。这可能会发生在用户在有机会认证之前接收到电话时。如果 stickyAuth
设置为 false
,这将导致插件返回失败结果给 Dart 应用程序。如果设置为 true
,插件将在应用程序恢复时重试认证。
更多关于Flutter本地身份验证插件local_auth的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter本地身份验证插件local_auth的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter应用中使用local_auth
插件进行本地身份验证(如指纹或面部识别)的示例代码。这个示例将展示如何请求用户进行身份验证并处理结果。
首先,你需要在你的pubspec.yaml
文件中添加local_auth
依赖:
dependencies:
flutter:
sdk: flutter
local_auth: ^1.0.0 # 请使用最新版本号
然后运行flutter pub get
来安装依赖。
接下来,在你的Flutter项目中,你可以按照以下方式使用local_auth
插件:
import 'package:flutter/material.dart';
import 'package:local_auth/local_auth.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Local Authentication Example'),
),
body: Center(
child: LocalAuthExample(),
),
),
);
}
}
class LocalAuthExample extends StatefulWidget {
@override
_LocalAuthExampleState createState() => _LocalAuthExampleState();
}
class _LocalAuthExampleState extends State<LocalAuthExample> {
bool _canCheckBiometrics = false;
String _authenticatedMessage = '';
@override
void initState() {
super.initState();
_checkBiometrics();
}
Future<void> _checkBiometrics() async {
bool canCheckBiometrics;
LocalAuthentication auth = LocalAuthentication();
try {
canCheckBiometrics = await auth.canCheckBiometrics;
} catch (e) {
print("Error checking biometrics: $e");
canCheckBiometrics = false;
}
if (!mounted) return;
setState(() {
_canCheckBiometrics = canCheckBiometrics;
});
}
Future<void> _authenticate() async {
setState(() {
_authenticatedMessage = '';
});
bool authenticated = false;
LocalAuthentication auth = LocalAuthentication();
try {
authenticated = await auth.authenticateWithBiometrics(
localizedReason: 'Please authenticate to continue',
useErrorDialogs: true,
stickyAuth: true,
);
} catch (e) {
print("Authentication failed: $e");
}
if (!mounted) return;
setState(() {
_authenticatedMessage = authenticated
? 'Authenticated successfully!'
: 'Authentication failed.';
});
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Can check biometrics: $_canCheckBiometrics'),
SizedBox(height: 20),
ElevatedButton(
onPressed: _canCheckBiometrics ? _authenticate : null,
child: Text('Authenticate'),
),
SizedBox(height: 20),
Text(_authenticatedMessage),
],
);
}
}
在这个示例中,我们创建了一个简单的Flutter应用,该应用具有以下几个功能:
-
检查设备是否支持生物识别:在
_checkBiometrics
方法中,我们使用LocalAuthentication
类的canCheckBiometrics
属性来检查设备是否支持生物识别功能。 -
显示生物识别支持状态:我们根据
_canCheckBiometrics
的值在界面上显示设备是否支持生物识别。 -
进行身份验证:在
_authenticate
方法中,我们使用authenticateWithBiometrics
方法来请求用户进行身份验证。如果身份验证成功,则显示“Authenticated successfully!”消息;如果失败,则显示“Authentication failed.”消息。 -
按钮控制:如果设备支持生物识别,则“Authenticate”按钮可以点击;否则,按钮将不可点击。
这个示例应该可以帮助你快速上手local_auth
插件的使用。你可以根据实际需求进一步扩展和修改这个示例。