Flutter无界面本地认证插件flutter_local_auth_invisible的使用

发布于 1周前 作者 ionicwang 来自 Flutter

Flutter无界面本地认证插件 flutter_local_auth_invisible 的使用

flutter_local_auth_invisible 是官方 local_auth 插件的一个分支,提供了在设备上进行本地用户身份验证的功能。它支持 iOS 上的生物识别(Touch ID 或锁屏密码)和 Android 6.0 及以上版本中的指纹 API。

功能特点

  • 支持 Face ID 和指纹识别。
  • 在 Android 上可以自定义 UI,因为它会抑制标准的系统级指纹认证对话框。
  • 提供默认的错误提示对话框,也可以关闭这些对话框并自行处理错误。

使用示例

导入包

首先,在 Dart 文件中导入该插件:

import 'package:flutter_local_auth_invisible/flutter_local_auth_invisible.dart';

检查设备是否支持生物识别

可以通过调用 canCheckBiometrics 方法来检查设备是否支持生物识别:

bool canCheckBiometrics = await LocalAuthentication.canCheckBiometrics;

获取已注册的生物识别类型

通过调用 getAvailableBiometrics 方法获取当前设备上已注册的生物识别类型:

List<BiometricType> availableBiometrics = await LocalAuthentication.getAvailableBiometrics();
if (availableBiometrics.contains(BiometricType.face)) {
  // Face ID.
} else if (availableBiometrics.contains(BiometricType.fingerprint)) {
  // Touch ID.
}

触发生物识别认证

使用默认对话框触发生物识别认证:

bool didAuthenticate = await LocalAuthentication.authenticateWithBiometrics(
  localizedReason: 'Please authenticate to show account balance',
);

如果不想使用默认对话框,可以将 useErrorDialogs 设置为 false

bool didAuthenticate = await LocalAuthentication.authenticateWithBiometrics(
  localizedReason: 'Please authenticate to show account balance',
  useErrorDialogs: false,
);

你还可以自定义 iOS 的对话框消息:

import 'package:local_auth/auth_strings.dart';

const iosStrings = const IOSAuthMessages(
  cancelButton: 'cancel',
  goToSettingsButton: 'settings',
  goToSettingsDescription: 'Please set up your Touch ID.',
  lockOut: 'Please reenable your Touch ID',
);
await LocalAuthentication.authenticateWithBiometrics(
  localizedReason: 'Please authenticate to show account balance',
  iOSAuthStrings: iosStrings,
  useErrorDialogs: false,
);

停止认证

在 Android 上,你可以手动停止认证:

void _cancelAuthentication() {
    LocalAuthentication.stopAuthentication();
}

异常处理

该插件可能抛出以下几种异常:PasscodeNotSet, NotEnrolled, NotAvailable, 和 OtherOperatingSystem。它们都被封装在 LocalAuthenticationError 类中。例如:

import 'package:flutter/services.dart';
import 'package:local_auth/error_codes.dart' as auth_error;

try {
  bool didAuthenticate = await LocalAuthentication.authenticate(
    localizedReason: 'Please authenticate to show account balance',
  );
} on PlatformException catch (e) {
  if (e.code == auth_error.notAvailable) {
    // Handle this exception here.
  }
}

平台集成

iOS 集成

Info.plist 文件中添加以下内容以支持 Face ID:

<key>NSFaceIDUsageDescription</key>
<string>Why is my app authenticating using face id?</string>

Android 集成

AndroidManifest.xml 文件中添加以下权限:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.app">
  <uses-permission android:name="android.permission.USE_FINGERPRINT"/>
</manifest>

完整示例 Demo

