[英]Screen not refreshing when user logs in with Firebase Authentication
I have a Flutter app in which I am using firebase_auth ^0.18.1+2
to log the user in with an email/password.我有一个 Flutter 应用程序,我在其中使用firebase_auth
^0.18.1+2
使用电子邮件/密码登录用户。 There are two screens:有两个屏幕:
After the user logs in, however, the app does not refresh to show the Dashboard;但是,用户登录后,应用程序不会刷新以显示仪表板; the Home screen continues to appear.
主屏幕继续出现。 Can anyone advise?
任何人都可以建议吗?
After logging in, only when I perform a Hot Restart does the Dashboard appear.登录后,只有当我执行热重启时,仪表板才会出现。
main.dart
: main.dart
:
MultiProvider(
providers: [
// Provider 1
// ...
// Provider 2
// ...
Provider<AuthService>(
create: (_) => AuthService(),
),
// Provider 4
// ...
// Provider 5
// ...
],
child: App(),
),
auth_service.dart
: auth_service.dart
:
Stream<User> get authStateChanges => FirebaseAuth.instance.authStateChanges();
app.dart
: app.dart
:
final AuthService authService =
Provider.of<AuthService>(context, listen: false);
return MaterialApp(
debugShowCheckedModeBanner: false,
home: StreamBuilder<User>(
stream: authService.authStateChanges,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
if (snapshot.hasData) {
authService.firebaseUser = snapshot.data;
return Scaffold(
body: FutureBuilder<DocumentSnapshot>(
future: authService.fetchExtraUserData(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
authService.user = snapshot.data;
// Dashboard does not appear, however Flutter logging shows that Dashboard
// initState() is being called in the background.
if (snapshot.hasData) {
return Dashboard();
} else {
return Scaffold(
backgroundColor: Colors.white,
body: Center(
child: CircularProgressIndicator(),
),
);
}
} else {
return Scaffold(
backgroundColor: Colors.white,
body: Center(
child: CircularProgressIndicator(),
),
);
}
},
),
);
} else {
return Home();
}
} else {
return Scaffold(
backgroundColor: Colors.white,
body: Center(
child: CircularProgressIndicator(),
),
);
}
},
),
);
I have also tried the following with no luck:我也试过以下没有运气:
Removing the FutureBuilder
which calls authService.fetchExtraUserData()
删除调用
authService.fetchExtraUserData()
的FutureBuilder
Moving StreamBuilder
above MaterialApp
将
StreamBuilder
移到MaterialApp
之上
return StreamBuilder<User>( stream: authService.authStateChanges, builder: (context, snapshot) { return MaterialApp( debugShowCheckedModeBanner: false, home: snapshot.hasData? Dashboard(): Home(), ); }, );
It is also interesting to see that logging out works correctly - the user is returned to the Home screen.还有趣的是,注销工作正常 - 用户返回到主屏幕。 This shows that
authStateChanges
is working correctly in this case.这表明
authStateChanges
在这种情况下工作正常。
logout(BuildContext context) async => await authService.signOut();
flutter doctor
output: flutter doctor
output:
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel beta, 1.23.0-18.1.pre, on Mac OS X 10.15.7 19H2 x86_64)
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.1)
[✓] Xcode - develop for iOS and macOS (Xcode 12.3)
[✓] Chrome - develop for the web
[✓] Android Studio (version 4.1)
[✓] VS Code (version 1.52.0)
[✓] Connected device (3 available)
Well I have a demo which does work perfectly fine, let me post the relevant parts:好吧,我有一个运行良好的演示,让我发布相关部分:
main.dart I used ChangeNotifierProvider.value()
main.dart我使用了
ChangeNotifierProvider.value()
...
return MultiProvider(
providers: [
ChangeNotifierProvider.value(
value: AuthenticationService.instance(),
),
],
child: MaterialApp(
theme: ThemeData(
primarySwatch: Colors.red,
),
home: _screenMaker(context),
));
...
This is my _screenMaker Widget in the main.dart
which is receiving the realtime state since im working with Consumers
from the provider Package这是我在
main.dart
中的Consumers
Widget
Widget _screenMaker(BuildContext context) {
return Consumer<AuthenticationService>(
builder: (ctx, AuthenticationService auth, _) {
switch (auth.status) {
case Status.Uninitialized:
return Splash();
case Status.Unauthenticated:
case Status.Authenticating:
return LoginPage();
case Status.NoVerification:
return Verification();
case Status.Authenticated:
return UserInfoPage(
user: auth.user,
);
}
},
);
}
Lets look at my AuthentificationService
class, Im going to post the complete content but the magic for the state management is happening at the beginning after my getters:让我们看看我的
AuthentificationService
class,我将发布完整的内容,但 state 管理的魔力发生在我的吸气剂之后:
import 'package:flutter/widgets.dart';
import 'package:firebase_auth/firebase_auth.dart';
enum Status { Uninitialized, Authenticated, Authenticating, Unauthenticated , NoVerification}
class AuthenticationService with ChangeNotifier {
FirebaseAuth _auth = FirebaseAuth.instance;
User _user;
Status _status = Status.Uninitialized;
Status get status => _status;
User get user => _user;
// Magic happens here
AuthenticationService.instance() : _auth = FirebaseAuth.instance {
_auth.authStateChanges().listen((firebaseUser) {
print('--- authstate listening');
if (firebaseUser == null) {
_status = Status.Unauthenticated;
} else if(firebaseUser != null && firebaseUser.emailVerified == false) {
_status = Status.NoVerification;
} else {
_user = firebaseUser;
_status = Status.Authenticated;
}
notifyListeners();
});
}
Future<bool> signIn(String email, String password) async {
try {
_status = Status.Authenticating;
notifyListeners();
await _auth.signInWithEmailAndPassword(email: 'admin@admin.de', password: 'admin123');
if(_auth.currentUser.emailVerified == null){
_status = Status.Unauthenticated;
print('--- user email verified is null');
notifyListeners();
}
if(_auth.currentUser.emailVerified != true) {
_status = Status.Authenticated;
return true;
} else {
print('--- user needs confirmation');
try {
_status = Status.NoVerification;
await user.sendEmailVerification();
signOut();
return true;
} catch (e) {
print('--- An error occured while trying to send email verification');
print(e.message);
}
}
} catch (e) {
print('--- $e');
signOut();
notifyListeners();
return false;
}
}
// Signout function
Future signOut() async {
_auth.signOut();
_status = Status.Unauthenticated;
notifyListeners();
return Future.delayed(Duration.zero);
}
}
Thats everything you need.这就是你需要的一切。 Read more about Consumers, this is a really powerful article for understanding it: https://medium.com/flutter-community/managing-flutter-state-using-provider-e26c78060c26
阅读有关消费者的更多信息,这是一篇非常强大的文章,可以帮助您理解它: https://medium.com/flutter-community/managing-flutter-state-using-provider-e26c78060c26
I think the issue is because of the false
parameters passed into the provider.of<T>()
call.我认为这个问题是因为传入
provider.of<T>()
调用的false
参数。
Try final AuthService authService = Provider.of<AuthService>(context);
尝试
final AuthService authService = Provider.of<AuthService>(context);
which tried to listen to a value exposed with the provider, from outside of the widget tree.它试图从小部件树的外部侦听提供者公开的值。
final AuthService authService =
Provider.of<AuthService>(context, listen: false);
In this line argument listen: false
tells the widget to not rebuild when the state changes(user logs in).在这一行中,参数
listen: false
告诉小部件在 state 更改(用户登录)时不重建。
Try removing listen: false
from the provider.尝试从提供者中删除
listen: false
。
Also instead of creating provider as也不是将提供者创建为
Provider<AuthService>(
create: (_) => AuthService(),
)
which only exposes Auth Service values to widget tree and does not rebuild widget tree when state changes.仅在 state 更改时将 Auth Service 值公开给小部件树,并且不会重建小部件树。
Use ChangeNotifierProvider
to listen to changes and rebuild your widget tree like this使用
ChangeNotifierProvider
来监听更改并像这样重建您的小部件树
ChangeNotifierProvider(
create: (context) => AuthService(),
)
Ok Try this,好的试试这个,
First modify your firebase api class like this首先像这样修改您的 firebase api class
Stream<User> get user {
return auth.onAuthStateChanged
.map((FirebaseUser user) => _userFromFirebase(user));
}
User _userFromFirebase(FirebaseUser user) {
return user != null ? User(id: user.uid) : null;
}
after in your main.dart file modify like this在你的 main.dart 文件中修改如下
void main() => runApp(MyApp()); void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StreamProvider<User>.value(
value: AuthService().user,
child: MaterialApp(
theme: ThemeData(scaffoldBackgroundColor: Colors.blueAccent),
debugShowCheckedModeBanner: false,
home: LoginWrapper(),
//home: McqLoader(),
),
);
}
}
make Login wrapper class like this像这样制作登录包装器 class
class LoginWrapper extends StatelessWidget {
@override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
if (user == null) {
return Login();
} else {
return DashboardPage(id: user.id,);
}
}
}
class LandingPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final auth = Provider.of<AuthBase>(context);
return StreamBuilder<Object>(
stream: auth.onAuthChange,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
User user = snapshot.data;
if (user == null) {
return SignIn();
}else {
return HomePage();
}
}
return CupertinoActivityIndicator();
},
);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.