Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit bc5acb9

Browse files
[local_auth] Overhaul README, and fix error_codes.dart visibility (#5653)
1 parent 3eba661 commit bc5acb9

File tree

9 files changed

+351
-142
lines changed

9 files changed

+351
-142
lines changed

packages/local_auth/local_auth/CHANGELOG.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
## NEXT
1+
## 2.0.1
22

3+
* Restores the ability to import `error_codes.dart`.
4+
* Updates README to match API changes in 2.0, and to improve clarity in
5+
general.
36
* Removes unnecessary imports.
47

58
## 2.0.0
@@ -9,11 +12,11 @@
912
* BREAKING CHANGE: Deprecated method `authenticateWithBiometrics` has been removed.
1013
Use `authenticate` instead.
1114
* BREAKING CHANGE: Enum `BiometricType` has been expanded with options for `strong` and `weak`,
12-
and applications should be updated to handle these accordingly.
15+
and applications should be updated to handle these accordingly.
1316
* BREAKING CHANGE: Parameters of `authenticate` have been changed.
14-
17+
1518
Example:
16-
```dart
19+
```dart
1720
// Old way of calling `authenticate`.
1821
Future<bool> authenticate(
1922
localizedReason: 'localized reason',

packages/local_auth/local_auth/README.md

Lines changed: 159 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -1,148 +1,188 @@
11
# local_auth
22

3+
<?code-excerpt path-base="excerpts/packages/local_auth_example"?>
4+
35
This Flutter plugin provides means to perform local, on-device authentication of
46
the user.
57

6-
This means referring to biometric authentication on iOS (Touch ID or lock code)
7-
and the fingerprint APIs on Android (introduced in Android 6.0).
8+
On supported devices, this includes authentication with biometrics such as
9+
fingerprint or facial recognition.
810

911
| | Android | iOS |
1012
|-------------|-----------|------|
1113
| **Support** | SDK 16+\* | 9.0+ |
1214

1315
## Usage
1416

15-
Import the relevant file:
16-
17-
```dart
18-
import 'package:local_auth/local_auth.dart';
19-
```
17+
### Device Capabilities
2018

21-
To check whether there is local authentication available on this device or not, call canCheckBiometrics:
19+
To check whether there is local authentication available on this device or not,
20+
call `canCheckBiometrics` (if you need biometrics support) and/or
21+
`isDeviceSupported()` (if you just need some device-level authentication):
2222

23+
<?code-excerpt "readme_excerpts.dart (CanCheck)"?>
2324
```dart
24-
bool canCheckBiometrics =
25-
await localAuth.canCheckBiometrics;
25+
import 'package:local_auth/local_auth.dart';
26+
// ···
27+
final LocalAuthentication auth = LocalAuthentication();
28+
// ···
29+
final bool canAuthenticateWithBiometrics = await auth.canCheckBiometrics;
30+
final bool canAuthenticate =
31+
canAuthenticateWithBiometrics || await auth.isDeviceSupported();
2632
```
2733

2834
Currently the following biometric types are implemented:
2935

3036
- BiometricType.face
3137
- BiometricType.fingerprint
38+
- BiometricType.weak
39+
- BiometricType.strong
40+
41+
### Enrolled Biometrics
42+
43+
`canCheckBiometrics` only indicates whether hardware support is available, not
44+
whether the device has any biometrics enrolled. To get a list of enrolled
45+
biometrics, call `getAvailableBiometrics()`.
3246

33-
To get a list of enrolled biometrics, call getAvailableBiometrics:
47+
The types are device-specific and platform-specific, and other types may be
48+
added in the future, so when possible you should not rely on specific biometric
49+
types and only check that some biometric is enrolled:
3450

51+
<?code-excerpt "readme_excerpts.dart (Enrolled)"?>
3552
```dart
36-
List<BiometricType> availableBiometrics =
53+
final List<BiometricType> availableBiometrics =
3754
await auth.getAvailableBiometrics();
3855
39-
if (Platform.isIOS) {
40-
if (availableBiometrics.contains(BiometricType.face)) {
41-
// Face ID.
42-
} else if (availableBiometrics.contains(BiometricType.fingerprint)) {
43-
// Touch ID.
44-
}
56+
if (availableBiometrics.isNotEmpty) {
57+
// Some biometrics are enrolled.
4558
}
46-
```
47-
48-
We have default dialogs with an 'OK' button to show authentication error
49-
messages for the following 2 cases:
50-
51-
1. Passcode/PIN/Pattern Not Set. The user has not yet configured a passcode on
52-
iOS or PIN/pattern on Android.
53-
2. Touch ID/Fingerprint Not Enrolled. The user has not enrolled any
54-
fingerprints on the device.
5559
56-
Which means, if there's no fingerprint on the user's device, a dialog with
57-
instructions will pop up to let the user set up fingerprint. If the user clicks
58-
'OK' button, it will return 'false'.
60+
if (availableBiometrics.contains(BiometricType.strong) ||
61+
availableBiometrics.contains(BiometricType.face)) {
62+
// Specific types of biometrics are available.
63+
// Use checks like this with caution!
64+
}
65+
```
5966

60-
Use the exported APIs to trigger local authentication with default dialogs:
67+
### Options
6168

62-
The `authenticate()` method uses biometric authentication, but also allows
63-
users to use pin, pattern, or passcode.
69+
The `authenticate()` method uses biometric authentication when possible, but
70+
also allows fallback to pin, pattern, or passcode.
6471

72+
<?code-excerpt "readme_excerpts.dart (AuthAny)"?>
6573
```dart
66-
var localAuth = LocalAuthentication();
67-
bool didAuthenticate =
68-
await localAuth.authenticate(
69-
localizedReason: 'Please authenticate to show account balance');
74+
try {
75+
final bool didAuthenticate = await auth.authenticate(
76+
localizedReason: 'Please authenticate to show account balance');
77+
// ···
78+
} on PlatformException {
79+
// ...
80+
}
7081
```
7182

72-
To authenticate using biometric authentication only, set `biometricOnly` to `true`.
83+
To require biometric authentication, pass `AuthenticationOptions` with
84+
`biometricOnly` set to `true`.
7385

86+
<?code-excerpt "readme_excerpts.dart (AuthBioOnly)"?>
7487
```dart
75-
var localAuth = LocalAuthentication();
76-
bool didAuthenticate =
77-
await localAuth.authenticate(
78-
localizedReason: 'Please authenticate to show account balance',
79-
biometricOnly: true);
88+
final bool didAuthenticate = await auth.authenticate(
89+
localizedReason: 'Please authenticate to show account balance',
90+
options: const AuthenticationOptions(biometricOnly: true));
8091
```
8192

82-
If you don't want to use the default dialogs, call this API with
83-
'useErrorDialogs = false'. In this case, it will throw the error message back
84-
and you need to handle them in your dart code:
85-
86-
```dart
87-
bool didAuthenticate =
88-
await localAuth.authenticate(
89-
localizedReason: 'Please authenticate to show account balance',
90-
useErrorDialogs: false);
91-
```
93+
#### Dialogs
9294

93-
You can use our default dialog messages, or you can use your own messages by
94-
passing in IOSAuthMessages and AndroidAuthMessages:
95+
The plugin provides default dialogs for the following cases:
9596

96-
```dart
97-
import 'package:local_auth/auth_strings.dart';
98-
99-
const iosStrings = const IOSAuthMessages(
100-
cancelButton: 'cancel',
101-
goToSettingsButton: 'settings',
102-
goToSettingsDescription: 'Please set up your Touch ID.',
103-
lockOut: 'Please reenable your Touch ID');
104-
await localAuth.authenticate(
105-
localizedReason: 'Please authenticate to show account balance',
106-
useErrorDialogs: false,
107-
iOSAuthStrings: iosStrings);
97+
1. Passcode/PIN/Pattern Not Set: The user has not yet configured a passcode on
98+
iOS or PIN/pattern on Android.
99+
2. Biometrics Not Enrolled: The user has not enrolled any biometrics on the
100+
device.
108101

109-
```
102+
If a user does not have the necessary authentication enrolled when
103+
`authenticate` is called, they will be given the option to enroll at that point,
104+
or cancel authentication.
110105

111-
If needed, you can manually stop authentication for android:
106+
If you don't want to use the default dialogs, set the `useErrorDialogs` option
107+
to `false` to have `authenticate` immediately return an error in those cases.
112108

109+
<?code-excerpt "readme_excerpts.dart (NoErrorDialogs)"?>
113110
```dart
111+
import 'package:local_auth/error_codes.dart' as auth_error;
112+
// ···
113+
try {
114+
final bool didAuthenticate = await auth.authenticate(
115+
localizedReason: 'Please authenticate to show account balance',
116+
options: const AuthenticationOptions(useErrorDialogs: false));
117+
// ···
118+
} on PlatformException catch (e) {
119+
if (e.code == auth_error.notAvailable) {
120+
// Add handling of no hardware here.
121+
} else if (e.code == auth_error.notEnrolled) {
122+
// ...
123+
} else {
124+
// ...
125+
}
126+
}
127+
```
114128

115-
void _cancelAuthentication() {
116-
localAuth.stopAuthentication();
117-
}
129+
If you want to customize the messages in the dialogs, you can pass
130+
`AuthMessages` for each platform you support. These are platform-specific, so
131+
you will need to import the platform-specific implementation packages. For
132+
instance, to customize Android and iOS:
118133

134+
<?code-excerpt "readme_excerpts.dart (CustomMessages)"?>
135+
```dart
136+
import 'package:local_auth_android/local_auth_android.dart';
137+
import 'package:local_auth_ios/local_auth_ios.dart';
138+
// ···
139+
final bool didAuthenticate = await auth.authenticate(
140+
localizedReason: 'Please authenticate to show account balance',
141+
authMessages: const <AuthMessages>[
142+
AndroidAuthMessages(
143+
signInTitle: 'Oops! Biometric authentication required!',
144+
cancelButton: 'No thanks',
145+
),
146+
IOSAuthMessages(
147+
cancelButton: 'No thanks',
148+
),
149+
]);
119150
```
120151

152+
See the platform-specific classes for details about what can be customized on
153+
each platform.
154+
121155
### Exceptions
122156

123-
There are 6 types of exceptions: PasscodeNotSet, NotEnrolled, NotAvailable, OtherOperatingSystem, LockedOut and PermanentlyLockedOut.
124-
They are wrapped in LocalAuthenticationError class. You can
125-
catch the exception and handle them by different types. For example:
157+
`authenticate` throws `PlatformException`s in many error cases. See
158+
`error_codes.dart` for known error codes that you may want to have specific
159+
handling for. For example:
126160

161+
<?code-excerpt "readme_excerpts.dart (ErrorHandling)"?>
127162
```dart
128163
import 'package:flutter/services.dart';
129164
import 'package:local_auth/error_codes.dart' as auth_error;
130-
131-
try {
132-
bool didAuthenticate = await local_auth.authenticate(
133-
localizedReason: 'Please authenticate to show account balance');
134-
} on PlatformException catch (e) {
135-
if (e.code == auth_error.notAvailable) {
136-
// Handle this exception here.
137-
}
138-
}
165+
import 'package:local_auth/local_auth.dart';
166+
// ···
167+
final LocalAuthentication auth = LocalAuthentication();
168+
// ···
169+
try {
170+
final bool didAuthenticate = await auth.authenticate(
171+
localizedReason: 'Please authenticate to show account balance',
172+
options: const AuthenticationOptions(useErrorDialogs: false));
173+
// ···
174+
} on PlatformException catch (e) {
175+
if (e.code == auth_error.notEnrolled) {
176+
// Add handling of no hardware here.
177+
} else if (e.code == auth_error.lockedOut ||
178+
e.code == auth_error.permanentlyLockedOut) {
179+
// ...
180+
} else {
181+
// ...
182+
}
183+
}
139184
```
140185

141-
### Android
142-
143-
\* The plugin will build and run on SDK 16+, but `isDeviceSupported()` will
144-
always return false before SDK 23 (Android 6.0).
145-
146186
## iOS Integration
147187

148188
Note that this plugin works with both Touch ID and Face ID. However, to use the latter,
@@ -158,46 +198,39 @@ app has not been updated to use Face ID.
158198

159199
## Android Integration
160200

161-
Note that local_auth plugin requires the use of a FragmentActivity as
162-
opposed to Activity. This can be easily done by switching to use
163-
`FlutterFragmentActivity` as opposed to `FlutterActivity` in your
164-
manifest (or your own Activity class if you are extending the base class).
165-
166-
Update your MainActivity.java:
167-
168-
```java
169-
import android.os.Bundle;
170-
import io.flutter.app.FlutterFragmentActivity;
171-
import io.flutter.plugins.flutter_plugin_android_lifecycle.FlutterAndroidLifecyclePlugin;
172-
import io.flutter.plugins.localauth.LocalAuthPlugin;
173-
174-
public class MainActivity extends FlutterFragmentActivity {
175-
@Override
176-
protected void onCreate(Bundle savedInstanceState) {
177-
super.onCreate(savedInstanceState);
178-
FlutterAndroidLifecyclePlugin.registerWith(
179-
registrarFor(
180-
"io.flutter.plugins.flutter_plugin_android_lifecycle.FlutterAndroidLifecyclePlugin"));
181-
LocalAuthPlugin.registerWith(registrarFor("io.flutter.plugins.localauth.LocalAuthPlugin"));
182-
}
183-
}
184-
```
201+
\* The plugin will build and run on SDK 16+, but `isDeviceSupported()` will
202+
always return false before SDK 23 (Android 6.0).
185203

186-
OR
204+
### Activity Changes
187205

188-
Update your MainActivity.kt:
206+
Note that `local_auth` requires the use of a `FragmentActivity` instead of an
207+
`Activity`. To update your application:
189208

190-
```kotlin
191-
import io.flutter.embedding.android.FlutterFragmentActivity
192-
import io.flutter.embedding.engine.FlutterEngine
193-
import io.flutter.plugins.GeneratedPluginRegistrant
209+
* If you are using `FlutterActivity` directly, change it to
210+
`FlutterFragmentActivity` in your `AndroidManifest.xml`.
211+
* If you are using a custom activity, update your `MainActivity.java`:
194212

195-
class MainActivity: FlutterFragmentActivity() {
196-
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
197-
GeneratedPluginRegistrant.registerWith(flutterEngine)
213+
```java
214+
import io.flutter.embedding.android.FlutterFragmentActivity;
215+
216+
public class MainActivity extends FlutterFragmentActivity {
217+
// ...
198218
}
199-
}
200-
```
219+
```
220+
221+
or MainActivity.kt:
222+
223+
```kotlin
224+
import io.flutter.embedding.android.FlutterFragmentActivity
225+
226+
class MainActivity: FlutterFragmentActivity() {
227+
// ...
228+
}
229+
```
230+
231+
to inherit from `FlutterFragmentActivity`.
232+
233+
### Permissions
201234

202235
Update your project's `AndroidManifest.xml` file to include the
203236
`USE_FINGERPRINT` permissions:
@@ -209,6 +242,8 @@ Update your project's `AndroidManifest.xml` file to include the
209242
<manifest>
210243
```
211244
245+
### Compatibility
246+
212247
On Android, you can check only for existence of fingerprint hardware prior
213248
to API 29 (Android Q). Therefore, if you would like to support other biometrics
214249
types (such as face scanning) and you want to support SDKs lower than Q,
@@ -223,10 +258,3 @@ if the user receives a phone call before they get a chance to authenticate. With
223258
`stickyAuth` set to false, this would result in plugin returning failure result
224259
to the Dart app. If set to true, the plugin will retry authenticating when the
225260
app resumes.
226-
227-
## Getting Started
228-
229-
For help getting started with Flutter, view our online
230-
[documentation](https://flutter.dev/).
231-
232-
For help on editing plugin code, view the [documentation](https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin).

0 commit comments

Comments
 (0)