Flutter指纹验证插件pin的使用

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

Flutter指纹验证插件pin的使用

pin 插件包含了任何 Flutter 应用可能需要的所有后端逻辑:

  • 处理 PIN 码(设置、更新、测试、移除)
  • 包含了 生物识别
  • 两种易于配置的 超时
  • 能够在应用在后台停留过长时间后请求重新输入 PIN 码
  • 可跳过 PIN 检查以避免打扰用户

如果你还对快速实现与 PIN 码相关的 UI 感兴趣,可以查看 pin_ui 插件。

![pin pub](https://img.shields.io/pub/v/pin.svg?style=flat&colorB=blue&label=pin pub) Star on Github

特性

PIN

该插件提供了一个控制器来处理 PIN 码的生命周期。它具有所有必要的方法来设置、更新、删除和测试 PIN 码。

注意: 在此插件中,测试 PIN 码意味着验证它是否正确。

生物识别

此插件使用 local_auth 来处理生物识别。通过使用 PinCodeController,您可以检查当前设备上是否支持生物识别,设置它,测试它,或者移除它。

注意: 生物识别可能仅在真实设备上工作!

不要忘记根据 local_auth 的指南配置您的应用以使用生物识别。

超时

开发者可以设置配置,以限制用户输入 PIN 码的次数。默认情况下,这个数量是无限的。

有两种类型的超时配置:可刷新不可刷新。第一种类型允许用户无限次输入 PIN 码,但防止暴力破解。第二种类型只给用户预定数量的尝试机会。一旦这些尝试用完,当前用户的会话必须终止,并且用户必须导航到一个新的登录过程以证明他们的身份。

请求再次

请求再次功能为您的应用提供了更多的保护!它允许预配置(由开发人员提前设置)或在应用设置中配置(由用户在运行时设置)一个简单的规则:如果应用在后台停留了一段时间,用户必须再次通过 PIN 码屏幕才能返回应用。

跳过 PIN

此功能是为了让用户有更好的体验,不会被打扰。为什么在几分钟前刚输入过 PIN 码的情况下还要再输入一次呢?控制器可以被配置为计算上次输入 PIN 码的时间。如果时间少于允许的时间间隔,则可以跳过下一个 PIN 码。

开始使用

local_auth 配置

如果您想使用生物识别,您必须通过所有步骤来配置 local_auth 以便在 Android 和 iOS 上使用。否则,当您调用与生物识别相关的函数时,应用程序的行为可能会出现意外并且崩溃。确保按照 pin 插件中 pubspec.yaml 文件中 local_auth 依赖版本的指南进行配置。

控制器初始化

在调用任何方法之前,必须先初始化控制器:

final controller = PinCodeController();
await controller.initialize(); // 异步初始化方法
请求再次配置

控制器会处理应用生命周期的变化。开发人员需要做的事情是提供这些变化发生时的状态。为此,您可以在应用中添加 WidgetsBindingObserver 混入类来覆盖这些方法:initStatedidChangeAppLifecycleStatedispose。具体操作如下:

  1. 添加观察者:
[@override](/user/override)
void initState() {
  super.initState();
  WidgetsBinding.instance.addObserver(this);
}
  1. 提供状态给控制器:
[@override](/user/override)
void didChangeAppLifecycleState(AppLifecycleState state) {
  controller.onAppLifecycleStateChanged(state);
  super.didChangeAppLifecycleState(state);
}
  1. 释放资源:
[@override](/user/override)
void dispose() {
  WidgetsBinding.instance.removeObserver(this);
  super.dispose();
}

如果您使用了请求再次功能,您必须始终在应用启动时设置 onRequestAgain 回调,并且每次设置新的配置时都必须设置。

[@override](/user/override)
void initState() {
  super.initState();
  if (controller.requestAgainConfig == null) return;
  WidgetsBinding.instance.addPostFrameCallback((_) async {
    await myPinCodeController.setRequestAgainConfig(
        controller.requestAgainConfig!.copyWith(onRequestAgain: requestAgainCallback));
  });
}

使用

日志记录

创建 PinCodeController 实例时,可以通过传递 logsEnabled 参数等于 true 来启用日志记录。这对于调试非常有帮助,因为所有发生的事件都会被日志覆盖。默认情况下是禁用的。

final controller = PinCodeController(logsEnabled: true);
配置超时

超时配置类有两个命名构造函数:PinCodeTimeoutConfig.notRefreshablePinCodeTimeoutConfig.refreshable。这两种的区别已在介绍部分描述。

两者都需要 timeouts 映射配置和几个回调(对于非可刷新配置,包括 onTimeoutEndedonTimeoutStartedonMaxTimeoutsReached)。映射包含在每次超时之前的尝试次数(值)和超时持续时间(键)。如果所有超时都是不可刷新的并且都已结束,则将触发 onMaxTimeoutsReached。如果超时是可刷新的并且都已结束,则将使用最后一个键值对重复使用,但用户每次只能尝试一次。

一些额外的要求:

  • 最大持续时间是 6 小时(21600 秒)。
  • 第一个超时持续时间总是 0。
  • 顺序不重要,但按直接顺序放置更容易理解。重要的是超时持续时间:较短的超时不能在较长的超时之后使用。它将始终根据当前超时持续时间从 0 开始逐个进行。
final timeoutConfig = PinCodeTimeoutConfig.notRefreshable(
  onTimeoutEnded: () {
    showToast('Timeout has ended, you can test pin code now!');
  },
  onTimeoutStarted: (timeoutDuration) {
    showToast('Timeout has started, you must wait $timeoutDuration '
            'before it ends!');
  },
  onMaxTimeoutsReached: () {
    showToast('Signing the user out and performing navigation '
            'to the auth screen!');
  },
  timeouts: {
    0: 3, // 初始时你有 3 次尝试,在 60 秒超时之前
    60: 2, // 另外 2 次尝试在 60 秒超时之后
    600: 1, // 另外 1 次尝试在 600 秒超时之后
    // 如果是可刷新超时,你将在每次 600 秒后获得一次尝试
  },
);

注意: 超时功能只能在应用开始运行之前设置,而不能在应用已经运行时设置。

配置请求再次

请求再次配置类构造函数需要 secondsBeforeRequestingAgain。这个主要参数确定用户在前台之前可以在后台停留多长时间而无需再次输入 PIN 码。

如果 0 秒过去了,那么它将每次都需要 PIN 码。

实际的 onRequestAgain 回调,当配置的时间条件为真时会被调用,可以在之后设置。但是必须在第一次潜在的请求再次调用之前设置。

await controller.setRequestAgainConfig(
    PinCodeRequestAgainConfig(
    secondsBeforeRequestingAgain: 60,
    onRequestAgain: () {
      // 导航用户到 PIN 屏幕,不允许他们通过返回按钮退出
      // 并在此处添加您需要的任何其他逻辑
    },
  ),
); 

注意: 请求再次功能可以由开发人员在应用开始时预先配置,也可以由用户在应用设置中运行时配置(如果设置了此类设置)。

配置跳过 PIN

跳过 PIN 配置需要一段在其中不需要输入 PIN 码的时间段。

请注意,作为开发人员,您必须手动处理它,通过检查 canSkipPinCodeNow 获取值。

控制器只能自动处理跳过请求再次,如果您在配置中将 forcedForRequestAgain 设置为 false(默认启用)。

await controller.setSkipPinCodeConfig(
    SkipPinCodeConfig(
    duration: const Duration(minutes: 1),
    forcedForRequestAgain: false,
  ),
); 

注意: 跳过 PIN 功能可以由开发人员在应用开始时预先配置,也可以由用户在应用设置中运行时配置(如果设置了此类设置)。

设置 PIN 码和生物识别

要设置 PIN 码,请使用异步方法 setPinCode

要设置生物识别,请使用异步方法 enableBiometricsIfAvailable。它不需要任何参数,因为控制器会自动选择生物识别类型。

还有名为 canSetBiometrics 的方法来检查当前设备是否可以设置生物识别。

await controller.setPinCode(pinCodeTextEditingController.text);

if (await controller.canSetBiometrics()) {
  final biometricsType = await pinCodeController.enableBiometricsIfAvailable();
  // 您可以使用 biometricsType 变量来显示消息或确定要显示在 UI 中的图标(Face Id 或指纹)
}
测试 PIN 码和生物识别

如果设置了 PIN 码,您可以调用 testPinCode 方法来测试(检查是否正确)。如果正确则返回 true,否则返回 false

对于生物识别,同样的方法叫做 testBiometrics

还有 canTestPinCodeisPinSetisBiometricsSet 方法,可以用来检查是否设置了 PIN 码,是否可以在当前时刻测试它等。

if (pinCodeController.isTimeoutRunning) {
  return showToast('You must wait for timeout to end');
}
if (!await pinCodeController.canTestPinCode()) {
  return showToast('You can\'t test PIN CODE now');
}
final isPinCodeCorrect = await pinCodeController.testPinCode(pin);
if (isPinCodeCorrect) {
  // 导航用户到下一个屏幕
} else {
  // 在屏幕上显示错误或显示提示
}
响应事件流

您可能需要在 UI 中响应与 PIN 码相关的事件(如成功输入 PIN,新配置或超时开始),例如更新视图,导航,显示提示等。一种实现方式是监听 PinCodeController 的名为 eventsStream 的流。您可以在名为 PinCodeEvents 的枚举中找到所有可以抛出的事件列表。

final subscription = controller.eventsStream.listen((event) {
  // 更新 UI,记录分析数据或自定义日志
});
异常

在运行时,如果您做错了什么,会抛出异常。因此最好在调用某些控制器方法时使用 try-catch 块并适当地处理它们。

您可以在 lib/src/exceptions 中看到所有潜在的异常列表。

释放

PinCodeController 有一个 dispose 方法,当您在视图类中调用 dispose 方法时应该调用它。

[@override](/user/override)
void dispose() {
  controller.dispose();
  super.dispose();
}

更多关于Flutter指纹验证插件pin的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter指纹验证插件pin的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中实现指纹验证功能,你可以使用pin_code_fieldslocal_auth这两个插件。pin_code_fields用于创建PIN码输入界面,而local_auth则用于处理本地身份验证(如指纹或面部识别)。以下是一个简化的代码示例,展示如何结合这两个插件来实现指纹验证功能。

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

dependencies:
  flutter:
    sdk: flutter
  pin_code_fields: ^7.0.0  # 请检查最新版本
  local_auth: ^1.0.0  # 请检查最新版本

然后,运行flutter pub get来安装这些依赖。

接下来,在你的Dart文件中,你可以这样实现指纹验证功能:

import 'package:flutter/material.dart';
import 'package:pin_code_fields/pin_code_fields.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('Flutter Fingerprint Verification'),
        ),
        body: FingerprintScreen(),
      ),
    );
  }
}

