Flutter Firebase Login
Это содержимое пока не доступно на вашем языке.
In the following tutorial, we’re going to build a Firebase Login Flow in Flutter using the Bloc library.
- BlocProvider, a Flutter widget which provides a bloc to its children.
- BlocBuilder, a Flutter widget that handles building the widget in response to new states.
- Using Cubit instead of Bloc. What’s the difference?
- Adding events with context.read.
- Prevent unnecessary rebuilds with Equatable.
- RepositoryProvider, a Flutter widget which provides a repository to its children.
- BlocListener, a Flutter widget which invokes the listener code in response to state changes in the bloc.
- Adding events with context.read.
We’ll start off by creating a brand new Flutter project.
Just like in the login tutorial, we’re going to create internal packages to better layer our application architecture and maintain clear boundaries and to maximize both reusability as well as improve testability.
In this case, the firebase_auth and google_sign_in packages are going to be our data layer so we’re only going to be creating an AuthenticationRepository
to compose data from the two API clients.
The AuthenticationRepository
will be responsible for abstracting the internal implementation details of how we authenticate and fetch user information. In this case, it will be integrating with Firebase but we can always change the internal implementation later on and our application will be unaffected.
We’ll start by creating packages/authentication_repository
and a pubspec.yaml
at the root of the project.
Next, we can install the dependencies by running:
in the authentication_repository
directory.
Just like most packages, the authentication_repository
will define it’s API surface via packages/authentication_repository/lib/authentication_repository.dart
Next, let’s take a look at the models.
The User
model will describe a user in the context of the authentication domain. For the purposes of this example, a user will consist of an email
, id
, name
, and photo
.
The AuthenticationRepository
is responsible for abstracting the underlying implementation of how a user is authenticated, as well as how a user is fetched.
The AuthenticationRepository
exposes a Stream<User>
which we can subscribe to in order to be notified of when a User
changes. In addition, it exposes methods to signUp
, logInWithGoogle
, logInWithEmailAndPassword
, and logOut
.
That’s it for the AuthenticationRepository
. Next, let’s take a look at how to integrate it into the Flutter project we created.
We need to follow the firebase_auth usage instructions in order to hook up our application to Firebase and enable google_sign_in.
We can replace the generated pubspec.yaml
at the root of the project with the following:
Notice that we are specifying an assets directory for all of our applications local assets. Create an assets
directory in the root of your project and add the bloc logo asset (which we’ll use later).
Then install all of the dependencies:
The main.dart
file can be replaced with the following:
It’s simply setting up some global configuration for the application and calling runApp
with an instance of App
.
Just like in the login tutorial, our app.dart
will provide an instance of the AuthenticationRepository
to the application via RepositoryProvider
and also creates and provides an instance of AuthenticationBloc
. Then AppView
consumes the AuthenticationBloc
and handles updating the current route based on the AuthenticationState
.
The AppBloc
is responsible for managing the global state of the application. It has a dependency on the AuthenticationRepository
and subscribes to the user
Stream in order to emit new states in response to changes in the current user.
The AppState
consists of an AppStatus
and a User
. Two named constructors are exposed: unauthenticated
and authenticated
to make it easier to work with.
The AppEvent
has two subclasses:
AppUserChanged
which notifies the bloc that the current user has changed.AppLogoutRequested
which notifies the bloc that the current user has requested to be logged out.
The AppBloc
responds to incoming AppEvents
and transforms them into outgoing AppStates
. Upon initialization, it immediately subscribes to the user
stream from the AuthenticationRepository
and adds an AuthenticationUserChanged
event internally to process changes in the current user.
An Email
and Password
input model are useful for encapsulating the validation logic and will be used in both the LoginForm
and SignUpForm
(later in the tutorial).
Both input models are made using the formz package and allow us to work with a validated object rather than a primitive type like a String
.
The LoginPage
is responsible for creating and providing an instance of LoginCubit
to the LoginForm
.
The LoginCubit
is responsible for managing the LoginState
of the form. It exposes APIs to logInWithCredentials
, logInWithGoogle
, as well as gets notified when the email/password are updated.
The LoginState
consists of an Email
, Password
, and FormzStatus
. The Email
and Password
models extend FormzInput
from the formz package.
The LoginCubit
has a dependency on the AuthenticationRepository
in order to sign the user in either via credentials or via google sign in.
The LoginForm
is responsible for rendering the form in response to the LoginState
and invokes methods on the LoginCubit
in response to user interactions.
The LoginForm
also renders a “Create Account” button which navigates to the SignUpPage
where a user can create a brand new account.
The SignUp
structure mirrors the Login
structure and consists of a SignUpPage
, SignUpView
, and SignUpCubit
.
The SignUpPage
is just responsible for creating and providing an instance of the SignUpCubit
to the SignUpForm
(exactly like in LoginPage
).
The SignUpCubit
manages the state of the SignUpForm
and communicates with the AuthenticationRepository
in order to create new user accounts.
The SignUpState
reuses the same Email
and Password
form input models because the validation logic is the same.
The SignUpCubit
is extremely similar to the LoginCubit
with the main exception being it exposes an API to submit the form as opposed to login.
The SignUpForm
is responsible for rendering the form in response to the SignUpState
and invokes methods on the SignUpCubit
in response to user interactions.
After a user either successfully logs in or signs up, the user
stream will be updated which will trigger a state change in the AuthenticationBloc
and will result in the AppView
pushing the HomePage
route onto the navigation stack.
From the HomePage
, the user can view their profile information and log out by tapping the exit icon in the AppBar
.
At this point we have a pretty solid login implementation using Firebase and we have decoupled our presentation layer from the business logic layer by using the Bloc Library.
The full source for this example can be found here.