Adicionar um fluxo de autenticação do usuário a um app do Flutter usando a FirebaseUI

1. Antes de começar

Neste codelab, você aprenderá a adicionar o Firebase Authentication ao seu app do Flutter usando o pacote de interface do FlutterFire. Com esse pacote, você vai adicionar a autenticação por e-mail/senha e a autenticação de Login do Google a um app do Flutter. Você também aprenderá a configurar um projeto do Firebase e a usar a CLI do FlutterFire para inicializar o Firebase no seu app criado com o 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:

Você também deve ter alguma experiência com o Firebase, mas não tem problema se você nunca adicionou o Firebase a um projeto Flutter. Se você não conhece o console do Firebase ou é completamente novo no Firebase, primeiro consulte os links a seguir:

O que você vai criar

Este codelab orienta você na criação do fluxo de autenticação para um app Flutter usando o Firebase para Authentication. 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.

6604fc9157f2c6ae.png eab9509a41074930.png da49189a5838e0bb.png b2ccfb3632b77878.png

Conteúdo

Este codelab abrange:

  • Como adicionar o Firebase a um app do Flutter
  • Configuração do Console do Firebase
  • Como usar a CLI do Firebase para adicionar o Firebase ao aplicativo
  • Usar a CLI do FlutterFire para gerar configurações do Firebase no Dart
  • Como adicionar o Firebase Authentication ao seu app do Flutter
  • Configuração do Firebase Authentication no console
  • Como adicionar login com e-mail e senha com o pacote firebase_ui_auth
  • Como adicionar o registro de usuário com o pacote firebase_ui_auth
  • Como adicionar uma página "Esqueceu a senha?"
  • Adicionando 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 de usuário ao aplicativo com o pacote firebase_ui_auth

Este codelab trata especificamente de adicionar um sistema robusto de autenticação usando o pacote firebase_ui_auth. Como você verá, o app inteiro, com todos os recursos acima, pode ser implementado com cerca de cem linhas de código.

Pré-requisitos

  • Conhecimento prático do Flutter (link em inglês) e do SDK instalado.
  • Um editor de texto (ambientes de desenvolvimento integrado do JetBrains, o Android Studio e o VS Code são compatíveis com o Flutter).
  • o navegador Google Chrome ou outra plataforma de desenvolvimento preferencial para o Flutter; Alguns comandos de terminal neste codelab presumem que você está executando o app no Chrome.

2. Criar e configurar um projeto do Firebase

A primeira tarefa que você precisa realizar é criar um projeto do Firebase no console da Web do Firebase.

criar um projeto do Firebase

  1. Faça login no Firebase.
  2. No Console do Firebase, clique em Adicionar projeto (ou Criar um projeto) e digite um nome para ele (por exemplo, FlutterFire-UI-Codelab).

df42a5e3d9584b48.png

  1. Clique nas opções de criação do projeto. Se solicitado, aceite os termos do Firebase. Pular a configuração do Google Analytics, porque ele não vai ser usado neste app.

d1fcec48bf251eaa.png

Para saber mais sobre os projetos do Firebase, consulte Noções básicas sobre os projetos do Firebase.

O app que você está criando usa o Firebase Authentication para permitir que os usuários façam login no app e que novos usuários se registrem pelo aplicativo Flutter.

O Firebase Authentication precisa ser ativado usando o Console do Firebase e precisa de configuração especial depois de ativado.

Ativar o login por e-mail para o Firebase Authentication

Para permitir que os usuários façam login no app da Web, primeiro você precisa usar o método de login de E-mail/senha. Mais tarde, você vai adicionar o método de Login do Google.

  1. No Console do Firebase, expanda o menu Build no painel esquerdo.
  2. Clique em Autenticação e, em seguida, no botão Primeiros passos e na guia Método de login (ou clique aqui para acessar a guia Método de login).
  3. Clique em E-mail/senha na lista Provedores de login, ative a opção Ativar e clique em Salvar. 58e3e3e23c2f16a4.png

3. Configurar o app do Flutter

Antes de começar, faça o download do código inicial e instale a CLI do Firebase.

Acessar o código inicial

Clone o repositório do GitHub (link em inglês) da linha de comando:

git clone https://github.com/flutter/codelabs.git flutter-codelabs

Como alternativa, se você tiver a ferramenta CLI do GitHub instalada:

