Reputation: 95
I have a scanning app that uses Firebase for Authorisation, I used Shared Preferences to keep the user signed in after closing the app but I get an error that says,
The getter 'uid' was called on null. Receiver: null Tried calling: uid
Below is my Main.dart page
In this main block, there is a ternary condition that is supposed to determine which page to go to based on wether the app was just closed or signed out
Future <void> main() async {
WidgetsFlutterBinding.ensureInitialized();
SharedPreferences preferences = await SharedPreferences.getInstance();
var email = preferences.get("email");
await Firebase.initializeApp();
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
title: "Jinjer Pay",
theme: ThemeData(
primaryColor: Colors.amber,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: email != null ? Login() : Scan_QR()));
// home: Login()));
}
Code for Login Page I put the shared preferences block at the end of the Auth. block. I am not sure if I have initialised the shared preferences block correctly with the Auth block.
RaisedButton(
child: Text(
"Log In",
style: TextStyle(fontSize: 19),
),
color: Colors.amberAccent,
elevation: 10,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(15)),
onPressed: () async {
if (formKey.currentState.validate()) {
Loading();
formKey.currentState.save();
setState(() => loading = true);
try {
UserCredential res;
String userID;
res = (await FirebaseAuth.instance
.signInWithEmailAndPassword(
email:
_emailController.text,
password:
_passwordController
.text));
userID = res.user.uid;
if (res != null) {
setState(() {
loading = false;
});
Navigator.pop(context);
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
Scan_QR()),
);
}
} catch (e) {
if (FirebaseAuth
.instance.currentUser.uid !=
e.code) {
setState(() {
loading = false;
});
}
if (e.code == "unknown") {
Fluttertoast.showToast(
msg:
"Email/Password Field cannot be Empty",
toastLength:
Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor:
Colors.redAccent,
textColor: Colors.white,
fontSize: 16.0);
}
if (e.code == "wrong-password") {
Fluttertoast.showToast(
msg:
"Your password is incorrect",
toastLength:
Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor:
Colors.redAccent,
textColor: Colors.white,
fontSize: 16.0);
}
if (e.code == "invalid-email") {
Fluttertoast.showToast(
msg:
"Email/Password Field cannot be Empty",
toastLength:
Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor:
Colors.redAccent,
textColor: Colors.white,
fontSize: 16.0);
}
if (e.code == "user-not-found") {
Fluttertoast.showToast(
msg:
"No User found with this email",
toastLength:
Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor:
Colors.redAccent,
textColor: Colors.white,
fontSize: 16.0);
}
if (e.code == "user-disabled") {
Fluttertoast.showToast(
msg:
"user with this email has been disabled",
toastLength:
Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor:
Colors.redAccent,
textColor: Colors.white,
fontSize: 16.0);
}
if (e.code ==
"network-request-failed") {
Fluttertoast.showToast(
msg:
"A network error has occurred",
toastLength:
Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor:
Colors.redAccent,
textColor: Colors.white,
fontSize: 16.0);
}
if (e.code == "too-many-requests") {
Fluttertoast.showToast(
msg:
"Too many requests, try again later",
toastLength:
Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor:
Colors.redAccent,
textColor: Colors.white,
fontSize: 16.0);
}
SharedPreferences preferences = await SharedPreferences.getInstance();
preferences.setString("email", _emailController.text);
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
Scan_QR()),
);
print(e);
_passwordController.text = "";
}
}
},
),
I have a Sign Out Block that is supposed to sign out the previously signed-in user data from the app and wait for a new user to sign in.
Future<void> SignOut() async {
SharedPreferences preferences = await SharedPreferences.getInstance();
preferences.remove("email");
await FirebaseAuth.instance.signOut().then((value) => Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => Login())));
}
Upvotes: 2
Views: 1049
Reputation: 733
You could use StreamBuilder
to check the authentication process when open the app instead of using the shared preference.
FirebaseAuth mAuth = FirebaseAuth.instance;
@override
Widget build(BuildContext context) {
return StreamBuilder<FirebaseUser>(
stream: mAuth.onAuthStateChanged,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
FirebaseUser user = snapshot.data;
if (user == null) {
//add the logic when user is null
} else {
// add the logic when user is not null
}
} else {
// add the logic when connection state not active
}
},
);
}
Then you could do your authentication process without using the shared preference.
Hope this answer will solve your problem!
Upvotes: 1