blob: b2b03b920d640b3ea46ec7833eeb9f3f1254a179 [file] [log] [blame]
// Copyright 2017 The Chromium 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 is a temporary ignore to allow us to land a new set of linter rules in a
// series of manageable patches instead of one gigantic PR. It disables some of
// the new lints that are already failing on this plugin, for this plugin. It
// should be deleted and the failing lints addressed as soon as possible.
// ignore_for_file: public_member_api_docs
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:meta/meta.dart';
import 'package:platform/platform.dart';
import 'auth_strings.dart';
import 'error_codes.dart';
enum BiometricType { face, fingerprint, iris }
const MethodChannel _channel = MethodChannel('plugins.flutter.io/local_auth');
Platform _platform = const LocalPlatform();
@visibleForTesting
void setMockPathProviderPlatform(Platform platform) {
_platform = platform;
}
/// A Flutter plugin for authenticating the user identity locally.
class LocalAuthentication {
/// Authenticates the user with biometrics available on the device.
///
/// Returns a [Future] holding true, if the user successfully authenticated,
/// false otherwise.
///
/// [localizedReason] is the message to show to user while prompting them
/// for authentication. This is typically along the lines of: 'Please scan
/// your finger to access MyApp.'
///
/// [useErrorDialogs] = true means the system will attempt to handle user
/// fixable issues encountered while authenticating. For instance, if
/// fingerprint reader exists on the phone but there's no fingerprint
/// registered, the plugin will attempt to take the user to settings to add
/// one. Anything that is not user fixable, such as no biometric sensor on
/// device, will be returned as a [PlatformException].
///
/// [stickyAuth] is used when the application goes into background for any
/// reason while the authentication is in progress. Due to security reasons,
/// the authentication has to be stopped at that time. If stickyAuth is set
/// to true, authentication resumes when the app is resumed. If it is set to
/// false (default), then as soon as app is paused a failure message is sent
/// back to Dart and it is up to the client app to restart authentication or
/// do something else.
///
/// Construct [AndroidAuthStrings] and [IOSAuthStrings] if you want to
/// customize messages in the dialogs.
///
/// Setting [sensitiveTransaction] to true enables platform specific
/// precautions. For instance, on face unlock, Android opens a confirmation
/// dialog after the face is recognized to make sure the user meant to unlock
/// their phone.
///
/// Throws an [PlatformException] if there were technical problems with local
/// authentication (e.g. lack of relevant hardware). This might throw
/// [PlatformException] with error code [otherOperatingSystem] on the iOS
/// simulator.
Future<bool> authenticateWithBiometrics({
@required String localizedReason,
bool useErrorDialogs = true,
bool stickyAuth = false,
AndroidAuthMessages androidAuthStrings = const AndroidAuthMessages(),
IOSAuthMessages iOSAuthStrings = const IOSAuthMessages(),
bool sensitiveTransaction = true,
}) async {
assert(localizedReason != null);
final Map<String, Object> args = <String, Object>{
'localizedReason': localizedReason,
'useErrorDialogs': useErrorDialogs,
'stickyAuth': stickyAuth,
'sensitiveTransaction': sensitiveTransaction,
};
if (_platform.isIOS) {
args.addAll(iOSAuthStrings.args);
} else if (_platform.isAndroid) {
args.addAll(androidAuthStrings.args);
} else {
throw PlatformException(
code: otherOperatingSystem,
message: 'Local authentication does not support non-Android/iOS '
'operating systems.',
details: 'Your operating system is ${_platform.operatingSystem}');
}
return await _channel.invokeMethod<bool>(
'authenticateWithBiometrics', args);
}
/// Returns true if auth was cancelled successfully.
/// This api only works for Android.
/// Returns false if there was some error or no auth in progress.
///
/// Returns [Future] bool true or false:
Future<bool> stopAuthentication() {
if (_platform.isAndroid) {
return _channel.invokeMethod<bool>('stopAuthentication');
}
return Future<bool>.sync(() => true);
}
/// Returns true if device is capable of checking biometrics
///
/// Returns a [Future] bool true or false:
Future<bool> get canCheckBiometrics async =>
(await _channel.invokeListMethod<String>('getAvailableBiometrics'))
.isNotEmpty;
/// Returns a list of enrolled biometrics
///
/// Returns a [Future] List<BiometricType> with the following possibilities:
/// - BiometricType.face
/// - BiometricType.fingerprint
/// - BiometricType.iris (not yet implemented)
Future<List<BiometricType>> getAvailableBiometrics() async {
final List<String> result =
(await _channel.invokeListMethod<String>('getAvailableBiometrics'));
final List<BiometricType> biometrics = <BiometricType>[];
result.forEach((String value) {
switch (value) {
case 'face':
biometrics.add(BiometricType.face);
break;
case 'fingerprint':
biometrics.add(BiometricType.fingerprint);
break;
case 'iris':
biometrics.add(BiometricType.iris);
break;
case 'undefined':
break;
}
});
return biometrics;
}
}