From b8bc8030e2c9f90f48a6a25932495bad8c7832f2 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 6 May 2022 14:05:26 -0400 Subject: [PATCH 1/6] Remove local_auth excerpt exemption --- script/configs/temp_exclude_excerpt.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/script/configs/temp_exclude_excerpt.yaml b/script/configs/temp_exclude_excerpt.yaml index fc8454d75a0c..bd73880ee5ee 100644 --- a/script/configs/temp_exclude_excerpt.yaml +++ b/script/configs/temp_exclude_excerpt.yaml @@ -15,7 +15,6 @@ - image_picker_for_web - in_app_purchase/in_app_purchase - ios_platform_images -- local_auth/local_auth - path_provider/path_provider - plugin_platform_interface - quick_actions/quick_actions From 94050a57c023159be91f93e9d91b52b6faf26510 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 6 May 2022 14:15:06 -0400 Subject: [PATCH 2/6] Enable excerpt support --- .../local_auth/example/build.excerpt.yaml | 15 +++++++++++++++ .../local_auth/local_auth/example/pubspec.yaml | 1 + 2 files changed, 16 insertions(+) create mode 100644 packages/local_auth/local_auth/example/build.excerpt.yaml diff --git a/packages/local_auth/local_auth/example/build.excerpt.yaml b/packages/local_auth/local_auth/example/build.excerpt.yaml new file mode 100644 index 000000000000..e317efa11cb3 --- /dev/null +++ b/packages/local_auth/local_auth/example/build.excerpt.yaml @@ -0,0 +1,15 @@ +targets: + $default: + sources: + include: + - lib/** + # Some default includes that aren't really used here but will prevent + # false-negative warnings: + - $package$ + - lib/$lib$ + exclude: + - '**/.*/**' + - '**/build/**' + builders: + code_excerpter|code_excerpter: + enabled: true diff --git a/packages/local_auth/local_auth/example/pubspec.yaml b/packages/local_auth/local_auth/example/pubspec.yaml index ad0de2002a4c..c8496fcc0da7 100644 --- a/packages/local_auth/local_auth/example/pubspec.yaml +++ b/packages/local_auth/local_auth/example/pubspec.yaml @@ -18,6 +18,7 @@ dependencies: path: ../ dev_dependencies: + build_runner: ^2.1.10 flutter_driver: sdk: flutter integration_test: From 066c56d2c066306f0983cd56bc40b4938473f249 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 6 May 2022 14:16:10 -0400 Subject: [PATCH 3/6] Convent error-handling example, and fix file visibility issue so that it works --- packages/local_auth/local_auth/README.md | 32 ++++++++++++------- .../example/lib/readme_error_handling.dart | 29 +++++++++++++++++ .../lib/{src/types => }/error_codes.dart | 0 .../local_auth/lib/src/local_auth.dart | 1 - 4 files changed, 50 insertions(+), 12 deletions(-) create mode 100644 packages/local_auth/local_auth/example/lib/readme_error_handling.dart rename packages/local_auth/local_auth/lib/{src/types => }/error_codes.dart (100%) diff --git a/packages/local_auth/local_auth/README.md b/packages/local_auth/local_auth/README.md index 3a60e45a57eb..fd1c82efbf5f 100644 --- a/packages/local_auth/local_auth/README.md +++ b/packages/local_auth/local_auth/README.md @@ -1,10 +1,12 @@ # local_auth + + This Flutter plugin provides means to perform local, on-device authentication of the user. -This means referring to biometric authentication on iOS (Touch ID or lock code) -and the fingerprint APIs on Android (introduced in Android 6.0). +On supported devices, this includes authentication with biometrics such as +fingerprint of facial recognition. | | Android | iOS | |-------------|-----------|------| @@ -18,7 +20,8 @@ Import the relevant file: import 'package:local_auth/local_auth.dart'; ``` -To check whether there is local authentication available on this device or not, call canCheckBiometrics: +To check whether there is local authentication available on this device or not, +call canCheckBiometrics: ```dart bool canCheckBiometrics = @@ -124,18 +127,25 @@ There are 6 types of exceptions: PasscodeNotSet, NotEnrolled, NotAvailable, Othe They are wrapped in LocalAuthenticationError class. You can catch the exception and handle them by different types. For example: + ```dart import 'package:flutter/services.dart'; import 'package:local_auth/error_codes.dart' as auth_error; - -try { - bool didAuthenticate = await local_auth.authenticate( - localizedReason: 'Please authenticate to show account balance'); -} on PlatformException catch (e) { - if (e.code == auth_error.notAvailable) { - // Handle this exception here. +import 'package:local_auth/local_auth.dart'; +// ··· + final LocalAuthentication auth = LocalAuthentication(); +// ··· + try { + final bool didAuthenticate = await auth.authenticate( + localizedReason: 'Please authenticate to show account balance'); + print(didAuthenticate ? 'Success!' : 'Failure'); + } on PlatformException catch (e) { + if (e.code == auth_error.notAvailable) { + // Add handling of no hardware here. + } else { + // ... + } } -} ``` ### Android diff --git a/packages/local_auth/local_auth/example/lib/readme_error_handling.dart b/packages/local_auth/local_auth/example/lib/readme_error_handling.dart new file mode 100644 index 000000000000..b012cb6fd4e4 --- /dev/null +++ b/packages/local_auth/local_auth/example/lib/readme_error_handling.dart @@ -0,0 +1,29 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// #docregion ErrorHandling +import 'package:flutter/services.dart'; +import 'package:local_auth/error_codes.dart' as auth_error; +import 'package:local_auth/local_auth.dart'; +// #enddocregion ErrorHandling + +void main() async { +// #docregion ErrorHandling + final LocalAuthentication auth = LocalAuthentication(); +// #enddocregion ErrorHandling + +// #docregion ErrorHandling + try { + final bool didAuthenticate = await auth.authenticate( + localizedReason: 'Please authenticate to show account balance'); + print(didAuthenticate ? 'Success!' : 'Failure'); + } on PlatformException catch (e) { + if (e.code == auth_error.notAvailable) { + // Add handling of no hardware here. + } else { + // ... + } + } +// #enddocregion ErrorHandling +} diff --git a/packages/local_auth/local_auth/lib/src/types/error_codes.dart b/packages/local_auth/local_auth/lib/error_codes.dart similarity index 100% rename from packages/local_auth/local_auth/lib/src/types/error_codes.dart rename to packages/local_auth/local_auth/lib/error_codes.dart diff --git a/packages/local_auth/local_auth/lib/src/local_auth.dart b/packages/local_auth/local_auth/lib/src/local_auth.dart index 77db4d57f018..206bd04f7b32 100644 --- a/packages/local_auth/local_auth/lib/src/local_auth.dart +++ b/packages/local_auth/local_auth/lib/src/local_auth.dart @@ -11,7 +11,6 @@ import 'dart:async'; import 'package:flutter/services.dart'; -import 'package:local_auth/src/types/error_codes.dart'; import 'package:local_auth_android/local_auth_android.dart'; import 'package:local_auth_ios/local_auth_ios.dart'; import 'package:local_auth_platform_interface/local_auth_platform_interface.dart'; From 41d99ad2e4023d2359f15b5e36134b731058f53a Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 6 May 2022 16:13:23 -0400 Subject: [PATCH 4/6] Convert the rest --- packages/local_auth/local_auth/README.md | 282 ++++++++++-------- .../example/lib/readme_error_handling.dart | 29 -- .../example/lib/readme_excerpts.dart | 164 ++++++++++ .../local_auth/lib/error_codes.dart | 8 +- 4 files changed, 318 insertions(+), 165 deletions(-) delete mode 100644 packages/local_auth/local_auth/example/lib/readme_error_handling.dart create mode 100644 packages/local_auth/local_auth/example/lib/readme_excerpts.dart diff --git a/packages/local_auth/local_auth/README.md b/packages/local_auth/local_auth/README.md index fd1c82efbf5f..73aa95044b5b 100644 --- a/packages/local_auth/local_auth/README.md +++ b/packages/local_auth/local_auth/README.md @@ -14,145 +14,175 @@ fingerprint of facial recognition. ## Usage -Import the relevant file: - -```dart -import 'package:local_auth/local_auth.dart'; -``` +### Device Capabilities To check whether there is local authentication available on this device or not, -call canCheckBiometrics: +call `canCheckBiometrics` (if you need biometrics support) and/or +`isDeviceSupported()` (if you just need some device-level authentication): + ```dart -bool canCheckBiometrics = - await localAuth.canCheckBiometrics; +import 'package:local_auth/local_auth.dart'; +// ··· + final LocalAuthentication auth = LocalAuthentication(); + // ··· + final bool canAuthenticateWithBiometrics = await auth.canCheckBiometrics; + final bool canAuthenticate = + canAuthenticateWithBiometrics || await auth.isDeviceSupported(); ``` Currently the following biometric types are implemented: - BiometricType.face - BiometricType.fingerprint +- BiometricType.weak +- BiometricType.strong + +### Enrolled Biometrics -To get a list of enrolled biometrics, call getAvailableBiometrics: +`canCheckBiometrics` only indicates whether hardware support is available, not +whether the device has any biometrics enrolled. To get a list of enrolled +biometrics, call `getAvailableBiometrics()`. +The types are device-specific and platform-specific, and other types may be +added in the future, so when possible you should not rely on specific biometric +types and only check that some biometric is enrolled: + + ```dart -List availableBiometrics = +final List availableBiometrics = await auth.getAvailableBiometrics(); -if (Platform.isIOS) { - if (availableBiometrics.contains(BiometricType.face)) { - // Face ID. - } else if (availableBiometrics.contains(BiometricType.fingerprint)) { - // Touch ID. - } +if (availableBiometrics.isNotEmpty) { + // Some biometrics are enrolled. } -``` - -We have default dialogs with an 'OK' button to show authentication error -messages for the following 2 cases: -1. Passcode/PIN/Pattern Not Set. The user has not yet configured a passcode on - iOS or PIN/pattern on Android. -2. Touch ID/Fingerprint Not Enrolled. The user has not enrolled any - fingerprints on the device. - -Which means, if there's no fingerprint on the user's device, a dialog with -instructions will pop up to let the user set up fingerprint. If the user clicks -'OK' button, it will return 'false'. +if (availableBiometrics.contains(BiometricType.strong) || + availableBiometrics.contains(BiometricType.face)) { + // Specific types of biometrics are available. + // Use checks like this with caution! +} +``` -Use the exported APIs to trigger local authentication with default dialogs: +### Options -The `authenticate()` method uses biometric authentication, but also allows -users to use pin, pattern, or passcode. +The `authenticate()` method uses biometric authentication when possible, but +also allows fallback to pin, pattern, or passcode. + ```dart -var localAuth = LocalAuthentication(); -bool didAuthenticate = - await localAuth.authenticate( - localizedReason: 'Please authenticate to show account balance'); +try { + final bool didAuthenticate = await auth.authenticate( + localizedReason: 'Please authenticate to show account balance'); + // ··· +} on PlatformException { + // ... +} ``` -To authenticate using biometric authentication only, set `biometricOnly` to `true`. +To require biometric authentication, pass `AuthenticationOptions` with +`biometricOnly` set to `true`. + ```dart -var localAuth = LocalAuthentication(); -bool didAuthenticate = - await localAuth.authenticate( - localizedReason: 'Please authenticate to show account balance', - biometricOnly: true); +final bool didAuthenticate = await auth.authenticate( + localizedReason: 'Please authenticate to show account balance', + options: const AuthenticationOptions(biometricOnly: true)); ``` -If you don't want to use the default dialogs, call this API with -'useErrorDialogs = false'. In this case, it will throw the error message back -and you need to handle them in your dart code: - -```dart -bool didAuthenticate = - await localAuth.authenticate( - localizedReason: 'Please authenticate to show account balance', - useErrorDialogs: false); -``` +#### Dialogs -You can use our default dialog messages, or you can use your own messages by -passing in IOSAuthMessages and AndroidAuthMessages: +The plugin provides default dialogs for the following cases: -```dart -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 localAuth.authenticate( - localizedReason: 'Please authenticate to show account balance', - useErrorDialogs: false, - iOSAuthStrings: iosStrings); +1. Passcode/PIN/Pattern Not Set: The user has not yet configured a passcode on + iOS or PIN/pattern on Android. +2. Biometrics Not Enrolled: The user has not enrolled any biometrics on the + device. -``` +If a user does not have the necessary authentication enrolled when +`authenticate` is called, they will be given the option to enroll at that point, +or cancel authentication. -If needed, you can manually stop authentication for android: +If you don't want to use the default dialogs, set the `useErrorDialogs` option +to `false` to have `authenticate` immediately return an error in those cases. + ```dart +import 'package:local_auth/error_codes.dart' as auth_error; +// ··· + 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.notAvailable) { + // Add handling of no hardware here. + } else if (e.code == auth_error.notEnrolled) { + // ... + } else { + // ... + } + } +``` -void _cancelAuthentication() { - localAuth.stopAuthentication(); -} +If you want to customize the messages in the dialogs, you can pass +`AuthMessages` for each platform you support. These are platform-specific, so +you will need to import the platform-specific implementation packages. For +instance, to customize Android and iOS: + +```dart +import 'package:local_auth_android/local_auth_android.dart'; +import 'package:local_auth_ios/local_auth_ios.dart'; +// ··· + final bool didAuthenticate = await auth.authenticate( + localizedReason: 'Please authenticate to show account balance', + authMessages: const [ + AndroidAuthMessages( + signInTitle: 'Oops! Biometric authentication required!', + cancelButton: 'No thanks', + ), + IOSAuthMessages( + cancelButton: 'No thanks', + ), + ]); ``` +See the platform-specific classes for details about what can be customized on +each platform. + ### Exceptions -There are 6 types of exceptions: PasscodeNotSet, NotEnrolled, NotAvailable, OtherOperatingSystem, LockedOut and PermanentlyLockedOut. -They are wrapped in LocalAuthenticationError class. You can -catch the exception and handle them by different types. For example: +`authenticate` throws `PlatformException`s in many error cases. See +`error_codes.dart` for known error codes that you may want to have specific +handling for. For example: - + ```dart import 'package:flutter/services.dart'; import 'package:local_auth/error_codes.dart' as auth_error; import 'package:local_auth/local_auth.dart'; // ··· final LocalAuthentication auth = LocalAuthentication(); -// ··· - try { - final bool didAuthenticate = await auth.authenticate( - localizedReason: 'Please authenticate to show account balance'); - print(didAuthenticate ? 'Success!' : 'Failure'); - } on PlatformException catch (e) { - if (e.code == auth_error.notAvailable) { - // Add handling of no hardware here. - } else { - // ... + // ··· + 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) { + // Add handling of no hardware here. + } else if (e.code == auth_error.lockedOut || + e.code == auth_error.permanentlyLockedOut) { + // ... + } else { + // ... + } } - } ``` -### Android - -\* The plugin will build and run on SDK 16+, but `isDeviceSupported()` will -always return false before SDK 23 (Android 6.0). - ## iOS Integration Note that this plugin works with both Touch ID and Face ID. However, to use the latter, @@ -168,46 +198,39 @@ app has not been updated to use Face ID. ## Android Integration -Note that local_auth plugin requires the use of a FragmentActivity as -opposed to Activity. This can be easily done by switching to use -`FlutterFragmentActivity` as opposed to `FlutterActivity` in your -manifest (or your own Activity class if you are extending the base class). - -Update your MainActivity.java: - -```java -import android.os.Bundle; -import io.flutter.app.FlutterFragmentActivity; -import io.flutter.plugins.flutter_plugin_android_lifecycle.FlutterAndroidLifecyclePlugin; -import io.flutter.plugins.localauth.LocalAuthPlugin; - -public class MainActivity extends FlutterFragmentActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - FlutterAndroidLifecyclePlugin.registerWith( - registrarFor( - "io.flutter.plugins.flutter_plugin_android_lifecycle.FlutterAndroidLifecyclePlugin")); - LocalAuthPlugin.registerWith(registrarFor("io.flutter.plugins.localauth.LocalAuthPlugin")); - } -} -``` +\* The plugin will build and run on SDK 16+, but `isDeviceSupported()` will +always return false before SDK 23 (Android 6.0). -OR +### Activity Changes -Update your MainActivity.kt: +Note that `local_auth` requires the use of a `FragmentActivity` instead of an +`Activity`. To update your application: -```kotlin -import io.flutter.embedding.android.FlutterFragmentActivity -import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugins.GeneratedPluginRegistrant +* If you are using `FlutterActivity` directly, change it to +`FlutterFragmentActivity` in your `AndroidManifest.xml`. +* If you are using a custom activity, update your `MainActivity.java`: -class MainActivity: FlutterFragmentActivity() { - override fun configureFlutterEngine(flutterEngine: FlutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine) + ```java + import io.flutter.embedding.android.FlutterFragmentActivity; + + public class MainActivity extends FlutterFragmentActivity { + // ... } -} -``` + ``` + + or MainActivity.kt: + + ```kotlin + import io.flutter.embedding.android.FlutterFragmentActivity + + class MainActivity: FlutterFragmentActivity() { + // ... + } + ``` + + to inherit from `FlutterFragmentActivity`. + +### Permissions Update your project's `AndroidManifest.xml` file to include the `USE_FINGERPRINT` permissions: @@ -219,6 +242,8 @@ Update your project's `AndroidManifest.xml` file to include the ``` +### Compatibility + On Android, you can check only for existence of fingerprint hardware prior to API 29 (Android Q). Therefore, if you would like to support other biometrics types (such as face scanning) and you want to support SDKs lower than Q, @@ -233,10 +258,3 @@ if the user receives a phone call before they get a chance to authenticate. With `stickyAuth` set to false, this would result in plugin returning failure result to the Dart app. If set to true, the plugin will retry authenticating when the app resumes. - -## Getting Started - -For help getting started with Flutter, view our online -[documentation](https://flutter.dev/). - -For help on editing plugin code, view the [documentation](https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin). diff --git a/packages/local_auth/local_auth/example/lib/readme_error_handling.dart b/packages/local_auth/local_auth/example/lib/readme_error_handling.dart deleted file mode 100644 index b012cb6fd4e4..000000000000 --- a/packages/local_auth/local_auth/example/lib/readme_error_handling.dart +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// #docregion ErrorHandling -import 'package:flutter/services.dart'; -import 'package:local_auth/error_codes.dart' as auth_error; -import 'package:local_auth/local_auth.dart'; -// #enddocregion ErrorHandling - -void main() async { -// #docregion ErrorHandling - final LocalAuthentication auth = LocalAuthentication(); -// #enddocregion ErrorHandling - -// #docregion ErrorHandling - try { - final bool didAuthenticate = await auth.authenticate( - localizedReason: 'Please authenticate to show account balance'); - print(didAuthenticate ? 'Success!' : 'Failure'); - } on PlatformException catch (e) { - if (e.code == auth_error.notAvailable) { - // Add handling of no hardware here. - } else { - // ... - } - } -// #enddocregion ErrorHandling -} diff --git a/packages/local_auth/local_auth/example/lib/readme_excerpts.dart b/packages/local_auth/local_auth/example/lib/readme_excerpts.dart new file mode 100644 index 000000000000..25ddfe0fa62f --- /dev/null +++ b/packages/local_auth/local_auth/example/lib/readme_excerpts.dart @@ -0,0 +1,164 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file exists solely to host compiled excerpts for README.md, and is not +// intended for use as an actual example application. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +// #docregion ErrorHandling +import 'package:flutter/services.dart'; +// #docregion NoErrorDialogs +import 'package:local_auth/error_codes.dart' as auth_error; +// #enddocregion NoErrorDialogs +// #docregion CanCheck +import 'package:local_auth/local_auth.dart'; +// #enddocregion CanCheck +// #enddocregion ErrorHandling + +// #docregion CustomMessages +import 'package:local_auth_android/local_auth_android.dart'; +import 'package:local_auth_ios/local_auth_ios.dart'; +// #enddocregion CustomMessages + +void main() { + runApp(MyApp()); +} + +class MyApp extends StatefulWidget { + @override + State createState() => _MyAppState(); +} + +class _MyAppState extends State { + // #docregion CanCheck + // #docregion ErrorHandling + final LocalAuthentication auth = LocalAuthentication(); + // #enddocregion CanCheck + // #enddocregion ErrorHandling + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + appBar: AppBar( + title: const Text('README example app'), + ), + body: const Text('See example in main.dart'), + ), + ); + } + + Future checkSupport() async { + // #docregion CanCheck + final bool canAuthenticateWithBiometrics = await auth.canCheckBiometrics; + final bool canAuthenticate = + canAuthenticateWithBiometrics || await auth.isDeviceSupported(); + // #enddocregion CanCheck + + print('Can authenticate: $canAuthenticate'); + print('Can authenticate with biometrics: $canAuthenticateWithBiometrics'); + } + + Future getEnrolledBiometrics() async { + // #docregion Enrolled + final List 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. + // Use checks like this with caution! + } + // #enddocregion Enrolled + } + + Future authenticate() async { + // #docregion AuthAny + try { + final bool didAuthenticate = await auth.authenticate( + localizedReason: 'Please authenticate to show account balance'); + // #enddocregion AuthAny + print(didAuthenticate); + // #docregion AuthAny + } on PlatformException { + // ... + } + // #enddocregion AuthAny + } + + Future authenticateWithBiometrics() async { + // #docregion AuthBioOnly + final bool didAuthenticate = await auth.authenticate( + localizedReason: 'Please authenticate to show account balance', + options: const AuthenticationOptions(biometricOnly: true)); + // #enddocregion AuthBioOnly + print(didAuthenticate); + } + + Future authenticateWithoutDialogs() async { + // #docregion NoErrorDialogs + try { + final bool didAuthenticate = await auth.authenticate( + localizedReason: 'Please authenticate to show account balance', + options: const AuthenticationOptions(useErrorDialogs: false)); + // #enddocregion NoErrorDialogs + print(didAuthenticate ? 'Success!' : 'Failure'); + // #docregion NoErrorDialogs + } on PlatformException catch (e) { + if (e.code == auth_error.notAvailable) { + // Add handling of no hardware here. + } else if (e.code == auth_error.notEnrolled) { + // ... + } else { + // ... + } + } + // #enddocregion NoErrorDialogs + } + + Future authenticateWithErrorHandling() async { + // #docregion ErrorHandling + try { + final bool didAuthenticate = await auth.authenticate( + localizedReason: 'Please authenticate to show account balance', + options: const AuthenticationOptions(useErrorDialogs: false)); + // #enddocregion ErrorHandling + print(didAuthenticate ? 'Success!' : 'Failure'); + // #docregion ErrorHandling + } on PlatformException catch (e) { + if (e.code == auth_error.notEnrolled) { + // Add handling of no hardware here. + } else if (e.code == auth_error.lockedOut || + e.code == auth_error.permanentlyLockedOut) { + // ... + } else { + // ... + } + } + // #enddocregion ErrorHandling + } + + Future authenticateWithCustomDialogMessages() async { + // #docregion CustomMessages + final bool didAuthenticate = await auth.authenticate( + localizedReason: 'Please authenticate to show account balance', + authMessages: const [ + AndroidAuthMessages( + signInTitle: 'Oops! Biometric authentication required!', + cancelButton: 'No thanks', + ), + IOSAuthMessages( + cancelButton: 'No thanks', + ), + ]); + // #enddocregion CustomMessages + print(didAuthenticate ? 'Success!' : 'Failure'); + } +} diff --git a/packages/local_auth/local_auth/lib/error_codes.dart b/packages/local_auth/local_auth/lib/error_codes.dart index 3426099bacbd..15660ee948df 100644 --- a/packages/local_auth/local_auth/lib/error_codes.dart +++ b/packages/local_auth/local_auth/lib/error_codes.dart @@ -9,18 +9,18 @@ /// PIN/pattern/password (Android) on the device. const String passcodeNotSet = 'PasscodeNotSet'; -/// Indicates the user has not enrolled any fingerprints on the device. +/// Indicates the user has not enrolled any biometrics on the device. const String notEnrolled = 'NotEnrolled'; -/// Indicates the device does not have a Touch ID/fingerprint scanner. +/// Indicates the device does not have hardware support for biometrics. const String notAvailable = 'NotAvailable'; /// Indicates the device operating system is unsupported. const String otherOperatingSystem = 'OtherOperatingSystem'; -/// Indicates the API lock out due to too many attempts. +/// Indicates the API is temporarily locked out due to too many attempts. const String lockedOut = 'LockedOut'; -/// Indicates the API being disabled due to too many lock outs. +/// Indicates the API is locked out more persistently than [lockedOut]. /// Strong authentication like PIN/Pattern/Password is required to unlock. const String permanentlyLockedOut = 'PermanentlyLockedOut'; From b5293f1594c2347b026709e46bd3d3bbc3827da4 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 6 May 2022 16:33:15 -0400 Subject: [PATCH 5/6] Bump version --- packages/local_auth/local_auth/CHANGELOG.md | 11 +++++++---- packages/local_auth/local_auth/pubspec.yaml | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/local_auth/local_auth/CHANGELOG.md b/packages/local_auth/local_auth/CHANGELOG.md index c495acae5a81..570d8eef7b9b 100644 --- a/packages/local_auth/local_auth/CHANGELOG.md +++ b/packages/local_auth/local_auth/CHANGELOG.md @@ -1,5 +1,8 @@ -## NEXT +## 2.0.1 +* Restores the ability to import `error_codes.dart`. +* Updates README to match API changes in 2.0, and to improve clarity in + general. * Removes unnecessary imports. ## 2.0.0 @@ -9,11 +12,11 @@ * BREAKING CHANGE: Deprecated method `authenticateWithBiometrics` has been removed. Use `authenticate` instead. * BREAKING CHANGE: Enum `BiometricType` has been expanded with options for `strong` and `weak`, - and applications should be updated to handle these accordingly. + and applications should be updated to handle these accordingly. * BREAKING CHANGE: Parameters of `authenticate` have been changed. - + Example: - ```dart + ```dart // Old way of calling `authenticate`. Future authenticate( localizedReason: 'localized reason', diff --git a/packages/local_auth/local_auth/pubspec.yaml b/packages/local_auth/local_auth/pubspec.yaml index fa055fab17f8..087b84920bb9 100644 --- a/packages/local_auth/local_auth/pubspec.yaml +++ b/packages/local_auth/local_auth/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for Android and iOS devices to allow local authentication via fingerprint, touch ID, face ID, passcode, pin, or pattern. repository: https://github.com/flutter/plugins/tree/main/packages/local_auth/local_auth issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+local_auth%22 -version: 2.0.0 +version: 2.0.1 environment: sdk: ">=2.14.0 <3.0.0" From 3d4aeff3958fbb207a21fcf6f4f88f1949c07360 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Fri, 6 May 2022 20:12:29 -0400 Subject: [PATCH 6/6] Typo --- packages/local_auth/local_auth/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/local_auth/local_auth/README.md b/packages/local_auth/local_auth/README.md index 73aa95044b5b..7ec4829ba521 100644 --- a/packages/local_auth/local_auth/README.md +++ b/packages/local_auth/local_auth/README.md @@ -6,7 +6,7 @@ This Flutter plugin provides means to perform local, on-device authentication of the user. On supported devices, this includes authentication with biometrics such as -fingerprint of facial recognition. +fingerprint or facial recognition. | | Android | iOS | |-------------|-----------|------|