class FingerprintScreen extends StatefulWidget {
  @override
  _FingerprintScreenState createState() => _FingerprintScreenState();
}

class _FingerprintScreenState extends State<FingerprintScreen> {
  final LocalAuthentication auth = LocalAuthentication();
  bool isAuthenticated = false;
  bool isVerifying = false;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(16.0),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          PinCodeTextField(
            length: 6, // 假设PIN码长度为6
            onCompleted: (pin) async {
              setState(() {
                isVerifying = true;
              });
              
              bool authenticated = await authenticateUser(pin);
              
              setState(() {
                isVerifying = false;
                isAuthenticated = authenticated;
              });

              if (authenticated) {
                // 验证成功后的逻辑
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(content: Text('Authenticated successfully!')),
                );
              } else {
                // 验证失败后的逻辑
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(content: Text('Authentication failed.')),
                );
              }
            },
            obscureText: false,
            animationType: AnimationType.fade,
            pinTheme: PinTheme(
              shape: PinCodeFieldShape.circle,
              activeColor: Colors.blue,
              inactiveColor: Colors.grey,
              activeFillColor: Colors.white,
              inactiveFillColor: Colors.transparent,
              selectedColor: Colors.green,
              fieldSize: 50.0,
              enabled: true,
            ),
          ),
          SizedBox(height: 20),
          if (isVerifying)
            CircularProgressIndicator()
          else if (isAuthenticated)
            Text('Authenticated!', style: TextStyle(color: Colors.green, fontSize: 20)),
        ],
      ),
    );
  }

  Future<bool> authenticateUser(String pin) async {
    bool canCheckBiometrics = await auth.canCheckBiometrics;
    if (!canCheckBiometrics) {
      return false;
    }

    List<BiometricType> availableBiometrics = await auth.getAvailableBiometrics();
    if (availableBiometrics.isEmpty) {
      return false;
    }

    // 这里假设你已经通过PIN码验证了用户身份,现在使用指纹进行二次验证
    bool isAuthenticated = false;
    try {
      isAuthenticated = await auth.authenticateWithBiometrics(
        localizedReason: 'Please authenticate to continue',
        useErrorDialogs: true,
        stickyAuth: true,
      );
    } catch (e) {
      print(e);
    }

    // 在实际应用中,你可能还需要将PIN码与服务器上的记录进行比对
    // 这里仅作为示例,直接返回指纹验证结果
    return isAuthenticated;
  }
}

请注意,这个示例仅用于演示如何将两个插件结合使用。在实际应用中,你可能需要处理更多的边界情况,例如PIN码输入错误次数限制、指纹验证失败后的重试逻辑等。此外,根据应用的需求,你可能还需要将PIN码发送到服务器进行验证,而不仅仅是在客户端进行验证。

回到顶部