Flutter - запрашивать TouchID/FaceID при открытии приложения
У меня проблема с реализацией аутентификации TouchID/FaceID таким образом, что она автоматически запрашивает пользователя при открытии приложения. Я использую зависимость local_auth для TouchID/FaceID.
В приведенном ниже коде биометрическая аутентификация появится после возобновления работы приложения, но ее также невозможно отменить. Если вы нажмете кнопку "Домой", она отклонит запрос TouchID, но сразу же начнет повторную попытку и вызовет бесконечный цикл, если вы продолжаете пробовать это. Он также дважды будет выдавать случайный запрос, поэтому, даже если вы успешно войдете в систему с первым запросом TouchID, он сразу же появится снова. Кто-нибудь знает способ исправить это? У меня также есть кнопка TouchID на странице входа, которую пользователи могут нажимать, чтобы вручную запросить TouchID, но я бы хотел воссоздать, как работают мои банковские приложения и другие, когда TouchID запрашивает, когда вы автоматически открываете приложение.
void initState() {
super.initState();
SystemChannels.lifecycle.setMessageHandler((msg) async {
if (msg==AppLifecycleState.resumed.toString()) {
// If can pop, app is not at login screen
// so don't prompt for authentication
if (!Navigator.canPop(context)) {
if (_useFingerprint) {
SharedPreferences prefs = await SharedPreferences.getInstance();
String password = prefs.getString('password');
biometricAuthentication(_username, password);
}
}
}
});
void biometricAuthentication(String user, String pass) async {
print("Biometric Authentication Called");
bool didAuthenticate = false;
try {
didAuthenticate = await localAuth.authenticateWithBiometrics(localizedReason: 'Please authenticate');
} on PlatformException catch (e) {
print(e);
}
if (!mounted) {
return;
}
if (!didAuthenticate) {
return;
}
else {
normalLogin(user, pass);
}
}
4 ответа
Попробуй это:
Создайте класс для управления жизнью вашего приложения
class LifecycleEventHandler extends WidgetsBindingObserver {
final Function onResume;
LifecycleEventHandler(this.onResume);
@override
Future<void> didChangeAppLifecycleState(AppLifecycleState state) async {
switch (state) {
case AppLifecycleState.resumed:
onResume.call();
break;
default:
break;
}
}
}
Затем в вашем основном:
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(
LifecycleEventHandler(() async {
//Put your auth function here (biometric auth or passcode)
}),
);
}
Каждый раз, когда вы возвращаетесь в приложение, действие, которое вы поставили, будет выполняться
Думаю, мне удалось ее решить. Если есть какие-либо другие проблемы, дайте мне знать.
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
bool isAuthenticated = await Authentication.authenticateWithBiometrics();
if (isAuthenticated) {
runApp(MyApp());
} else {
main();
}
}
Кажется, это работает каждый раз, когда я открываю приложение. Более того, вот мой файл authentification.dart
class Authentication {
static Future<bool> authenticateWithBiometrics() async {
final LocalAuthentication localAuthentication = LocalAuthentication();
bool isBiometricSupported = await localAuthentication.isDeviceSupported();
bool canCheckBiometrics = await localAuthentication.canCheckBiometrics;
bool isAuthenticated = false;
if (isBiometricSupported && canCheckBiometrics) {
isAuthenticated = await localAuthentication.authenticate(
localizedReason: 'Please complete the biometrics to proceed.',
//biometricOnly: true,
stickyAuth: true,
);
}
return isAuthenticated;
}
}
Это сработало для меня
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
if (await _isBiometricAvailable()) {
await _getListOfBiometricTypes();
await _authenticateUser();
}
runApp(App());
}
Отказ от ответственности: я не очень разбираюсь в разработке под iOS, поэтому я немного экстраполирую из Android здесь.
Я считаю, что проблема в том, что системные диалоги делают ваше приложение неактивным, что ведет к бесконечному циклу
- пользователь возобновляет приложение
- приложение отображает диалог TouchID/FaceID, тем самым делая себя неактивным
- пользователь подтверждает диалог
- диалог закрывается
- Ваше приложение снова выходит на передний план и тем самым возобновляется
- см шаг 2
Возможные решения
- Не запрашивайте аутентификацию при запуске приложения, а скорее, когда в приложении происходят важные действия. Именно так должна была использоваться функция аутентификации, поэтому это самое идиоматическое решение. (мое любимое)
- Установите ограничение по времени, например, показывать диалог только в том случае, если пользователь отсутствовал более x секунд, тем самым отфильтровывая длинные интерактивные фазы от коротких (в том числе для аутентификации). (для меня это обходной путь)