gh repo clone flutter/codelabs flutter-codelabs

O exemplo de código precisa ser clonado no diretório flutter-codelabs da 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 é chamado de complete, e o outro é chamado de start. O diretório start contém um projeto incompleto, e é nele que você vai passar a maior parte do tempo.

cd flutter-codelabs/firebase-auth-flutterfire-ui/start

Se você quiser avançar ou ver como algo deve ficar quando completo, procure no diretório chamado complete para fazer 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 ao longo do codelab. Abra ou importe esse diretório para o 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ê instalará em breve.

Há várias maneiras de instalar a CLI. A maneira mais simples, se você estiver usando o MacOS ou o Linux, é executar este comando no seu terminal:

curl -sL https://firebase.tools | bash

Depois de instalar a CLI, faça a autenticação com o Firebase.

  1. Faça login no Firebase com sua Conta do Google executando o seguinte comando:
firebase login
  1. Esse comando conecta sua máquina local ao Firebase e concede acesso aos seus projetos do Firebase.
  1. Liste seus projetos do Firebase para testar se a CLI está instalada corretamente e tem acesso à conta. Execute este comando:
firebase projects:list
  1. A lista exibida precisa conter os mesmos projetos do Firebase listados no Console do Firebase. Deve haver pelo menos flutterfire-ui-codelab.

Instalar a CLI do FlutterFire

A CLI do FlutterFire é uma ferramenta que facilita o processo de instalação do Firebase em todas as plataformas compatíveis com seu app do Flutter. Ela é baseada 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 gera o menu de ajuda.

flutterfire -—help

Adicionar seu projeto do Firebase ao app Flutter

Configurar o FlutterFire

É possível usar o FlutterFire para gerar o código Dart necessário para usar o Firebase no seu app criado com o Flutter.

flutterfire configure

Quando esse comando é executado, você precisa selecionar qual projeto do Firebase quer usar e quais plataformas quer configurar.

As capturas de tela abaixo mostram as solicitações que você precisa responder.

  1. Selecione o projeto que você quer usar. Nesse caso, use flutterfire-ui-codelab 1359cdeb83204baa.png.
  2. Selecione as plataformas que você quer usar. Neste codelab, existem etapas para configurar o Firebase Authentication para Flutter na Web, iOS e Android, mas você pode configurar seu projeto do Firebase para usar todas as opções. 301c9534f594f472.png
  3. Esta captura de tela mostra a saída no final do processo. Se estiver familiarizado com o Firebase, você perceberá que não era necessário criar aplicativos de plataforma (por exemplo, um aplicativo Android) no console, e que a CLI do FlutterFire fez isso por você. 12199a85ade30459.png

Quando isso terminar, observe o app do Flutter no seu 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 mantêm 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 (link em inglês)

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.appspot.com',
   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.appspot.com',
 );

 static const FirebaseOptions ios = FirebaseOptions(
   apiKey: 'AIzaSyBqLWsqFjYAdGyihKTahMRDQMo0N6NVjAs',
   appId: '1:963656261848:ios:d9e01cfe8b675dfcb237ad',
   messagingSenderId: '963656261848',
   projectId: 'flutterfire-ui-codelab',
   storageBucket: 'flutterfire-ui-codelab.appspot.com',
   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.appspot.com',
   iosClientId: '963656261848-v7r3vq1v6haupv0l1mdrmsf56ktnua60.apps.googleusercontent.com',
   iosBundleId: 'com.example.complete',
 );
}

O Firebase usa o termo "aplicativo" para se referir a um build específico de uma plataforma 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 a Web.

O método DefaultFirebaseOptions.currentPlatform usa a enumeração TargetPlatform exposta 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 do Flutter. O arquivo firebase_options.dart vai conter erros porque depende de pacotes do Firebase que ainda não foram adicionados. No terminal, verifique se você está na raiz do projeto 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 que você precisa no momento.

Inicializar o Firebase

Para usar os pacotes adicionados e o DefaultFirebaseOptions.currentPlatform,, atualize o código na função main no arquivo main.dart.

main.dart (link em inglês)

void main() async {
 WidgetsFlutterBinding.ensureInitialized();
 await Firebase.initializeApp(
   options: DefaultFirebaseOptions.currentPlatform,
 );


 runApp(const MyApp());
}

