Simple Recipes App made in Flutter — Firebase and Google Sign-In
Firebase, Google Authentication and Flutter. Let’s see how it works.
Firebase includes a lot of great tools for building, maintaining and improving quality of apps. Let’s have a more detailed look at Google Sign-In and how to integrate this functionality into a Flutter project.
This series of articles describes the implementation of a simple recipes app made in Flutter. In previous articles Simple Recipes App made in Flutter — Introduction and Simple Recipes App made in Flutter — List View we’ve learned how to implement the user interface.
You can find the code used in this and previous articles in the recipes_app repository on github. If you have already read previous articles of this series, we’re ready to go.
Setup
First, we have to create a new Firebase project and add our app to it. I can only recommend you to follow this guide written by Google.
To implement the Google Sign-In functionality we are going to use packages firebase_auth and google_sign_in as libraries. Add the lines that follow to the dependencies
section in pubspec.yaml.
To get the packages execute flutter packages get on the command line.
Now, we can move on to the implementation.
Implementation
Before we start with the implementation we have to choose the pattern for the state management in our app. There are many ways to reach this goal. We’re going to manage the state in the Flutter way of doing it.
Do you remember how we’ve implemented the list view? We’ve created an active parent widget that gets notified by its inactive widgets in order to update the content as soon as the list of favorites changes. The pattern that we are about to implement today is pretty similar. In the implementation we’re going to use the class InheritedWidget.
InheritedWidget ?
Basically, we can describe InheritedWidget
as a parent widget which passes its data down the widget tree. You can access the data from every widget in the app by using the method inheritFromWidgetOfExactType of the BuildContext class.
In previous articles we’ve learned how to access the theme from every widget in the widget tree. We’ve used Theme.of(context)
to get styles of the theme and apply them to our widgets.
Here, we are going to do the same. We’re going to access data of the state by StateWidget.of(context)
. The class StateWidget
is going to wrap a custom InheritedWidget
. Furthermore, it is going to provide the of
method and do some additional work on the initialization of the state.
Let’s start with the implementation step by step.
Model
We are going to store the state of our app as an object of the class StateModel
. The state is going to provide the information about the current signed-in Firebase user. In addition, it is going to say us whether our app is loading.
In order to implement the StateModel
class create a new file state.dart in the model directory.
Here’s the implementation:
Helper Methods
We are going to put the code below in a new file auth.dart in the utils directory. In the next step of the implementation we’re going to use these helper methods to authenticate the user with Google.
You will find that we are using keywords async
and await
in multiple lines of the code that follows. Why do we need async
and await
?
Dart provides us the async
keyword for writing an asynchronous code. We can use this keyword if we want to write methods which are going to run in the background while the rest of the code is being executed at the same time. But how about using async
in combination with the await
keyword?
Let’s see what the official Dart documentation says about it:
Note: Although an async function might perform time-consuming operations, it doesn’t wait for those operations. Instead, the async function executes only until it encounters its first
await
expression (details). Then it returns a Future object, resuming execution only after theawait
expression completes.
Don’t hesitate to experiment with the asynchronous programming in Dart. You can find more about this topic in A Tour of the Dart Language written by the Dart team.
Here’s the implementation of our helper methods:
Cheers! We’re ready to move on.
The State Widget
Let’s take a look at the implementation of our state widget.
We’re going to be able to access the state included into our custom InheritedWidget
from everywhere in the widget tree by using the public class StateWidget
. It is going to implement the of
method. The class _StateDataWidget
that inherits from InheritedWidget
is going to be private and store only the state data in its member of the type _StateWidgetState
.
In this way we are going to encapsulate the way of how we provide access to the state and how we store its data. But what about the logic of the initialization of the state including the usage of our helper methods defined in the last step? This job is going to be done by the class _StateWidgetState
.
Put the code below into a new file called state_widget.dart in the lib directory.
Now, let’s use StateWidget
and change the code in main.dart:
Great! After this change the app’s state is going to be initialized on every start of the app. As a next step, we are going to change the implementation of our app so that it depends on the state.
Home Screen
Until now the route of the login screen has been the initial route of our app. Since we are able to access the state it’s obsolete. If a user is signed-in, we want to put only the HomeScreen
widget into the widget tree. In the next step we are going to change the initial route to the route of the home screen.
Since the property initialRoute
of MaterialApp
overrides the default route /
we do not need to use initialRoute
anymore. Just delete the line in app.dart where initialRoute
is being set. Our app is going to start with the HomeScreen
widget on the next run.
In HomeScreen
we are going to:
- Show a loading indicator if the app is loading
- Show the login screen if there is neither a currently signed-in user nor a previously signed-in user
- Show recipes if a user is signed-in
The code that follows contains new private methods which are being used to implement the scenario described above and build the content based on the app’s state.
Awesome! If you run the app, it’s going to show the login screen because we have not used Firebase and there is no previously signed-in user. We have successfully implemented Google authorization and state management for our app.
To finalize the implementation for today we still need to make a little change in the class _LoginScreenState
.
Login Screen
The widget GoogleSignInButton
in the build method of _LoginScreenState
just navigates to the home screen by now. Let’s change it and use the method signInWithGoogle
of StateWidget
:
Conclusion
Today we have learned a lot about Flutter.
Let me summarize the topics:
- State management by using a custom InheritedWidget as an implementation detail of a public stateful widget
- Authentication by Google developed with the Firebase plugin for Flutter by using packages firebase_auth and google_sign_in
Firebase is a very nice tool for deploying serverless mobile applications. In the next article we’re going to focus closely on Firestore. We’re going to work with real data and store users’ favorites in a cloud database in Firestore.
Thanks a lot for reading. I wish you happy fluttering.