Whenever the user closes the app, they have to re-log back in. I looked and tried to implement authStateChanges. But yet my app is still forcing users to log back in after they close the app. In the App class, you can see that I tried to do exactly the authStateChange but nothing seems to be happening, unfortunately.
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(App());
}
// Firebase Auth Instance
FirebaseAuth auth = FirebaseAuth.instance;
class MyApp extends StatelessWidget {
final Future<FirebaseApp> _initialization = Firebase.initializeApp();
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Tanbo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: LoginPage(),
);
}
}
// This is the main root screen of the Tanbo app
class App extends StatelessWidget {
final Future<FirebaseApp> _initialization = Firebase.initializeApp();
@override
Widget build(BuildContext context) {
return FutureBuilder(
// Initialize FlutterFire
future: _initialization,
builder: (context, snapshot) {
final user = FirebaseAuth.instance.authStateChanges().listen((User user) {
if (user == null) {
print('User signed out');
} else {
print('User signed in');
}
});
// Check for errors
if (snapshot.hasError) {
return ErrorHandler();
}
// Once complete, show your application
if (snapshot.connectionState == ConnectionState.done) {
// If the user isn't logged in, we will be sent to sign up page.
if (user != null) {
return MyApp();
} else {
// If the user is logged in, TabHandler will be shown.
return TabHandler();
}
}
// Otherwise, show something whilst waiting for initialization to complete
return LoadingHandler();
},
);
}
}
FlutterAgency.com is our portal Platform dedicated to Flutter Technology and Flutter Developers. The portal is full of cool resources from Flutter like Flutter Widget Guide , Flutter Projects , Code libs and etc.
The portal is full of cool resources from Flutter like Flutter Widget Guide , Flutter Projects , Code libs and etc. FlutterAgency.com is one of the most popular online portal dedicated to Flutter Technology and daily thousands of unique visitors come to this portal to enhance their knowledge on Flutter.
Firebase returns a Stream of FirebaseUser with its onAuthStateChanged function. There are many ways to listen to the user’s authentication state change. Take a look at below Code Snippet. We return a StreamBuilder to my App’s home page, and the StreamBuilder returns specific pages based on the auth status of the user. ? MainPage()
The problem is you have explicitly made your login page as your homepage. When the app opens, it will automatically read through the main.dart
file and see login page as the assigned Homepage.
This is how you fix it. And also make an authentication system where you can get the logged in user's ID at any point in the app.
What you need:
Step 0: Add the needed dependencies and run flutter pub get. This one is a no brainer.
Step1: Make an auth_services
class:
Code is below
For older versions of firebase auth
:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
class AuthService {
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
final GoogleSignIn _googleSignIn = GoogleSignIn();
Stream<String> get onAuthStateChanged =>
_firebaseAuth.onAuthStateChanged.map(
(FirebaseUser user) => user?.uid,
);
// GET UID
Future<String> getCurrentUID() async {
return (await _firebaseAuth.currentUser()).uid;
}
}
For newer versions of firebase auth dependency:
class AuthService {
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
final GoogleSignIn _googleSignIn = GoogleSignIn();
Stream<User> get onAuthStateChanged => _firebaseAuth.authStateChanges();
// GET UID
Future<String> getCurrentUID() async {
return _firebaseAuth.currentUser.uid;
}
}
Explanation : I have made this class to handle all auth functions. I am making a function called onAuthStateChanged that returns a stream of type User (ids for older versions of firebase auth) and i am going to listen to this stream to find out whether there is a user logged in or not.
Step 2: Create the auth provider that is going to wrap the entire app and make it possible to get our user id anywhere in the app.
Create a file called auth_provider.dart. The code is below.
import 'package:flutter/material.dart';
import 'auth_service.dart';
class Provider extends InheritedWidget {
final AuthService auth;
Provider({
Key key,
Widget child,
this.auth,
}) : super(key: key, child: child);
@override
bool updateShouldNotify(InheritedWidget oldWiddget) {
return true;
}
static Provider of(BuildContext context) =>
(context.dependOnInheritedWidgetOfExactType<Provider>());
}
The next step is to wrap the entire app in this provider widget and set the home controller as the homepage.
Step 3: On the main.dart file, or anywhere really, make a class called HomeController which will handle the logged in state, and set the home Controller as the assigned homepage.
NB: I have set a container of color black to be shown as the app is loading to determine if a user is logged in or not. It is a fairly fast process but if you want to, you can set it to be container of the theme color of your app. You can even set it to be a splash screen. (Please note. This containeris shown for about 1 second at most. From my experience)
Code is below: Import all the necessary things
void main() {
//WidgetsFlutterBinding.ensureInitialized();
// await Firebase.initializeApp();
//only add these if you're on the latest firebase
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Provider(
auth: AuthService(),
child: MaterialApp(
title: 'Dreamora',
theme: ThemeData(
// fontFamily: "Montserrat",
brightness: Brightness.light,
inputDecorationTheme: InputDecorationTheme(
contentPadding:
EdgeInsets.only(top: 10, bottom: 10, left: 10, right: 10),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0),
),
),
primarySwatch: Colors.purple,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: HomeController(),
);
},
),
),}
//(I think i have messed up the brackets here, but, you get the
//gist)
class HomeController extends StatelessWidget {
const HomeController({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
final AuthService auth = Provider.of(context).auth;
return StreamBuilder(
stream: auth.onAuthStateChanged,
builder: (context, AsyncSnapshot<String> snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
final bool signedIn = snapshot.hasData;
return signedIn ? DashBoard() : FirstView();
}
return Container(
color: Colors.black,
);
},
);
}
}
Explanation: The home controller is just a steam builder that listens to the steeam of auth changes we made. If there is any stuff, the user is logged in. If not, he is logged out. Fairly simple. There is like a 1 second lag though in between determining a user's logged in state. Soo, i am returning a black container in that time. The user will see the screen turn black for about a second after opening the app and then boom. Homepage
IMPORTANT: You should wrap your entire app with provider. This is important. Do not forget it.
HOW TO GET THE USER ID AT ANY POINT IN THE APP
Provider.of(context).auth.getCurrentUID()
There you go. Enjoy
[EDIT]As L. Gangemi put it, The new version of Firebase Auth returns a stream of users. So edit the home controller code to be
builder: (context, AsyncSnapshot<User> snapshot) {
I believe it does not work because of this issue - https://github.com/FirebaseExtended/flutterfire/issues/3356
Solved by downgrading firebase-app.js and firebase-auth.js versions to 7.20.0
and replacing authStateChanges() method with userChanges()
FirebaseAuth.instance
.userChanges()
.listen((User user) {
if (user == null) {
print('User is currently signed out!');
} else {
print('User is signed in!');
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With