Esse código faz duas coisas.

  1. WidgetsFlutterBinding.ensureInitialized() instrui o Flutter a não começar a executar o código do widget do aplicativo até que o framework do Flutter seja completamente inicializado. O Firebase usa canais de plataforma nativos, que exigem que o framework esteja em execução.
  2. O Firebase.initializeApp configura uma conexão entre o app Flutter e o projeto do Firebase. O DefaultFirebaseOptions.currentPlatform é importado do arquivo firebase_options.dart gerado. Esse valor estático detecta em qual plataforma você está sendo executado e transmite as chaves do Firebase correspondentes.

4. Adicionar página inicial de autenticação da interface do Firebase

A interface do Firebase para Auth fornece widgets que representam telas inteiras no seu aplicativo. Essas telas lidam com diferentes fluxos de autenticação em todo o aplicativo, como Login, Registro, Esqueci a senha, Perfil do usuário e muito mais. Para começar, adicione ao seu aplicativo uma página de destino que atue como uma proteção de autenticação para o aplicativo principal.

App Material ou Cupertino

A interface do FlutterFire exige que seu aplicativo seja unido a um MaterialApp ou CupertinoApp. Dependendo da sua escolha, a interface vai refletir automaticamente as diferenças dos widgets do Material Design ou da Cupertino. Neste codelab, use MaterialApp, que já foi adicionado ao app em app.dart.

app.dart (link em inglês)

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. 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 fluxo authStateChanges.

A API authStateChanges retorna um Stream com o usuário atual (se ele tiver feito login) ou nulo se ele não estiver conectado. Para se inscrever nesse estado no nosso aplicativo, você pode usar o widget StreamBuilder do Flutter e transmitir o stream para ele.

O StreamBuilder é um widget criado com base no snapshot mais recente dos dados de um stream transmitido. 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 transmitido para FirebaseAuth.instance.authStateChanged, o fluxo mencionado, que retornará um objeto User do Firebase se o usuário tiver feito a autenticação. Caso contrário, retornará null.
  • Em seguida, o código usa snapshot.hasData para verificar se o valor do stream contém o objeto User.
  • Se não houver, ele vai retornar um widget SignInScreen. Atualmente, essa tela não faz nada. Isso será atualizado na próxima etapa.
  • Caso contrário, ele retorna um HomeScreen, que é a parte principal do aplicativo que só os usuários autenticados podem acessar.

O SignInScreen é um widget 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 interface do FlutterFire, adiciona a seguinte funcionalidade:

  • Permite que os usuários façam login
  • Se os usuários esquecerem a senha, eles poderão tocar em "Esqueceu a senha?" e serão direcionados a um formulário de redefinição.
  • Se um usuário ainda não estiver registrado, ele poderá tocar em "Registrar" e ser direcionado para outro formulário que permita a inscrição.

Novamente, isso requer apenas algumas linhas de código. Retorne ao código no widget AuthGate:

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(), // new
            ],
          );
        }

        return const HomeScreen();
      },
    );
  }
}

O widget SignInScreen e o argumento providers dele são o único código necessário para acessar toda a funcionalidade mencionada. Você verá uma tela de login com entradas de texto "e-mail" e "senha", 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

cabeçalho

Com o argumento SignInScreen.headerBuilder, você pode adicionar os widgets que quiser acima do formulário de login. Atualize o arquivo auth_gate.dart 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('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,
);

Por ser um callback, ele expõe valores que podem ser usados, como BuildContext e BoxConstraints, e exige que você retorne um widget. O widget retornado será exibido na parte superior da tela. Neste exemplo, o novo código adiciona uma imagem à parte de cima da tela. Agora, o aplicativo deve ficar assim:

73d7548d91bbd2ab.png

Criador de legendas

A tela de login expõe três outros parâmetros que permitem personalizar a tela: subtitleBuilder, footerBuilder e sideBuilder.

O subtitleBuilder é um pouco diferente, porque os argumentos de callback incluem uma ação, que é do tipo AuthAction. AuthAction é uma enumeração que pode ser usada 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 ficará assim:

O argumento footerBuilder é o mesmo que o subtitleBuilder. Ele não expõe BoxConstraints ou shrinkOffset, já que ele é destinado a texto em vez de imagens. No entanto, você pode adicionar o widget que quiser.

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 lateral

