生物辨識使用local_auth
<key>NSFaceIDUsageDescription</key>
<string>Why is my app authenticating using face id?</string>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.app">
  <uses-permission android:name="android.permission.USE_FINGERPRINT"/>
<manifest>
都是透過LocalAuthentication()這個實例
canEvaluatePolicy☘️☘️☘️
  Future<void> _checkBiometrics() async {
    bool canCheckBiometrics;
    canCheckBiometrics = await _localAuth.canCheckBiometrics;
    if (!mounted) return;
    setState(() {
      _canEvaluatePolicy = canCheckBiometrics ? "是" : "否";
    });
  }
LABiometryType☘️☘️☘️
注意一下 這邊是回傳一個陣列 不是某個類型⚠️⚠️⚠️
所以代表Andorid好像有裝置可以同時支援(難保以後iPhone不會)
  Future<void> _getAvailableBiometrics() async {
    List<BiometricType> availableBiometrics;
    availableBiometrics = await _localAuth.getAvailableBiometrics();
    if (!mounted) return;
    setState(() {
      if (availableBiometrics.isEmpty) {
        _biometryType = noEnrolledWording;
      } else {
        switch (availableBiometrics.first) {
          case BiometricType.face:
            _biometryType = "點我驗證Face ID";
            break;
          case BiometricType.fingerprint:
            _biometryType = "點我驗證Touch ID";
            break;
          default:
            _biometryType = noEnrolledWording;
            break;
        }
      }
    });
  }
evaluatePolicy☘️☘️☘️

 
 
  Future<void> _authenticate() async {
    print("驗證中");
    bool authenticated = false;
    try {
      authenticated = await _localAuth.authenticateWithBiometrics(
          localizedReason: 'Scan your fingerprint to authenticate',
          stickyAuth: true,
          useErrorDialogs: true,
          iOSAuthStrings: IOSAuthMessages(
              lockOut: "鎖",
              goToSettingsButton: "設定",
              goToSettingsDescription: "請設定",
              cancelButton: "算了"
          )
      );
    } on PlatformException catch (e) {
      print("例外");
      print(e);
    }
    if (!mounted) return;
    final result = authenticated ? "驗證成功" : "驗證失敗";
    scaffoldKey.currentState.showSnackBar(SnackBar(content: Text(result)));
  }
上面第2節中的三個function中可以看到
官方用了個小技巧mounted
來判斷await是否回來了
如果是Android的話
可以透過_localAuth.stopAuthentication()來中斷驗證
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:local_auth/auth_strings.dart';
import 'package:local_auth/local_auth.dart';
class LessonPageLocalAuthentication extends StatefulWidget {
  @override
  _LessonPageLocalAuthenticationState createState() => _LessonPageLocalAuthenticationState();
}
class _LessonPageLocalAuthenticationState extends State<LessonPageLocalAuthentication> {
  final noEnrolledWording = "未啟用生物辨識";
  final scaffoldKey = GlobalKey<ScaffoldState>();
  final LocalAuthentication _localAuth = LocalAuthentication();
  String _canEvaluatePolicy = "";
  String _biometryType = "";
  Future<void> _checkBiometrics() async {
    bool canCheckBiometrics;
    canCheckBiometrics = await _localAuth.canCheckBiometrics;
    if (!mounted) return;
    setState(() {
      _canEvaluatePolicy = canCheckBiometrics ? "是" : "否";
    });
  }
  Future<void> _getAvailableBiometrics() async {
    List<BiometricType> availableBiometrics;
    availableBiometrics = await _localAuth.getAvailableBiometrics();
    if (!mounted) return;
    setState(() {
      if (availableBiometrics.isEmpty) {
        _biometryType = noEnrolledWording;
      } else {
        switch (availableBiometrics.first) {
          case BiometricType.face:
            _biometryType = "點我驗證Face ID";
            break;
          case BiometricType.fingerprint:
            _biometryType = "點我驗證Touch ID";
            break;
          default:
            _biometryType = noEnrolledWording;
            break;
        }
      }
    });
  }
  Future<void> _authenticate() async {
    print("驗證中");
    bool authenticated = false;
    try {
      authenticated = await _localAuth.authenticateWithBiometrics(
          localizedReason: 'Scan your fingerprint to authenticate',
          stickyAuth: true,
          useErrorDialogs: true,
          iOSAuthStrings: IOSAuthMessages(
              lockOut: "鎖",
              goToSettingsButton: "設定",
              goToSettingsDescription: "請設定",
              cancelButton: "算了"
          )
      );
    } on PlatformException catch (e) {
      print("例外");
      print(e);
    }
    if (!mounted) return;
    final result = authenticated ? "驗證成功" : "驗證失敗";
    scaffoldKey.currentState.showSnackBar(SnackBar(content: Text(result)));
  }
  @override
  void initState() {
    super.initState();
    _checkBiometrics();
    _getAvailableBiometrics();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        key: scaffoldKey,
        appBar: AppBar(
          title: Text("Local Authentication"),
        ),
        body: Container(
            alignment: Alignment.center,
            child: Column(
              children: [
                SizedBox(height: 100),
                Text("您的裝置是否支援生物辨識:$_canEvaluatePolicy"),
                OutlineButton(
                    child: Text(_biometryType),
                    onPressed: _biometryType == noEnrolledWording ? null : _authenticate
//                    onPressed: _authenticate
                )
              ],
            )
        )
    );
  }
}
本集內容Android版請見:iOS Developer Learning Android. Lesson 21
下集預告:Map
最後提供一下github.com/mark33699/IDLF