Я использую Amplify с Flutter для аутентификации пользователя, но не могу получить сеанс пользователя. Ошибка, которую я получаю:
> Launching lib/main.dart on 2109119DG in debug mode...
Running Gradle task 'assembleDebug'...
✓ Built build/app/outputs/flutter-apk/app-debug.apk.
Debug service listening on ws://xxxx
Syncing files to device 2109119DG...
I/amplify:flutter:auth_cognito(27806): Added Auth plugin
E/flutter (27806): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: AmplifyException(message: Auth plugin has not been added to Amplify, recoverySuggestion: Add Auth plugin to Amplify and call configure before calling Auth related APIs, underlyingException: null)
E/flutter (27806): #0 AuthCategory.fetchAuthSession (package:amplify_core/src/category/amplify_auth_category.dart:189:11)
E/flutter (27806): #1 _MyAppState.isUserSignedIn (package:base_app/main.dart:37:39)
E/flutter (27806): #2 _MyAppState.build (package:base_app/main.dart:47:21)
E/flutter (27806): #3 StatefulElement.build (package:flutter/src/widgets/framework.dart:4992:27)
E/flutter (27806): #4 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4878:15)
E/flutter (27806): #5 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5050:11)
E/flutter (27806): #6 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
E/flutter (27806): #7 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4859:5)
E/flutter (27806): #8 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:5041:11)
E/flutter (27806): #9 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4853:5)
E/flutter (27806): #10 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3863:16)
E/flutter (27806): #11 Element.updateChild (package:flutter/src/widgets/framework.dart:3592:18)
E/flutter (27806): #12 RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:1195:16)
E/flutter (27806): #13 RenderObjectToWidgetElement.mount (package:flutter/src/widgets/binding.dart:1164:5)
E/flutter (27806): #14 RenderObjectToWidgetAdapter.attachToRenderTree.<anonymous closure> (package:flutter/src/widgets/binding.dart:1111:18)
E/flutter (27806): #15 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2605:19)
E/flutter (27806): #16 RenderObjectToWidgetAdapter.attachToRenderTree (package:flutter/src/widgets/binding.dart:1110:13)
E/flutter (27806): #17 WidgetsBinding.attachRootWidget (package:flutter/src/widgets/binding.dart:945:7)
E/flutter (27806): #18 WidgetsBinding.scheduleAttachRootWidget.<anonymous closure> (package:flutter/src/widgets/binding.dart:925:7)
E/flutter (27806): #19 Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:18:15)
E/flutter (27806): #20 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:398:19)
E/flutter (27806): #21 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:429:5)
E/flutter (27806): #22 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:192:12)
E/flutter (27806):
D/AWSMobileClient(27806): Using the SignInProviderConfig from `awsconfiguration.json`.
D/AWSMobileClient(27806): Inspecting user state details
I/flutter (27806): Successfully configured
D/AWSMobileClient(27806): Inspecting user state details
I/TetheringManager(27806): registerTetheringEventCallback:com.dontknow.base_app
D/AWSMobileClient(27806): hasFederatedToken: false provider: cognito-idp.eu-central-1.amazonaws.com/eu-central-1_xxxx
D/AWSMobileClient(27806): hasFederatedToken: false provider: cognito-idp.eu-central-1.amazonaws.com/eu-central-1_xxxx
D/AWSMobileClient(27806): Inspecting user state details
D/AWSMobileClient(27806): hasFederatedToken: true provider: cognito-idp.eu-central-1.amazonaws.com/eu-central-1_xxxx
D/AWSMobileClient(27806): waitForSignIn: userState:SIGNED_IN
D/AWSMobileClient(27806): getCredentials: Validated user is signed-in
Я строго следовал туториалам AWS и добавил плагин перед вызовом «настроить» в коде. Что также странно, так это то, что в строке, предшествующей ошибке, действительно загружается плагин.
Вот мой main.dart:
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
_configureAmplify();
}
void _configureAmplify() async {
try {
await Amplify.addPlugin(AmplifyAuthCognito());
await Amplify.configure(amplifyconfig);
print('Successfully configured');
} on Exception catch (e) {
print('Error configuring Amplify: $e');
}
}
Future<bool> isUserSignedIn() async {
final result = await Amplify.Auth.fetchAuthSession();
return result.isSignedIn;
}
@override
Widget build(BuildContext context) {
return Authenticator(
child: MaterialApp(
builder: Authenticator.builder(),
home: FutureBuilder(
future: isUserSignedIn(),
builder: (BuildContext ctx, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return const Center(
child: CircularProgressIndicator(),
);
} else {
return Text("logged in");
}
}),
),
);
}
}
Вы пытаетесь выполнить асинхронную работу в initState()
, но ее завершение до вызова build()
не гарантируется. Поэтому, когда вы вызываете Amplify.Auth.fetchAuthSession()
в своей build()
функции, инициализация и настройка не завершены.
Попробуйте вызвать _configureAmplify()
до runApp()
.
Чтобы это работало, вам также нужно вызвать WidgetsBinding ensureInitialized()
перед _configureAmplify()
.
Как правило, такая работа не относится к коду пользовательского интерфейса (страницы или виджеты). Скорее это должно быть сделано в управлении состоянием приложения.
@Muleque Вполне возможно, что это сработало для них, поскольку такие условия гонки дают совершенно непредсказуемые результаты. Может быть очень трудно определить, все ли работает, пока вы не добавите какое-нибудь тривиальное изменение в дерево виджетов.
к сожалению, когда я помещаю _configureAmplify() в main, я получаю еще одну ошибку: [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Binding has not yet been initialized.
Я застрял здесь.
Да. Это потому, что привязки флаттера не были инициализированы в то время. Вам также необходимо вызвать WidgetsBinding.ensureInitialized()
перед настройкой Amplify.
Наконец-то я нашел подходящее исправление, соответствующее моему уровню навыков, здесь github-repo
Я добавил переменную состояния _isAmplifyConfigured
, которая устанавливается в true, когда _configureAmplify()
завершается. Затем в построителе я проверяю, настроено ли усиление или нет, с помощью простого оператора if-else. Вот полный код:
import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_authenticator/amplify_authenticator.dart';
import 'package:amplify_flutter/amplify_flutter.dart';
import 'package:flutter/material.dart';
import 'amplifyconfiguration.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool _isAmplifyConfigured = false;
@override
void initState() {
super.initState();
_configureAmplify();
}
void _configureAmplify() async {
try {
await Amplify.addPlugin(AmplifyAuthCognito());
await Amplify.configure(amplifyconfig);
setState(() => _isAmplifyConfigured = true);
print('Successfully configured');
} on Exception catch (e) {
print('Error configuring Amplify: $e');
}
}
Future<bool> isUserSignedIn() async {
final result = await Amplify.Auth.fetchAuthSession();
return result.isSignedIn;
}
@override
Widget build(BuildContext context) {
return Authenticator(
child: MaterialApp(
builder: Authenticator.builder(),
home: _isAmplifyConfigured? FutureBuilder(
future: isUserSignedIn(),
builder: (BuildContext ctx, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return const Center(
child: CircularProgressIndicator(),
);
} else {
return Text("logged in");
}
}): Text("not logged in")
),
);
}
}
Имеет смысл. Поскольку я только что скопировал это из учебника AWS, мне интересно, почему они делают это таким образом, если он не работает должным образом.