O argumento SignInScreen.sidebuilder aceita um callback e, desta vez, os argumentos são BuildContext e double shrinkOffset. O widget que o sideBuilder retorna será exibido à esquerda do formulário de login e apenas em telas grandes. Na verdade, isso significa que o widget será exibido apenas em apps da Web e de computador.

Internamente, a interface do FlutterFire usa um ponto de interrupção para determinar se o conteúdo do cabeçalho precisa ser mostrado (em telas altas, como em dispositivos móveis) ou o conteúdo lateral precisa ser mostrado (em telas widescreen, computadores ou Web). Especificamente, se uma tela tiver mais de 800 pixels de largura, o conteúdo do criador lateral será mostrado, mas o 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 (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),
               ),
             );
           },
           sideBuilder: (context, shrinkOffset) {
             return Padding(
               padding: const EdgeInsets.all(20),
               child: AspectRatio(
                 aspectRatio: 1,
                 child: Image.asset('flutterfire_300x.png'),
               ),
             );
           },
         );
       }
       return const HomeScreen();
     },
   );
 }
}

O app vai ficar assim quando você expandir a largura da janela (se estiver usando o Flutter na Web ou MacOS).

8dc60b4e5d7dd2d0.png

Criar um usuário

Neste ponto, todo o código da tela está concluído. Antes de fazer login, porém, é necessário criar um usuário. Você pode fazer isso na tela "Registrar" ou criar um usuário no console do Firebase.

Para usar o console:

  1. Acesse a tabela "Usuários" no Console do Firebase.
  2. Clique aqui
  3. Selecione "flutterfire-ui-codelab" ou outro projeto caso você tenha usado um nome diferente. Você vai encontrar esta tabela:

f038fd9a58ed60d9.png

  1. Clique no botão "Adicionar usuário".

2d78390d4c5dbbfa.png

  1. Digite um endereço de e-mail e uma senha para o novo usuário. Pode ser um e-mail e uma senha falsos, como eu digitei na imagem abaixo. Isso vai funcionar, mas a funcionalidade "Esqueci a senha" não vai funcionar se você usar um endereço de e-mail falso.

62ba0feb33d54add.png

  1. Clique em "Adicionar usuário"

32b236b3ef94d4c7.png

Agora, você pode retornar ao aplicativo do Flutter e fazer o login de um usuário na página de login. O app vai ficar assim:

dd43d260537f3b1a.png

6. Tela do perfil

A interface do FlutterFire também oferece um widget ProfileScreen, que oferece muitas funcionalidades com apenas algumas linhas de código.

Adicionar 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 o IconButton.isPressed method.. Quando esse IconButton é pressionado, o aplicativo cria uma nova rota anônima e navega até ela. Essa rota exibirá o widget ProfileScreen, que é retornado do callback MaterialPageRoute.builder.

Atualize o aplicativo e pressione o ícone no canto superior direito (na barra de aplicativos). Ele exibirá uma página como esta:

36487fc4ab4f26a7.png

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, se você inserir um nome no campo de texto "Nome", a interface do FlutterFire chamará o método FirebaseAuth.instance.currentUser?.updateDisplayName, que salvará esse nome no Firebase.

Saindo

Por enquanto, se você pressionar o botão "Sair", o aplicativo não mudará. Você será desconectado, mas não será levado de volta ao widget AuthGate. Para implementar isso, 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 para o argumento ProfileScreen.actions. Essas ações são do tipo FlutterFireUiAction. Há muitas classes diferentes que são subtipos de FlutterFireUiAction e, em geral, elas são usadas para instruir o app a reagir a diferentes mudanças de estado de autenticação. O SignedOutAction chama uma função de callback que é fornecida quando o estado de autenticação do Firebase muda para o currentUser sendo nulo.

Ao adicionar um callback que chama Navigator.of(context).pop() quando SignedOutAction é acionado, o app vai navegar para a página anterior. Neste app 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. Como isso acontece quando o usuário sai, o aplicativo exibe a página de login.

Personalizar a página de perfil

Assim como a página de login, a página do perfil é personalizável. Primeiro, nossa página atual não tem como voltar à página inicial quando um usuário está na página de perfil. Para corrigir isso, atribua 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 Flutter Material para que possa ser tratado como qualquer outro AppBar que você tenha criado e transmitido para um Scaffold. Nesse exemplo, a funcionalidade padrão de adicionar automaticamente um botão "Voltar" é mantida, e a tela agora tem um título.

