I have the following code and I need to keep users logged when they reopen the app. I have a flutter phone authentication service from firebase. The given is function to verify google phone authentication. There is a button when pressed 2 functions mentioned below to get call named verifyPhoneNumber() & signInWithPhoneNumber().
void verifyPhoneNumber() async {
if (_formKey.currentState!.validate()) {
setState(() {
loading = true;
});
PhoneVerificationCompleted verificationCompleted =
(PhoneAuthCredential phoneAuthCredential) async {
User? user;
bool error = false;
try {
user = (await firebaseAuth.signInWithCredential(phoneAuthCredential))
.user!;
} catch (e) {
print("Failed to sign in: " e.toString());
error = true;
}
if (!error && user != null) {
String id = user.uid;
//here you can store user data in backend
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => PhoneAuthDataNext(
phone: phoneNumber,
)));
}
};
PhoneVerificationFailed verificationFailed =
(FirebaseAuthException authException) {
showToast(authException.message!);
};
PhoneCodeSent codeSent =
(String? verificationId, [int? forceResendingToken]) async {
showToast('Please check your phone for the verification code.');
this.forceResendingToken = forceResendingToken;
_verificationId = verificationId;
};
PhoneCodeAutoRetrievalTimeout codeAutoRetrievalTimeout =
(String verificationId) {
_verificationId = verificationId;
};
try {
await firebaseAuth.verifyPhoneNumber(
phoneNumber: phoneNumber!,
timeout: const Duration(seconds: 10),
forceResendingToken:
forceResendingToken != null ? forceResendingToken : null,
verificationCompleted: verificationCompleted,
verificationFailed: verificationFailed,
codeSent: codeSent,
codeAutoRetrievalTimeout: codeAutoRetrievalTimeout);
showOtpScreen = true;
} catch (e) {
showToast("Failed to Verify Phone Number: $e");
showOtpScreen = false;
}
setState(() {
loading = false;
});
}
}
void signInWithPhoneNumber() async {
bool error = false;
User? user;
AuthCredential credential;
setState(() {
loading = true;
});
try {
credential = PhoneAuthProvider.credential(
verificationId: _verificationId!,
smsCode: otpEditingController.text,
);
user = (await firebaseAuth.signInWithCredential(credential)).user!;
} catch (e) {
showToast("Failed to sign in: " e.toString());
error = true;
}
if (!error && user != null) {
credential = PhoneAuthProvider.credential(
verificationId: _verificationId!,
smsCode: otpEditingController.text,
);
UserCredential userCredential =
await firebaseAuth.signInWithCredential(credential);
storeTokenAndData(userCredential);
//here you can store user data in backend
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => PhoneAuthDataNext(
phone: phoneNumber,
credential: credential,
)));
}
setState(() {
loading = false;
});
}
Please Give me a solution.
CodePudding user response:
Firebase already restores the user credentials from local storage/shared preferences when the app restarts. But this is an asynchronous process, since it requires a call to the server.
To detect and respond to the authentication state, listen to the authStateChanges stream as shown in the documentation on authentication state.
FirebaseAuth.instance
.authStateChanges()
.listen((User? user) {
if (user == null) {
print('User is currently signed out!');
} else {
print('User is signed in!');
}
});
You'll typically want to wrap FirebaseAuth.instance.authStateChanges() in a StreamBuilder to show the correct UI state based on whether the user is signed in.
CodePudding user response:
Firebase already handles the 'session' for you. You can use the authStateChanges method to check auth state and update your UI as I have done with the code below
class AuthGate extends StatelessWidget {
const AuthGate({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (BuildContext context, AsyncSnapshot<User?> snapshot) {
if (snapshot.hasData) {
return HomePage();
}
return LoginPage();
},
);
}
}