以下是一个完整的示例应用,展示了如何使用 flutter_local_auth_invisible 插件进行生物识别认证:

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_local_auth_invisible/flutter_local_auth_invisible.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  [@override](/user/override)
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String _authorized = 'Not Authorized';

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: [
            Text(
              'Can ${AuthProviderState.biometricsEnabled ? '' : 'not '}'
              'auth with biometrics',
            ),
            Text('Current State: $_authorized\n'),
            AuthProvider(
              'hash',
              onSuccess: () => setState(
                () => _authorized = 'Authorized',
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class AuthProvider extends StatefulWidget {
  const AuthProvider(
    this.pinHash, {
    this.onFinishChecking,
    this.onStartChecking,
    this.onSuccess,
  });
  final Function()? onFinishChecking;
  final Function()? onStartChecking;
  final Function()? onSuccess;
  final String pinHash;

  [@override](/user/override)
  AuthProviderState createState() => AuthProviderState();
}

class AuthProviderState extends State<AuthProvider> {
  static bool biometricsEnabled = false;
  bool _biometricsSelected = true;
  List<BiometricType> _biometricSensors = [];
  String? _biometricsIcon;

  [@override](/user/override)
  void initState() {
    super.initState();
    WidgetsBinding.instance!.addPostFrameCallback((_) => _init());
  }

  Future<void> _init() async {
    _biometricSensors = await LocalAuthentication.getAvailableBiometrics();
    biometricsEnabled = (await LocalAuthentication.canCheckBiometrics) &&
        _biometricSensors.isNotEmpty;
    _biometricsIcon = _biometricSensors.contains(BiometricType.face)
        ? 'ui.faceId'
        : 'ui.fingerprint';
    setState(() {});
    await _launchScannerSchedule();
  }

  [@override](/user/override)
  void didUpdateWidget(oldWidget) {
    _launchScannerSchedule();
    super.didUpdateWidget(oldWidget);
  }

  [@override](/user/override)
  Widget build(BuildContext context) => Column(
        children: [
          biometricsEnabled && _biometricsSelected
              ? Text('BiometricsView()')
              : Text('PinPadView()'),
          TextButton(
            onPressed: _toggleView,
            child: Text('Toggle auth method'),
          ),
        ],
      );

  Future<void> _launchScannerSchedule() async {
    if (!biometricsEnabled) return;

    await LocalAuthentication.stopAuthentication();
    await Future.delayed(const Duration(milliseconds: 300), _launchScanner);
  }

  Future<void> _launchScanner() async {
    try {
      while (_biometricsSelected) {
        final didAuthenticate = await LocalAuthentication.authenticate(
          localizedReason:
              'Please pass the biometrical authentication to continue.',
          stickyAuth: false,
          useErrorDialogs: true,
        );
        if (didAuthenticate) {
          widget.onSuccess?.call();
          break;
        } else {
          await Future.delayed(const Duration(milliseconds: 500));
        }
      }
    } on PlatformException catch (_) {
      // Report the issue
    }
  }

  void _toggleView() {
    setState(() => _biometricsSelected = !_biometricsSelected);
    if (_biometricsSelected) {
      _launchScanner();
    } else {
      LocalAuthentication.stopAuthentication();
    }
  }
}

更多关于Flutter无界面本地认证插件flutter_local_auth_invisible的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter无界面本地认证插件flutter_local_auth_invisible的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何使用 flutter_local_auth_invisible 插件进行无界面本地认证的代码示例。flutter_local_auth_invisible 插件允许你在Flutter应用中执行本地身份验证(如指纹或面部识别),而无需显示任何用户界面组件。

首先,你需要在你的 pubspec.yaml 文件中添加该插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_local_auth_invisible: ^x.y.z  # 请替换为最新版本号

然后,运行 flutter pub get 以获取依赖。

接下来,在你的 Dart 代码中,你可以按照以下步骤使用 flutter_local_auth_invisible

import 'package:flutter/material.dart';
import 'package:flutter_local_auth_invisible/flutter_local_auth_invisible.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Local Auth Invisible Example'),
        ),
        body: Center(
          child: AuthButton(),
        ),
      ),
    );
  }
}

class AuthButton extends StatefulWidget {
  @override
  _AuthButtonState createState() => _AuthButtonState();
}

class _AuthButtonState extends State<AuthButton> {
  final FlutterLocalAuthInvisible _auth = FlutterLocalAuthInvisible();

  Future<void> _authenticate() async {
    bool authenticated = false;
    try {
      authenticated = await _auth.authenticateWithBiometrics(
        localizedReason: 'Please authenticate to continue',
        useErrorDialogs: true,
        stickyAuth: false,
      );
    } catch (e) {
      print('Authentication failed: $e');
    }

    if (authenticated) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Authenticated successfully!')),
      );
    } else {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Authentication failed!')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: _authenticate,
      child: Text('Authenticate'),
    );
  }
}

在这个示例中,我们创建了一个简单的Flutter应用,其中包含一个按钮。当用户点击该按钮时,会触发 _authenticate 方法,该方法尝试使用设备上的生物识别功能(如指纹或面部识别)进行认证。

authenticateWithBiometrics 方法接受几个参数:

  • localizedReason:一个字符串,解释为什么需要进行身份验证。这通常会显示在设备的本地认证对话框中(尽管在这个插件中是“无界面”的,这个参数仍然需要,因为一些设备可能需要它进行内部处理)。
  • useErrorDialogs:一个布尔值,指示在认证失败时是否显示错误对话框。
  • stickyAuth:一个布尔值,指示认证是否应该“粘性”(即,一旦用户通过认证,后续调用将立即成功,直到设备重启或应用被杀死)。

请注意,尽管这个插件被设计为“无界面”,但在某些设备上,系统可能仍然会显示一个简短的本地认证提示(如指纹图标或面部识别动画),这是由操作系统控制的,而不是插件本身。

希望这个示例能帮助你理解如何使用 flutter_local_auth_invisible 插件进行无界面本地认证。

回到顶部