Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions packages/local_auth/local_auth/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
## NEXT

## 3.0.0

* **BREAKING CHANGES:**
* Throws `LocalAuthException`s rather than `PlatformException`s for most
failures cases, allowing structured error handling using the specific
`LocalAuthExceptionCode` values.
* Replaces `AuthenticationOptions` in `authenticate` with specific parameters.
* `AuthenticationOptions.stickyAuth` corresponds to
`persistAcrossBackgrounding`.
* `AuthenticationOptions.useErrorDialogs` has no replacement, as specific
error-handling UI should be up to plugin clients to determine. Callers
should use the new structured error codes to detect and handle failure
modes that used to have native dialogs.
* Updates minimum supported SDK version to Flutter 3.29/Dart 3.7.
* Updates README to reflect that only Android API 24+ is supported.

Expand Down
92 changes: 21 additions & 71 deletions packages/local_auth/local_auth/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,72 +66,34 @@ if (availableBiometrics.contains(BiometricType.strong) ||

### Options

The `authenticate()` method uses biometric authentication when possible, but
also allows fallback to pin, pattern, or passcode.
#### Requiring Biometrics

<?code-excerpt "readme_excerpts.dart (AuthAny)"?>
```dart
try {
final bool didAuthenticate = await auth.authenticate(
localizedReason: 'Please authenticate to show account balance',
);
// ···
} on PlatformException {
// ...
}
```

To require biometric authentication, pass `AuthenticationOptions` with
`biometricOnly` set to `true`.
The `authenticate()` method uses biometric authentication when possible, but
by default also allows fallback to pin, pattern, or passcode. To require
biometric authentication, set `biometricOnly` to `true`.

<?code-excerpt "readme_excerpts.dart (AuthBioOnly)"?>
```dart
final bool didAuthenticate = await auth.authenticate(
localizedReason: 'Please authenticate to show account balance',
options: const AuthenticationOptions(biometricOnly: true),
biometricOnly: true,
);
```

*Note*: `biometricOnly` is not supported on Windows since the Windows implementation's underlying API (Windows Hello) doesn't support selecting the authentication method.

#### Dialogs
#### Background Handling

The plugin provides default dialogs for the following cases:
On mobile platforms, authentication may be canceled by the system if the app
is backgrounded. This might happen if the user receives a phone call before
they get a chance to authenticate, for example. Setting
`persistAcrossBackgrounding` to true will cause the plugin to instead wait until
the app is foregrounded again, retry the authentication, and only return once
that new attempt completes.

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 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.

<?code-excerpt "readme_excerpts.dart (NoErrorDialogs)"?>
```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 {
// ...
}
}
```
#### Dialog customization

If you want to customize the messages in the dialogs, you can pass
If you want to customize the messages in the system 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:
Expand All @@ -158,29 +120,26 @@ each platform.

### Exceptions

`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:
`authenticate` throws `LocalAuthException`s in most failure cases. See
`LocalAuthExceptionCodes` for known error codes that you may want to have
specific handling for. For example:

<?code-excerpt "readme_excerpts.dart (ErrorHandling)"?>
```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',
options: const AuthenticationOptions(useErrorDialogs: false),
);
// ···
} on PlatformException catch (e) {
if (e.code == auth_error.notEnrolled) {
} on LocalAuthException catch (e) {
if (e.code == LocalAuthExceptionCode.noBiometricHardware) {
// Add handling of no hardware here.
} else if (e.code == auth_error.lockedOut ||
e.code == auth_error.permanentlyLockedOut) {
} else if (e.code == LocalAuthExceptionCode.temporaryLockout ||
e.code == LocalAuthExceptionCode.biometricLockout) {
// ...
} else {
// ...
Expand Down Expand Up @@ -287,12 +246,3 @@ the Android theme directly in `android/app/src/main/AndroidManifest.xml`:
</application>
...
```

## Sticky Auth

You can set the `stickyAuth` option on the plugin to true so that plugin does not
return failure if the app is put to background by the system. This might happen
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.
34 changes: 27 additions & 7 deletions packages/local_auth/local_auth/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -86,16 +86,27 @@ class _MyAppState extends State<MyApp> {
});
authenticated = await auth.authenticate(
localizedReason: 'Let OS determine authentication method',
options: const AuthenticationOptions(stickyAuth: true),
persistAcrossBackgrounding: true,
);
setState(() {
_isAuthenticating = false;
});
} on LocalAuthException catch (e) {
print(e);
setState(() {
_isAuthenticating = false;
if (e.code != LocalAuthExceptionCode.userCanceled &&
e.code != LocalAuthExceptionCode.systemCanceled) {
_authorized =
'Error - ${e.code.name}${e.description != null ? ': ${e.description}' : ''}';
}
});
return;
} on PlatformException catch (e) {
print(e);
Comment on lines +95 to 106
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is having print statements in catch blocks normal for our examples?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not uncommon; our examples have historically been pretty bare-bones, and tend to skew more toward enabling manual testing than showing best practices. Some stick the errors into some in-app UI, which is an improvement, but also more code in the example.

It's something that ideally we should address, but polishing example apps that most clients will probably never actually run is also pretty low priority, so I've never followed up on it.

setState(() {
_isAuthenticating = false;
_authorized = 'Error - ${e.message}';
_authorized = 'Unexpected error - ${e.message}';
});
return;
}
Expand All @@ -118,20 +129,29 @@ class _MyAppState extends State<MyApp> {
authenticated = await auth.authenticate(
localizedReason:
'Scan your fingerprint (or face or whatever) to authenticate',
options: const AuthenticationOptions(
stickyAuth: true,
biometricOnly: true,
),
persistAcrossBackgrounding: true,
biometricOnly: true,
);
setState(() {
_isAuthenticating = false;
_authorized = 'Authenticating';
});
} on LocalAuthException catch (e) {
print(e);
setState(() {
_isAuthenticating = false;
if (e.code != LocalAuthExceptionCode.userCanceled &&
e.code != LocalAuthExceptionCode.systemCanceled) {
_authorized =
'Error - ${e.code.name}${e.description != null ? ': ${e.description}' : ''}';
}
});
return;
} on PlatformException catch (e) {
print(e);
setState(() {
_isAuthenticating = false;
_authorized = 'Error - ${e.message}';
_authorized = 'Unexpected Error - ${e.message}';
});
return;
}
Expand Down
52 changes: 5 additions & 47 deletions packages/local_auth/local_auth/example/lib/readme_excerpts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@

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
Expand Down Expand Up @@ -79,68 +75,30 @@ class _MyAppState extends State<MyApp> {
// #enddocregion Enrolled
}

Future<void> 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<void> authenticateWithBiometrics() async {
// #docregion AuthBioOnly
final bool didAuthenticate = await auth.authenticate(
localizedReason: 'Please authenticate to show account balance',
options: const AuthenticationOptions(biometricOnly: true),
biometricOnly: true,
);
// #enddocregion AuthBioOnly
print(didAuthenticate);
}

Future<void> 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<void> 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) {
} on LocalAuthException catch (e) {
if (e.code == LocalAuthExceptionCode.noBiometricHardware) {
// Add handling of no hardware here.
} else if (e.code == auth_error.lockedOut ||
e.code == auth_error.permanentlyLockedOut) {
} else if (e.code == LocalAuthExceptionCode.temporaryLockout ||
e.code == LocalAuthExceptionCode.biometricLockout) {
// ...
} else {
// ...
Expand Down
4 changes: 4 additions & 0 deletions packages/local_auth/local_auth/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,7 @@ dev_dependencies:

flutter:
uses-material-design: true
# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.
# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins
dependency_overrides:
local_auth_platform_interface: {path: ../../../../packages/local_auth/local_auth_platform_interface}
29 changes: 0 additions & 29 deletions packages/local_auth/local_auth/lib/error_codes.dart

This file was deleted.

6 changes: 2 additions & 4 deletions packages/local_auth/local_auth/lib/local_auth.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,5 @@
// found in the LICENSE file.

export 'package:local_auth/src/local_auth.dart' show LocalAuthentication;
export 'package:local_auth_platform_interface/types/auth_options.dart'
show AuthenticationOptions;
export 'package:local_auth_platform_interface/types/biometric_type.dart'
show BiometricType;
export 'package:local_auth_platform_interface/local_auth_platform_interface.dart'
show BiometricType, LocalAuthException, LocalAuthExceptionCode;
Loading