Adicionar filhos à tela do perfil

O widget ProfileScreen também tem um argumento opcional chamado "filhos". Esse argumento aceita uma lista de widgets, que serão colocados verticalmente dentro de um widget Column que já é usado internamente para criar a ProfileScreen. Esse widget Column no método de compilação ProfileScreen colocará os filhos que você transmitir acima do botão "Sign out".

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 e você verá o seguinte na tela:

ebe5792b765dbf87.png

7. Login do Google Auth multiplataforma

A interface do FlutterFire também oferece widgets e funcionalidades para autenticação com provedores externos, como Google, Twitter, Facebook, Apple e GitHub.

Para integrar com a autenticação do Google, instale o plug-in firebase_ui_oauth_google oficial e as dependências dele que manipularão o fluxo de autenticação nativo. 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 Google no Console do Firebase:

  1. Navegue até a tela Provedores de login de autenticação no console.
  2. Clique em "Adicionar novo provedor". 8286fb28be94bf30.png
  3. Selecione "Google". c4e28e6f4974be7f.png
  4. Selecione a chave "Ativar" e pressione "Salvar". e74ff86990763826.png
  5. Se um modal aparecer com informações sobre como fazer o download dos arquivos de configuração, clique em "Concluído".
  6. Confirme se o provedor de login do Google foi adicionado. 5329ce0543c90d95.png

Adicionar o botão de Login do Google

Com o Login do Google ativado, adicione o widget necessário para exibir um botão de login estilizado 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 app para ver o botão de Login do Google.

aca71a46a011bfb5.png

Configurar botão de login

O botão não funciona sem outras configurações. Se estiver desenvolvendo com o Flutter Web, esta é a única etapa que você precisa adicionar para que o recurso funcione. Outras plataformas exigem etapas adicionais, que serão abordadas mais adiante.

  1. Acesse a página "Provedores do Authentication" no Console do Firebase.
  2. Clique no provedor do Google. 9b3a325c5eca6e49.png
  3. Clique no painel de expansão "Configuração do SDK da Web".
  4. Copie o valor de "ID do cliente da Web" 711a79f0d931c60f.png
  5. Volte ao editor de texto e atualize a instância de GoogleProvider no arquivo auth_gate.dart transmitindo esse ID para o parâmetro chamado clientId.
GoogleProvider(
   clientId: "YOUR_WEBCLIENT_ID"
)

Depois de inserir o ID do cliente da Web, recarregue o app. Ao pressionar o botão "Fazer login com o Google", uma nova janela vai aparecer (se você estiver usando a Web), que vai guiar você pelo fluxo de login do Google. Inicialmente, ela tem esta aparência:

14e73e3c9de704bb.png

Configurar o iOS

Para que isso funcione no iOS, há um processo de configuração adicional.

  1. Navegue até a tela "Configurações do projeto" no Console do Firebase. Haverá um card que lista seus apps do Firebase com a seguinte aparência: fefa674acbf213cc.png
  2. Clique no iOS. O nome do seu aplicativo será diferente do meu. Quando o meu estiver concluído, o seu dirá "iniciar", se você tiver usado o projeto flutter-codelabs/firebase-auth-flutterfire-ui/start para acompanhar este codelab.
  3. Clique no botão "GoogleServices-Info.plist" para fazer o download do arquivo de configuração necessário. f89b3192871dfbe3.png
  4. Arraste e solte o arquivo baixado no diretório ./ios/Runner no seu projeto do Flutter.
  5. Abra o Xcode executando o seguinte comando do terminal na raiz do seu projeto:

abrir ios/Runner.xcworkspace

  1. Clique com o botão direito do mouse no diretório "Runner" e selecione "Adicionar arquivos a "Runner". 858986063a4c5201.png
  2. Selecione GoogleService-Info.plist no gerenciador de arquivos.
  3. 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 -->

Se o app do Flutter já estiver em execução no iOS, será necessário desativá-lo completamente e executá-lo 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 "completo" do GitHub: Flutter Codelabs (link em inglês).

O que aprendemos

  • Como configurar um app do 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
  • Usar a interface do FlutterFire para processar facilmente a autenticação do Firebase no seu app do Flutter

Próximas etapas

Saiba mais

O Sparky está aqui para comemorar com você!

2a0ad195769368b1.gif