Firebase services have played a keen and vital role in terms of the Flutter framework. Due to its easy implementation techniques and code snippets. With this, offering a wide range of features, today we are going to have a deep look at the initial two; Authentication and Crashlytics features within our application. Let’s explore Mastering Firebase Services – Authentication and Crashlytics in a Flutter App.
Note: Before we jump into this blog post content:
Be sure to check out the latest Firebase integration via FlutterFire CLI from the link below:
To grab full-fledged knowledge regarding this database and to get the most out of it.
– Project Overview
Student Grading Application
Note: If you’ve gone through the above-mentioned blog post, which lists a Student Grading App,
We’re going to apply these features on the same platform since it’s going to reduce a lot of workloads.
– Firebase Auth
Auth (authentication), in general, covers the entire flow of applications from signup to OTP to verification and so on.
However, we’re going to perform a perfect Login and Registration
process with this feature, and others upon deep dive.
— Implementation
Note: Be sure to select the correct Gmail account, otherwise you will end up struggling for the right project.
Under the Firebase Dashboard, Build section, check for the Authentication tab.
Here, onboard yourself with it, you should see Add new Provider. Our main task starts here.
You shall see a thorough listing of different providers with whom Firebase could be connected.
For the sake of simplicity, choose Email/Password, and enable the first switch button.
Let’s now move to our Flutter project and add two additional screens for signup and login respectively.
Both would require the same input.
In the pubspec.yaml
file, add firebase_auth
plugin to enable all the associated services.
user_signup.dart:
Firstly, initialize FirebaseAuth
and add this method:
late FirebaseAuth auth;
@override
void initState() {
// TODO: implement initState
auth = FirebaseAuth.instance;
super.initState();
}
signup() async {
isLoading = true;
await auth.createUserWithEmailAndPassword(email: emailC.text, password:
passC.text);
if (auth.currentUser != null) {
SgNavigation().pushAndRemove(const StudentGrading());
}
isLoading = false;
}
On successful sign-up, you shall be able to see the record inserted under the users’ section in Auth (Firebase dashboard).
Moreover, this method will run fine, but will not give suitable output on failure, so let’s wrap it up with a try-catch approach
and apply Firebase’s built-in exception:
Updated Code Snippet:
signup() async {
try {
isLoading = true;
await auth.createUserWithEmailAndPassword(email: emailC.text, password:
passC.text);
if (auth.currentUser != null) {
SgNavigation().pushAndRemove(const StudentGrading());
}
isLoading = false;
}
on FirebaseException catch (e) {
if(e.code == 'account-exists-with-different-credential') {
SgUtils().showSnackBar("User already registered");
isLoading = false;
}
else if(e.code == 'ERROR_EMAIL_ALREADY_IN_USE') {
SgUtils().showSnackBar("User already registered");
isLoading = false;
}
else if(e.code == 'email-already-in-use') {
SgUtils().showSnackBar("User already registered");
isLoading = false;
}
setState(() {});
}
finally {
isLoading = false;
setState(() {});
}
}
/* Calling the method */
isLoading
? const Center(
child: CircularProgressIndicator(),
)
: ElevatedButton(
onPressed: () {
setState(() {});
signup();
},
child: const Text("Signup")),
user_login.dart:
The process shall remain the same as above, so, here is the direct method overview.
signIn() async {
try {
isLoading = true;
await auth.signInWithEmailAndPassword(email: emailC.text, password:
passC.text);
if (auth.currentUser != null) {
SgNavigation().pushAndRemove(const StudentGrading());
}
isLoading = false;
}
on FirebaseException catch (e) {
if(e.code == 'ERROR_WRONG_PASSWORD') {
SgUtils().showSnackBar("Wrong Password");
isLoading = false;
}
else if(e.code == 'ERROR_USER_NOT_FOUND') {
SgUtils().showSnackBar("No user exists");
isLoading = false;
}
else if(e.code == 'INVALID_LOGIN_CREDENTIALS') {
SgUtils().showSnackBar("No user exists");
isLoading = false;
}
setState(() {});
}
finally {
isLoading = false;
setState(() {});
}
}
/* Calling the method */
isLoading
? const Center(
child: CircularProgressIndicator(),
)
: ElevatedButton(
onPressed: () {
setState(() {});
signIn();
},
child: const Text("Sign in")),
Secondly, one more thing we need to handle is:
Once a user is signed in, it returns to the respective screens.
In the app.dart file
, where this snippet exists:
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
navigatorKey: SgNavigation.navigatorKey,
home: UserSignup(),
);
}
}
Here is the updated & replaced version of it:
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
Stream<bool> isUserSignedIn() async* {
User? auth = FirebaseAuth.instance.currentUser; // Check if user's data
exists
if(auth == null) {
yield false;
}
else {
yield true;
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
navigatorKey: SgNavigation.navigatorKey,
home: StreamBuilder<bool>(
initialData: false,
stream: isUserSignedIn(),
builder: (context, sp) {
return sp.data! ? const StudentGrading() : const UserSignup();
},
)
);
}
}
Snippet for User-Signout:
await FirebaseAuth.instance.signOut();
Video Preview
— Other Stuff
Apart from this, there are various other built-in methods available, such as:
- Password change - Sending email - Verifying phone number and so on...
Let’s do it for a password change:
Add a new screen as change_password.dart
and apply the following snippet:
late User? credential;
@override
void initState() {
// TODO: implement initState
credential = FirebaseAuth.instance.currentUser;
super.initState();
}
updatePassword() async {
try {
isLoading = true;
await credential!.updatePassword(passC.text);
SgUtils().showSnackBar('Password updated successfully');
SgNavigation().pushAndRemove(const UserSignIn());
isLoading = false;
}
catch (e) {
SgUtils().showSnackBar(e.toString());
isLoading = false;
setState(() {});
}
finally {
isLoading = false;
setState(() {});
}
}
Firebase Auth gets completed here, let’s now add a more creative and interesting concept of Crashlytics to our existing App.
– Firebase Crashlytics
Crashlytics, as the name has its answer, reports real-time app crashes when real users use your App. Furthermore, it provides quite useful ways to fix extensive bugs/crashes.
— Implementation
First, add firebase_crashlytics
to pubspec.yaml
.
You could make use of this command too:
flutter pub add firebase_crashlytics
to install the suitable version according to Flutter and Dark SDKs.
Next, be sure to jot down these two commands:
dart pub global activate flutterfire_cli
flutterfire configure
Note: The above-mentioned commands have been taken from the blog post that was mentioned at the start, having the title – Adding Firebase to Flutter App – A Latest Integration Overview.
This command ensures that Firebase services on the respective project are updated with new plugins, including Crashlytics.
Now, under the root method – main()
, add the following snippets:
FlutterError.onError = (errorDetails) {
FirebaseCrashlytics.instance.recordFlutterFatalError(errorDetails);
};
This command passes all errors that are caught by the Flutter framework to Crashlytics.
PlatformDispatcher.instance.onError = (error, stack) {
FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
return true;
};
This command passes all uncaught async errors that are not handled by Flutter to Crashlytics.
The Complete Code Snippet:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
FlutterError.onError = (errorDetails) {
FirebaseCrashlytics.instance.recordFlutterFatalError(errorDetails);
};
PlatformDispatcher.instance.onError = (error, stack) {
FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
return true;
};
runApp(const App());
}
Let’s now run the App and throw an exception intentionally.
Upon the App running, head over to the Crashlytics dashboard, Engage section. You shall see this view:
On Callback:
We would be able to see the error that has been caught:
This is how the Firebase Crashlytics presents you with a surprise.
It’s time to wind up this blog post.
I hope you thoroughly enjoyed it!
Wrapping Up
Mastering Firebase Services – Authentication and Crashlytics in a Flutter App was all about exploring the entire flow of Auth vis-à-vis Crashlytics dashboard, implementation with the help of useful snippets, screenshots, etc.
However, if you think something was missed or presented wrongly, you can jot it down in the comments section below. I would love to help you.
Meanwhile, you can connect with me on the following:
GitHub – Click Here
LinkedIn – Click Here
Once again, thanks for your precious time!