1. Antes de começar
Neste codelab, você vai aprender a adicionar o Firebase Authentication ao seu app Flutter usando o pacote da interface do FlutterFire. Com esse pacote, você vai adicionar a autenticação por e-mail/senha e a autenticação do Google Sign In a um app Flutter. Também vai aprender a configurar um projeto do Firebase e usar a CLI do FlutterFire para inicializar o Firebase no seu app Flutter.
Pré-requisitos
Este codelab presume que você tem alguma experiência com o Flutter. Caso contrário, talvez você queira primeiro aprender o básico. Confira alguns links úteis:
- Faça um tour do framework do widget do Flutter
- Teste o codelab Criar seu primeiro app do Flutter, parte 1
Você também precisa ter alguma experiência com o Firebase, mas não precisa ter adicionado o Firebase a um projeto do Flutter. Se você não conhece o Console do Firebase ou é novo no Firebase, consulte os links a seguir:
O que você vai criar
Este codelab orienta você a criar o fluxo de autenticação de um app Flutter usando o Firebase para autenticação. O aplicativo terá uma tela de login, uma tela de "Registro", uma tela de recuperação de senha e uma tela de perfil do usuário.
O que você vai aprender
Este codelab aborda:
- Como adicionar o Firebase a um app Flutter
- Configuração do Console do Firebase
- Como usar a CLI do Firebase para adicionar o Firebase ao seu aplicativo
- Como usar a CLI do FlutterFire para gerar a configuração do Firebase no Dart
- Adicionar o Firebase Authentication ao seu app Flutter
- Configuração do Firebase Authentication no console
- Como adicionar o login com e-mail e senha ao pacote
firebase_ui_auth
- Como adicionar o registro de usuário com o pacote
firebase_ui_auth
- Como adicionar a página "Esqueceu a senha?"
- Como adicionar o Login do Google com
firebase_ui_auth
- Configurar o app para funcionar com vários provedores de login.
- Como adicionar uma tela de perfil do usuário ao seu app com o pacote
firebase_ui_auth
Este codelab trata especificamente de adicionar um sistema de autenticação robusto usando o pacote firebase_ui_auth
. Como você vai notar, esse app inteiro, com todos os recursos acima, pode ser implementado com cerca de 100 linhas de código.
Pré-requisitos
- Conhecimento prático do Flutter (link em inglês) e do SDK instalado.
- Um editor de texto (os ambientes de desenvolvimento integrado da JetBrains, o Android Studio e o VS Code são compatíveis com o Flutter)
- Navegador Google Chrome ou outra plataforma de desenvolvimento da sua preferência para o Flutter. Alguns comandos do terminal neste codelab vão presumir que o app está sendo executado no Chrome.
2. Criar e configurar um projeto do Firebase
A primeira tarefa que você precisa concluir é criar um projeto do Firebase no console da Web do Firebase.
Criar um projeto do Firebase
- Faça login no Firebase.
- No Console do Firebase, clique em Adicionar projeto (ou Criar um projeto) e insira um nome para o projeto do Firebase (por exemplo, FlutterFire-UI-Codelab).
- Clique nas opções de criação de projeto. Aceite os termos do Firebase se solicitado. Ignore a configuração do Google Analytics, porque você não vai usá-lo para este app.
Para saber mais sobre os projetos do Firebase, consulte Noções básicas sobre projetos do Firebase.
Ativar o login por e-mail para o Firebase Authentication
O app que você está criando usa o Firebase Authentication para permitir que os usuários façam login e também permite que novos usuários se registrem no aplicativo Flutter.
O Firebase Authentication precisa ser ativado por meio do Console do Firebase e de configuração especial após a ativação.
Para permitir que os usuários façam login no app da Web, primeiro use o método de login E-mail/senha. Mais tarde, você vai adicionar o método Google Sign-In.
- No Console do Firebase, abra o menu Build no painel à esquerda.
- Clique em Autenticação e depois no botão Começar. Em seguida, clique na guia Método de login (ou clique aqui para acessar diretamente a guia Método de login).
- Clique em E-mail/Senha na lista Provedores de login, defina a chave Ativar como "Ativado" e clique em Salvar.
3. Configurar o app Flutter
Você vai precisar fazer o download do código inicial e instalar a CLI do Firebase antes de começar.
Acessar o código inicial
Clone o repositório do GitHub (link em inglês) na linha de comando:
git clone https://github.com/flutter/codelabs.git flutter-codelabs
Como alternativa, se você tiver a ferramenta de CLI do GitHub instalada:
gh repo clone flutter/codelabs flutter-codelabs
O exemplo de código será clonado no diretório flutter-codelabs
da sua máquina, que contém o código de uma coleção de codelabs. O código deste codelab está no subdiretório flutter-codelabs/firebase-auth-flutterfire-ui
.
O diretório flutter-codelabs/firebase-auth-flutterfire-ui
contém dois projetos do Flutter. Um se chama complete
e o outro é start
. O diretório start
contém um projeto incompleto, e é nele que você vai passar mais tempo.
cd flutter-codelabs/firebase-auth-flutterfire-ui/start
Se você quiser pular para a frente ou conferir como algo vai ficar quando estiver concluído, procure no diretório "complete" para fazer uma referência cruzada.
Se você quiser acompanhar o codelab e adicionar código por conta própria, comece com o app do Flutter em flutter-codelabs/firebase-auth-flutterfire-ui/start
e adicione código a esse projeto durante todo o codelab. Abra ou importe esse diretório no ambiente de desenvolvimento integrado de sua preferência.
Instalar a CLI do Firebase
A CLI do Firebase oferece ferramentas para gerenciar seus projetos do Firebase. A CLI é necessária para a CLI do FlutterFire, que você vai instalar em breve.
Há várias maneiras de instalar a CLI. A maneira mais simples, se você estiver usando o MacOS ou Linux, é executar este comando no terminal:
curl -sL https://firebase.tools | bash
Depois de instalar a CLI, você precisa fazer a autenticação com o Firebase.
- Faça login no Firebase com sua Conta do Google executando o seguinte comando:
firebase login
- Esse comando conecta sua máquina local ao Firebase e concede acesso aos seus projetos do Firebase.
- Liste seus projetos do Firebase para testar se a CLI está instalada corretamente e tem acesso à sua conta. Execute este comando:
firebase projects:list
- A lista exibida precisa conter os mesmos projetos que aparecem no Console do Firebase. Você verá pelo menos
flutterfire-ui-codelab.
Instalar a CLI do FlutterFire
A CLI do FlutterFire é uma ferramenta que ajuda a facilitar o processo de instalação do Firebase em todas as plataformas compatíveis com seu app do Flutter. Ela foi criada com base na CLI do Firebase.
Primeiro, instale a CLI:
dart pub global activate flutterfire_cli
Verifique se a CLI foi instalada. Execute o comando a seguir e verifique se a CLI exibe o menu de ajuda.
flutterfire -—help
Adicionar o projeto do Firebase ao app Flutter
Configurar o FlutterFire
Você pode usar o FlutterFire para gerar o código Dart necessário para usar o Firebase no seu app Flutter.
flutterfire configure
Quando esse comando for executado, você vai precisar selecionar o projeto do Firebase que quer usar e as plataformas que quer configurar.
As capturas de tela a seguir mostram as solicitações que você precisa responder.
- Selecione o projeto que você quer usar. Nesse caso, use
flutterfire-ui-codelab
- Selecione as plataformas que você quer usar. Neste codelab, há etapas para configurar a Autenticação do Firebase para Flutter na Web, no iOS e no Android, mas você pode configurar seu projeto do Firebase para usar todas as opções.
- Esta captura de tela mostra a saída no final do processo. Se você já conhece o Firebase, vai perceber que não precisou criar aplicativos de plataforma (por exemplo, um aplicativo Android) no console, e a CLI do FlutterFire fez isso por você.
Quando terminar, observe o app Flutter no editor de texto. A CLI do FlutterFire gerou um novo arquivo chamado firebase_options.dart
. Esse arquivo contém uma classe chamada FirebaseOptions, que tem variáveis estáticas que armazenam a configuração do Firebase necessária para cada plataforma. Se você tiver selecionado todas as plataformas ao executar flutterfire configure
, verá valores estáticos chamados web
, android
, ios
e macos
.
firebase_options.dart
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
show defaultTargetPlatform, kIsWeb, TargetPlatform;
/// Default [FirebaseOptions] for use with your Firebase apps.
///
/// Example:
/// ```dart
/// import 'firebase_options.dart';
/// // ...
/// await Firebase.initializeApp(
/// options: DefaultFirebaseOptions.currentPlatform,
/// );
/// ```
class DefaultFirebaseOptions {
static FirebaseOptions get currentPlatform {
if (kIsWeb) {
return web;
}
// ignore: missing_enum_constant_in_switch
switch (defaultTargetPlatform) {
case TargetPlatform.android:
return android;
case TargetPlatform.iOS:
return ios;
case TargetPlatform.macOS:
return macos;
}
throw UnsupportedError(
'DefaultFirebaseOptions are not supported for this platform.',
);
}
static const FirebaseOptions web = FirebaseOptions(
apiKey: 'AIzaSyCqFjCV_9CZmYeIvcK9FVy4drmKUlSaIWY',
appId: '1:963656261848:web:7219f7fca5fc70afb237ad',
messagingSenderId: '963656261848',
projectId: 'flutterfire-ui-codelab',
authDomain: 'flutterfire-ui-codelab.firebaseapp.com',
storageBucket: 'flutterfire-ui-codelab.firebasestorage.app',
measurementId: 'G-DGF0CP099H',
);
static const FirebaseOptions android = FirebaseOptions(
apiKey: 'AIzaSyDconZaCQpkxIJ5KQBF-3tEU0rxYsLkIe8',
appId: '1:963656261848:android:c939ccc86ab2dcdbb237ad',
messagingSenderId: '963656261848',
projectId: 'flutterfire-ui-codelab',
storageBucket: 'flutterfire-ui-codelab.firebasestorage.app',
);
static const FirebaseOptions ios = FirebaseOptions(
apiKey: 'AIzaSyBqLWsqFjYAdGyihKTahMRDQMo0N6NVjAs',
appId: '1:963656261848:ios:d9e01cfe8b675dfcb237ad',
messagingSenderId: '963656261848',
projectId: 'flutterfire-ui-codelab',
storageBucket: 'flutterfire-ui-codelab.firebasestorage.app',
iosClientId: '963656261848-v7r3vq1v6haupv0l1mdrmsf56ktnua60.apps.googleusercontent.com',
iosBundleId: 'com.example.complete',
);
static const FirebaseOptions macos = FirebaseOptions(
apiKey: 'AIzaSyBqLWsqFjYAdGyihKTahMRDQMo0N6NVjAs',
appId: '1:963656261848:ios:d9e01cfe8b675dfcb237ad',
messagingSenderId: '963656261848',
projectId: 'flutterfire-ui-codelab',
storageBucket: 'flutterfire-ui-codelab.firebasestorage.app',
iosClientId: '963656261848-v7r3vq1v6haupv0l1mdrmsf56ktnua60.apps.googleusercontent.com',
iosBundleId: 'com.example.complete',
);
}
O Firebase usa o termo “aplicativo” para se referir a uma versão específica de uma plataforma específica em um projeto do Firebase. Por exemplo, o projeto do Firebase chamado FlutterFire-ui-codelab tem vários aplicativos: um para Android, um para iOS, um para MacOS e um para Web.
O método DefaultFirebaseOptions.currentPlatform
usa o tipo enumerado TargetPlatform
exposto pelo Flutter para detectar a plataforma em que o app está sendo executado e retorna os valores de configuração do Firebase necessários para o aplicativo correto.
Adicionar pacotes do Firebase ao app Flutter
A etapa final de configuração é adicionar os pacotes relevantes do Firebase ao seu projeto Flutter. O arquivo firebase_options.dart
precisa conter erros, porque ele depende de pacotes do Firebase que ainda não foram adicionados. No terminal, verifique se você está na raiz do projeto do Flutter em flutter-codelabs/firebase-emulator-suite/start
. Em seguida, execute os três comandos a seguir:
flutter pub add firebase_core
flutter pub add firebase_auth
flutter pub add firebase_ui_auth
Esses são os únicos pacotes necessários neste momento.
Inicializar o Firebase
Para usar os pacotes adicionados e o DefaultFirebaseOptions.currentPlatform,
, atualize o código na função main
do arquivo main.dart
.
main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(const MyApp());
}
Esse código faz duas coisas.
WidgetsFlutterBinding.ensureInitialized()
informa ao Flutter que ele não deve começar a executar o código do widget do aplicativo até que o framework do Flutter seja inicializado completamente. O Firebase usa canais de plataforma nativos, que exigem que o framework esteja em execução.- O
Firebase.initializeApp
configura uma conexão entre o app Flutter e o projeto do Firebase. ODefaultFirebaseOptions.currentPlatform
é importado do arquivofirebase_options.dart
gerado. Esse valor estático detecta a plataforma em que você está executando e transmite as chaves do Firebase correspondentes.
4. Adicionar a página inicial da autenticação da interface do Firebase
A interface do Firebase para Auth oferece widgets que representam telas inteiras no seu aplicativo. Essas telas processam fluxos de autenticação diferentes no seu app, como "Fazer login", "Registro", "Esqueci a senha", "Perfil do usuário" e muito mais. Para começar, adicione uma página de destino ao app que funcione como um protetor de autenticação para o aplicativo principal.
App do Material Design ou da Cupertino
A interface do FlutterFire exige que seu aplicativo seja envolvido em um MaterialApp ou CupertinoApp. Dependendo da sua escolha, a interface vai refletir automaticamente as diferenças entre os widgets do Material Design e do Cupertino. Neste codelab, use MaterialApp
, que já foi adicionado ao app em app.dart
.
app.dart
import 'package:flutter/material.dart';
import 'auth_gate.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const AuthGate(),
);
}
}
Verificar o estado da autenticação
Antes de exibir uma tela de login, você precisa determinar se o usuário está autenticado no momento. A maneira mais comum de verificar isso é detectar o authStateChanges do FirebaseAuth usando o plug-in do Firebase Auth.
No exemplo de código acima, o MaterialApp
está criando um widget AuthGate
no método de build. Esse é um widget personalizado, não fornecido pela interface do FlutterFire.
Esse widget precisa ser atualizado para incluir o stream authStateChanges
.
A API authStateChanges
retorna um Stream
com o usuário atual (se ele tiver feito login) ou nulo. Para se inscrever nesse estado no app, use o widget StreamBuilder do Flutter e transmita o stream para ele.
O StreamBuilder
é um widget criado com base no snapshot mais recente de dados de um Stream que você transmite. Ele é recriado automaticamente quando o stream emite um novo snapshot.
Atualize o código em auth_gate.dart
.
auth_gate.dart (link em inglês)
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [],
);
}
return const HomeScreen();
},
);
}
}
StreamBuilder.stream
está sendo transmitidoFirebaseAuth.instance.authStateChanged
, o stream mencionado, que vai retornar um objetoUser
do Firebase se o usuário tiver feito a autenticação. Caso contrário,null
será retornado.- Em seguida, o código está usando
snapshot.hasData
para verificar se o valor do stream contém o objetoUser
. - Se não houver, ele retornará um widget
SignInScreen
. No momento, essa tela não faz nada. Isso será atualizado na próxima etapa. - Caso contrário, ele retornará um
HomeScreen
, que é a parte principal do aplicativo que apenas usuários autenticados podem acessar.
O SignInScreen
é um widget que vem do pacote de interface do FlutterFire. Esse será o foco da próxima etapa deste codelab. Ao executar o app nesse momento, você verá uma tela de login em branco.
5. Tela de login
O widget SignInScreen
, fornecido pela FlutterFire UI, adiciona a seguinte funcionalidade:
- Permite que os usuários façam login
- Se os usuários esquecerem a senha, poderão tocar em "Esqueceu a senha?" e acessar um formulário para redefinir a senha.
- Se um usuário ainda não estiver registrado, ele pode tocar em "Registrar-se" e ser direcionado para outro formulário que permite que ele se inscreva.
Novamente, isso requer apenas algumas linhas de código. Recupere o código no widget do AuthGate:
auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider(), // new
],
);
}
return const HomeScreen();
},
);
}
}
O widget SignInScreen
e o argumento providers
são o único código necessário para aproveitar todas as funcionalidades mencionadas acima. Uma tela de login com as entradas de texto "e-mail" e "senha" vai aparecer, além do botão "Fazer login".
Embora funcional, ele não tem estilo. O widget expõe parâmetros para personalizar a aparência da tela de login. Por exemplo, você pode adicionar o logotipo da sua empresa.
Personalizar a tela de login
headerBuilder
Usando o argumento SignInScreen.headerBuilder
, você pode adicionar os widgets que quiser acima do formulário de login. Esse widget só aparece em telas estreitas, como dispositivos móveis. Em telas amplas, você pode usar SignInScreen.sideBuilder
, que será discutido mais adiante neste codelab.
Atualize o arquivo auth_gate.dart
com este código:
auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider(),
],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('assets/flutterfire_300x.png'),
),
);
},
);
}
return const HomeScreen();
},
);
}
}
O argumento headerBuilder requer uma função do tipo HeaderBuilder, que é definida no pacote de interface do FlutterFire.
typedef HeaderBuilder = Widget Function(
BuildContext context,
BoxConstraints constraints,
double shrinkOffset,
);
Como é um callback, ele expõe valores que você pode usar, como BuildContext
e BoxConstraints
, e exige que você retorne um widget. O widget retornado é exibido na parte de cima da tela. Neste exemplo, o novo código adiciona uma imagem à parte de cima da tela. O aplicativo ficará assim:
Criador de legendas
A tela de login expõe três parâmetros adicionais que permitem personalizar a tela: subtitleBuilder
, footerBuilder
e sideBuilder
.
O subtitleBuilder
é um pouco diferente, já que os argumentos de callback incluem uma ação, que é do tipo AuthAction
. O AuthAction
é um tipo enumerado que pode ser usado para detectar se a tela em que o usuário está é a de "login" ou "registro".
Atualize o código em auth_gate.dart para usar o subtitleBuilder.
auth_gate.dart (link em inglês)
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider()
],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
subtitleBuilder: (context, action) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: action == AuthAction.signIn
? const Text('Welcome to FlutterFire, please sign in!')
: const Text('Welcome to Flutterfire, please sign up!'),
);
},
);
}
return const HomeScreen();
},
);
}
}
Atualize o aplicativo. Ele vai ficar assim:
Criador de rodapés
O argumento footerBuilder é o mesmo que subtitleBuilder. Ele não expõe BoxConstraints
ou shrinkOffset
, porque é destinado a texto, não a imagens. No entanto, você pode adicionar qualquer widget.
Adicione um rodapé à tela de login com este código.
auth_gate.dart (link em inglês)
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider()
],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
subtitleBuilder: (context, action) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: action == AuthAction.signIn
? const Text('Welcome to FlutterFire, please sign in!')
: const Text('Welcome to Flutterfire, please sign up!'),
);
},
footerBuilder: (context, action) {
return const Padding(
padding: EdgeInsets.only(top: 16),
child: Text(
'By signing in, you agree to our terms and conditions.',
style: TextStyle(color: Colors.grey),
),
);
},
);
}
return const HomeScreen();
},
);
}}
Criador secundário
O argumento SignInScreen.sidebuilder aceita um callback e, desta vez, os argumentos são BuildContext
e double shrinkOffset
. O widget retornado pelo sideBuilder será exibido à esquerda do formulário de login e apenas em telas amplas. Isso significa que o widget só vai aparecer em apps para computador e da Web.
Internamente, a FlutterFire UI usa um ponto de interrupção para determinar se o conteúdo do cabeçalho deve ser mostrado (em telas altas, como dispositivos móveis) ou se o conteúdo lateral deve ser mostrado (em telas largas, computadores ou na Web). Especificamente, se uma tela tiver mais de 800 pixels de largura, o conteúdo do builder lateral será mostrado, mas o do cabeçalho não. Se a tela tiver menos de 800 pixels de largura, o oposto será verdadeiro.
Atualize o código em auth_gate.dart para adicionar widgets sideBuilder.
auth_gate.dart
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider(),
],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
subtitleBuilder: (context, action) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: action == AuthAction.signIn
? const Text('Welcome to FlutterFire, please sign in!')
: const Text('Welcome to Flutterfire, please sign up!'),
);
},
footerBuilder: (context, action) {
return const Padding(
padding: EdgeInsets.only(top: 16),
child: Text(
'By signing in, you agree to our terms and conditions.',
style: TextStyle(color: Colors.grey),
),
);
},
sideBuilder: (context, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
);
}
return const HomeScreen();
},
);
}
}
Agora, o app vai ficar assim quando você expandir a largura da janela (se estiver usando o Flutter na Web ou o MacOS).
Criar um usuário
Neste ponto, todo o código para essa tela está pronto. No entanto, antes de fazer login, você precisa criar um usuário. Você pode fazer isso com a tela "Registrar" ou criar um usuário no console do Firebase.
Para usar o console:
- Acesse a tabela "Usuários" no console do Firebase.
- Clique aqui
- Selecione "flutterfire-ui-codelab" (ou outro projeto se você usou um nome diferente). Você verá esta tabela:
- Clique no botão "Adicionar usuário".
- Digite um endereço de e-mail e uma senha para o novo usuário. O e-mail e a senha podem ser falsos, como inseri na imagem abaixo. Isso funcionará, mas a funcionalidade "Esqueci a senha" não funcionará se você usar um endereço de e-mail falso.
- Clique em "Adicionar usuário"
Agora, você pode voltar ao seu aplicativo Flutter e fazer login de um usuário pela página de login. O app vai ficar assim:
6. Tela de perfil
A FlutterFire UI também fornece um widget ProfileScreen
, que oferece muitas funcionalidades em poucas linhas de código.
Adicionar o widget ProfileScreen
Navegue até o arquivo home.dart
no seu editor de texto. Atualize com este código:
home.dart
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: const Icon(Icons.person),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<ProfileScreen>(
builder: (context) => const ProfileScreen(),
),
);
},
)
],
automaticallyImplyLeading: false,
),
body: Center(
child: Column(
children: [
Image.asset('dash.png'),
Text(
'Welcome!',
style: Theme.of(context).textTheme.displaySmall,
),
const SignOutButton(),
],
),
),
);
}
}
O novo código de observação é o callback transmitido para IconButton.isPressed method.
. Quando esse IconButton
é pressionado, seu app cria uma nova rota anônima e navega até ela. Essa rota vai mostrar o widget ProfileScreen
, que é retornado do callback MaterialPageRoute.builder
.
Recarregue o app e toque no ícone no canto superior direito (na barra de apps). Uma página como esta será exibida:
Essa é a interface padrão fornecida pela página de interface do FlutterFire. Todos os botões e campos de texto são conectados ao Firebase Auth e funcionam imediatamente. Por exemplo, é possível inserir um nome no campo de texto "Name" e a interface do FlutterFire vai chamar o método FirebaseAuth.instance.currentUser?.updateDisplayName
, que o salvará no Firebase.
Como sair
No momento, se você pressionar o botão "Sair", o app não mudará. Você será desconectado, mas não será redirecionado para o widget do AuthGate. Para implementar, use o parâmetro ProfileScreen.actions.
Primeiro, atualize o código em home.dart.
home.dart
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: const Icon(Icons.person),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<ProfileScreen>(
builder: (context) => ProfileScreen(
actions: [
SignedOutAction((context) {
Navigator.of(context).pop();
})
],
),
),
);
},
)
],
automaticallyImplyLeading: false,
),
body: Center(
child: Column(
children: [
Image.asset('dash.png'),
Text(
'Welcome!',
style: Theme.of(context).textTheme.displaySmall,
),
const SignOutButton(),
],
),
),
);
}
}
Agora, ao criar uma instância de ProfileScreen
, você também transmite uma lista de ações a ela para o argumento ProfileScreen.actions
. Essas ações são do tipo FlutterFireUiAction
. Há muitas classes diferentes que são subtipos de FlutterFireUiAction
. Em geral, elas são usadas para instruir o app a reagir a diferentes mudanças no estado de autenticação. A SignedOutAction chama uma função de callback que você fornece quando o estado do Firebase Auth muda para o currentUser ser nulo.
Ao adicionar um callback que chama Navigator.of(context).pop()
quando SignedOutAction é acionado, o app vai navegar para a página anterior. Neste aplicativo de exemplo, há apenas uma rota permanente, que mostra a página de login se não houver um usuário conectado, e a página inicial, se houver um. Como isso acontece quando o usuário sai da conta, o app vai mostrar a página de login.
Personalizar a página do perfil
Semelhante à página de login, a página de perfil é personalizável. Primeiro, nossa página atual não tem como voltar à página inicial quando um usuário está na página do perfil. Para corrigir isso, forneça uma AppBar ao widget ProfileScreen.
home.dart
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: const Icon(Icons.person),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<ProfileScreen>(
builder: (context) => ProfileScreen(
appBar: AppBar(
title: const Text('User Profile'),
),
actions: [
SignedOutAction((context) {
Navigator.of(context).pop();
})
],
),
),
);
},
)
],
automaticallyImplyLeading: false,
),
body: Center(
child: Column(
children: [
Image.asset('dash.png'),
Text(
'Welcome!',
style: Theme.of(context).textTheme.displaySmall,
),
const SignOutButton(),
],
),
),
);
}
}
O argumento ProfileScreen.appBar
aceita um widget AppBar
do pacote do Flutter Material, para que ele possa ser tratado como qualquer outro AppBar
criado e transmitido para um Scaffold
. Neste exemplo, a funcionalidade padrão de adicionar automaticamente um botão "Voltar" é mantida, e a tela agora tem um título.
Adicionar crianças à tela de perfil
O widget ProfileScreen também tem um argumento opcional chamado "children". Esse argumento aceita uma lista de widgets, que serão colocados verticalmente dentro de um widget de coluna que já é usado internamente para criar a ProfileScreen. Esse widget de coluna no método de build ProfileScreen vai colocar os filhos que você transmite acima do botão "Sair".
Atualize o código em home.dart para mostrar o logotipo da empresa aqui, semelhante à tela de login.
home.dart
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: const Icon(Icons.person),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<ProfileScreen>(
builder: (context) => ProfileScreen(
appBar: AppBar(
title: const Text('User Profile'),
),
actions: [
SignedOutAction((context) {
Navigator.of(context).pop();
})
],
children: [
const Divider(),
Padding(
padding: const EdgeInsets.all(2),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
),
],
),
),
);
},
)
],
automaticallyImplyLeading: false,
),
body: Center(
child: Column(
children: [
Image.asset('dash.png'),
Text(
'Welcome!',
style: Theme.of(context).textTheme.displaySmall,
),
const SignOutButton(),
],
),
),
);
}
}
Atualize o app para ver esta tela:
7. Login no Google Auth multiplataforma
A interface do FlutterFire também oferece widgets e funcionalidades para autenticação com provedores de terceiros, como Google, Twitter, Facebook, Apple e GitHub.
Para integrar com a autenticação do Google, instale o plug-in oficial firebase_ui_oauth_google e as dependências dele, que processarão o fluxo de autenticação nativa. No terminal, navegue até a raiz do seu projeto do Flutter e digite o seguinte comando:
flutter pub add google_sign_in flutter pub add firebase_ui_oauth_google
Ativar o provedor de login do Google
Em seguida, ative o provedor do Google no Console do Firebase:
- Navegue até a tela Provedores de login de autenticação no console.
- Clique em "Adicionar novo provedor".
- Selecione "Google".
- Ative a opção "Ativar" e pressione "Salvar".
- Se aparecer um modal com informações sobre o download de arquivos de configuração, clique em "Concluído".
- Confirme se o provedor de login do Google foi adicionado.
Adicionar botão de Login do Google
Com o recurso ativado, adicione o widget necessário para mostrar um botão estilizado do Login do Google na página de login. Navegue até o arquivo auth_gate.dart e atualize o código para o seguinte:
auth_gate.dart (link em inglês)
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:firebase_ui_oauth_google/firebase_ui_oauth_google.dart'; // new
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider(),
GoogleProvider(clientId: "YOUR_WEBCLIENT_ID"), // new
],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
subtitleBuilder: (context, action) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: action == AuthAction.signIn
? const Text('Welcome to FlutterFire, please sign in!')
: const Text('Welcome to Flutterfire, please sign up!'),
);
},
footerBuilder: (context, action) {
return const Padding(
padding: EdgeInsets.only(top: 16),
child: Text(
'By signing in, you agree to our terms and conditions.',
style: TextStyle(color: Colors.grey),
),
);
},
sideBuilder: (context, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
);
}
return const HomeScreen();
},
);
}
}
O único código novo aqui é a adição de GoogleProvider(clientId: "YOUR_WEBCLIENT_ID")
à configuração do widget SignInScreen.
Com isso adicionado, atualize o aplicativo e você verá um botão de Login do Google.
Configurar o botão de login
O botão não funciona sem configurações adicionais. Se você estiver desenvolvendo com o Flutter Web, essa é a única etapa que precisa ser adicionada para que isso funcione. Outras plataformas exigem etapas adicionais, que serão discutidas mais adiante.
- Acesse a página "Provedores de autenticação" no Console do Firebase.
- Clique no provedor do Google.
- Clique no painel de expansão "Configuração do SDK da Web".
- Copie o valor de "ID do cliente da Web"
- Volte ao editor de texto e atualize a instância de
GoogleProvider
no arquivoauth_gate.dart
transmitindo esse ID para o parâmetro chamadoclientId
.
GoogleProvider(
clientId: "YOUR_WEBCLIENT_ID"
)
Depois que o ID do cliente da Web for inserido, recarregue o app. Quando você pressionar o botão "Fazer login com o Google", uma nova janela vai aparecer (se você estiver usando a Web) que vai orientar você pelo fluxo de login do Google. Inicialmente, ele terá esta aparência:
Configurar o iOS
Para que isso funcione no iOS, há um processo de configuração adicional.
- Navegue até a tela "Configurações do projeto" no Console do Firebase. Será exibido um card listando seus apps do Firebase, como este:
- Clique no iOS. O nome do seu aplicativo será diferente do meu. Quando o meu diz "concluir", o seu vai dizer "iniciar", se você usou o projeto
flutter-codelabs/firebase-auth-flutterfire-ui/start
para acompanhar este codelab. - Clique no botão "GoogleServices-Info.plist" para fazer o download do arquivo de configuração necessário.
- Arraste e solte o arquivo baixado para o diretório chamado .
/ios/Runner
no seu projeto do Flutter. - Abra o Xcode executando o seguinte comando do terminal na raiz do seu projeto:
open ios/Runner.xcworkspace
- Clique com o botão direito do mouse no diretório do Runner e selecione Adicionar arquivos ao "Runner".
- Selecione GoogleService-Info.plist no gerenciador de arquivos.
- No editor de texto (que não é o Xcode), adicione os atributos CFBundleURLTypes abaixo ao arquivo [my_project]/ios/Runner/Info.plist.
<!-- Put me in the [my_project]/ios/Runner/Info.plist file -->
<!-- Google Sign-in Section -->
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<!-- TODO Replace this value: -->
<!-- Copied from GoogleService-Info.plist key REVERSED_CLIENT_ID -->
<string>com.googleusercontent.apps.861823949799-vc35cprkp249096uujjn0vvnmcvjppkn</string>
</array>
</dict>
</array>
<!-- End of the Google Sign-in Section -->
- É necessário substituir o
GoogleProvider.clientId
adicionado na configuração da Web pelo ID do cliente associado ao seu ID do cliente do Firebase iOS. Primeiro, você pode encontrar esse ID no arquivofirebase_options.dart
, como parte da constanteiOS
. Copie o valor transmitido paraiOSClientId
.
static const FirebaseOptions ios = FirebaseOptions(
apiKey: 'YOUR API KEY',
appId: 'YOUR APP ID',
messagingSenderId: '',
projectId: 'PROJECT_ID',
storageBucket: 'PROJECT_ID.firebasestorage.app',
iosClientId: 'IOS CLIENT ID', // Find your iOS client Id here.
iosBundleId: 'com.example.BUNDLE',
);
- Cole esse valor no argumento
GoogleProvider.clientId
do widgetAuthGate
.
import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:firebase_ui_oauth_google/firebase_ui_oauth_google.dart';
import 'package:flutter/material.dart';
import 'home.dart';
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SignInScreen(
providers: [
EmailAuthProvider(),
GoogleProvider(clientId: "YOUR IOS CLIENT ID"), // replace String
],
headerBuilder: (context, constraints, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
subtitleBuilder: (context, action) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: action == AuthAction.signIn
? const Text('Welcome to FlutterFire, please sign in!')
: const Text('Welcome to Flutterfire, please sign up!'),
);
},
footerBuilder: (context, action) {
return const Padding(
padding: EdgeInsets.only(top: 16),
child: Text(
'By signing in, you agree to our terms and conditions.',
style: TextStyle(color: Colors.grey),
),
);
},
sideBuilder: (context, shrinkOffset) {
return Padding(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: Image.asset('flutterfire_300x.png'),
),
);
},
);
}
return const HomeScreen();
},
);
}
}
Se o app do Flutter já estiver em execução no iOS, será necessário desativá-lo completamente e executar o aplicativo novamente. Caso contrário, execute o app no iOS.
8. Parabéns!
Você concluiu o codelab da interface do Firebase Auth para Flutter. O código completo deste codelab está disponível no diretório "complete" no GitHub: Flutter Codelabs.
O que vimos
- Configurar um app Flutter para usar o Firebase
- Como configurar um projeto do Firebase no Console do Firebase
- CLI do FlutterFire
- CLI do Firebase
- Como usar o Firebase Authentication
- Como usar a interface do FlutterFire para processar a autenticação do Firebase no seu app do Flutter facilmente
Próximas etapas
- Saiba mais sobre como usar o Firestore e o Authentication no Flutter: Codelab do Firebase para Flutter
- Conheça outras ferramentas do Firebase para criar seu aplicativo Flutter:
- Cloud Storage
- Cloud Functions
- Realtime Database
Saiba mais
- Site do Firebase: firebase.google.com
- Site do Flutter: flutter.dev (link em inglês)
- Widgets do Flutter para Firebase do FlutterFire: firebase.flutter.dev (link em inglês)
- Canal do Firebase no YouTube
- Canal do Flutter no YouTube
O Sparky está aqui para comemorar com você!