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

1. Antes de começar

Neste codelab, você vai aprender a adicionar o Firebase Authentication ao seu app Flutter usando o pacote FlutterFire UI. Com esse pacote, você vai adicionar a autenticação por e-mail e senha e a autenticação do Google Sign-In a um app Flutter. Você 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:

Você também precisa ter alguma experiência com o Firebase, mas não tem problema se nunca tiver adicionado o Firebase a um projeto do Flutter. Se você não conhece o console do Firebase ou nunca usou o Firebase, consulte os seguintes links primeiro:

O que você vai criar

Este codelab mostra como criar o fluxo de autenticação de um app Flutter usando o Firebase Authentication. O aplicativo terá uma tela de login, uma tela "Registrar", uma tela de recuperação de senha e uma tela de perfil do usuário.

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

O que você vai aprender

Este codelab aborda:

  • Adicionar o Firebase a um app Flutter
  • Configuração do console do Firebase
  • 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 em Dart
  • Adicionar o Firebase Authentication ao seu app Flutter
  • Configuração do Firebase Authentication no console
  • Adicionar login com e-mail e senha usando o pacote firebase_ui_auth
  • Adicionar registro de usuário com o pacote firebase_ui_auth
  • Adicionar uma página "Esqueceu a senha?"
  • Adicionar o Login do Google com firebase_ui_auth
  • Configurar seu app para trabalhar com vários provedores de login.
  • Adicionar uma tela de perfil de usuário ao seu aplicativo com o pacote firebase_ui_auth

Este codelab se concentra especificamente em adicionar um sistema de autenticação robusto usando o pacote firebase_ui_auth. Como você vai ver, todo esse app, com todos os recursos acima, pode ser implementado com cerca de 100 linhas de código.

Pré-requisitos

  • Conhecimento prático de Flutter e do SDK instalado
  • Um editor de texto (o Flutter é compatível com os ambientes de desenvolvimento integrado da JetBrains, o Android Studio e o VS Code)
  • Navegador Google Chrome ou outro destino de desenvolvimento preferido 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 é criar um projeto do Firebase no console da Web do Firebase.

Criar um projeto do Firebase

  1. Faça login no console do Firebase usando sua Conta do Google.
  2. Clique no botão para criar um projeto e insira um nome (por exemplo, FlutterFire-UI-Codelab).
  3. Clique em Continuar.
  4. Se solicitado, leia e aceite os Termos do Firebase e clique em Continuar.
  5. (Opcional) Ative a assistência de IA no console do Firebase (chamada de "Gemini no Firebase").
  6. Neste codelab, você não precisa do Google Analytics. Portanto, desative a opção do Google Analytics.
  7. Clique em Criar projeto, aguarde o provisionamento e clique em Continuar.

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. Ele também permite que novos usuários se registrem no aplicativo Flutter.

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

Para permitir que os usuários façam login no app da Web, primeiro use o método de login E-mail/Senha. Depois, você vai adicionar o método Fazer login com o Google.

  1. No console do Firebase, expanda o menu Build no painel esquerdo.
  2. Clique em Autenticação e depois no botão Começar e na guia Método de login (ou acesse diretamente a guia Método de login).
  3. Clique em E-mail/senha na lista Provedores de login, defina a chave Ativar como "Ativado" e clique em Salvar.

58e3e3e23c2f16a4.png

3. Configurar o app do Flutter

Você vai precisar baixar o código inicial e instalar a CLI do Firebase antes de começar.

Acessar o código inicial

Clone o repositório do GitHub 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 precisa ser clonado para o diretório flutter-codelabs na 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. Uma é chamada de complete e a outra, de start. O diretório start contém um projeto incompleto e é onde você vai passar mais tempo.

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

Se quiser avançar ou ver como algo deve ficar quando estiver concluído, consulte o diretório chamado "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 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 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. Confira todas as opções disponíveis para seu sistema operacional em firebase.google.com/docs/cli.

Depois de instalar a CLI, é necessário fazer a autenticação com o Firebase.

  1. Faça login no Firebase com sua Conta do Google executando o seguinte comando:
    firebase login
    
  2. Esse comando conecta sua máquina local ao Firebase e concede acesso aos seus projetos.
  3. Para testar se a CLI está instalada corretamente e tem acesso à sua conta, liste seus projetos do Firebase. Execute este comando:
    firebase projects:list
    
  4. A lista exibida precisa conter os mesmos projetos que aparecem no Console do Firebase. Você vai ver 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 no seu app Flutter. Ela é 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 mostra o menu de ajuda.

flutterfire --help

Adicionar o projeto do Firebase ao app Flutter

Configurar o FlutterFire

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

flutterfire configure

Ao executar esse comando, você vai precisar selecionar qual projeto do Firebase quer usar e quais plataformas quer configurar.

As capturas de tela a seguir mostram os comandos que você precisa responder.

  1. Selecione o projeto que você quer usar. Nesse caso, use flutterfire-ui-codelab1359cdeb83204baa.png
  2. Selecione as plataformas que você quer usar. Neste codelab, há 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 você conhece o Firebase, vai notar que não foi necessário criar aplicativos de plataforma (por exemplo, um aplicativo Android) no console. A CLI do FlutterFire fez isso por você. 12199a85ade30459.png

Quando isso for concluído, confira o app Flutter no editor de texto. A CLI do FlutterFire modificou um 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ê selecionou todas as plataformas ao executar flutterfire configure, verá valores estáticos chamados web, android, ios e macos.

lib/firebase_options.dart

import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
    show defaultTargetPlatform, kIsWeb, TargetPlatform;

class DefaultFirebaseOptions {
  static FirebaseOptions get currentPlatform {
    if (kIsWeb) {
      return web;
    }

    switch (defaultTargetPlatform) {
      case TargetPlatform.android:
        return android;
      case TargetPlatform.iOS:
        return ios;
      case TargetPlatform.macOS:
        return macos;
      default:
        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 a palavra "aplicativo" para se referir a um build específico para 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 enum 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 da configuração é adicionar os pacotes relevantes do Firebase ao seu projeto do Flutter. O arquivo firebase_options.dart vai ter erros porque 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 firebase_auth firebase_ui_auth

Esses são os únicos pacotes necessários neste momento.

Inicializar o Firebase

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

lib/main.dart

import 'package:firebase_core/firebase_core.dart';                  // Add this import
import 'package:flutter/material.dart';

import 'app.dart';
import 'firebase_options.dart';                                     // And this import

// TODO(codelab user): Get API key
const clientId = 'YOUR_CLIENT_ID';

void main() async {
  // Add from here...
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
  // To here.

  runApp(const MyApp(clientId: clientId));
}

Esse código faz duas coisas.

  1. WidgetsFlutterBinding.ensureInitialized() informa ao Flutter para não começar a executar o código do widget de aplicativo até que a estrutura do Flutter seja inicializada completamente. 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 seu app Flutter e seu projeto do Firebase. O DefaultFirebaseOptions.currentPlatform é importado do arquivo firebase_options.dart gerado. Esse valor estático detecta em qual plataforma você está executando e transmite as chaves correspondentes do Firebase.

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

A interface do Firebase para autenticação oferece widgets que representam telas inteiras no seu aplicativo. Essas telas processam diferentes fluxos de autenticação em todo o aplicativo, como fazer login, registrar, esquecer a senha, perfil do usuário e muito mais. Para começar, adicione uma página de destino ao seu app que funcione como uma proteção de autenticação para o aplicativo principal.

App Material ou Cupertino

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

lib/app.dart

import 'package:flutter/material.dart';

import 'auth_gate.dart';

class MyApp extends StatelessWidget {
  const MyApp({super.key, required this.clientId});

  final String clientId;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: AuthGate(clientId: clientId),
    );
  }
}

Verificar o estado da autenticação

Antes de mostrar uma tela de login, é necessário 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.

Na amostra de código acima, o MaterialApp está criando um widget AuthGate no método build. (Este é um widget personalizado, não fornecido pela interface do FlutterFire.)

Ele precisa ser atualizado para incluir o stream authStateChanges.

A API authStateChanges retorna um Stream com o usuário atual (se ele estiver conectado) ou nulo se não estiver. Para assinar esse estado no aplicativo, use o widget StreamBuilder do Flutter e transmita o fluxo para ele.

O StreamBuilder é um widget que se cria com base no snapshot mais recente de dados de uma Stream que você transmite. Ele é reconstruído automaticamente quando o Stream emite um novo snapshot.

Atualize o código em auth_gate.dart.

lib/auth_gate.dart

import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider; // Add this import
import 'package:firebase_ui_auth/firebase_ui_auth.dart';                  // And this import
import 'package:flutter/material.dart';

import 'home.dart';

class AuthGate extends StatelessWidget {
  const AuthGate({super.key, required this.clientId});

  final String clientId;

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(                                       // Modify from here...
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return SignInScreen(providers: []);
        }

        return const HomeScreen();
      },
    );                                                                 // To here.
  }
}
  • StreamBuilder.stream está recebendo FirebaseAuth.instance.authStateChanged, o fluxo mencionado acima, que vai retornar um objeto User do Firebase se o usuário tiver feito a autenticação. Caso contrário, vai 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. Por enquanto, essa tela não vai fazer nada. Ela será atualizada na próxima etapa.
  • Caso contrário, ele retorna um HomeScreen, que é a parte principal do aplicativo que apenas usuários autenticados podem acessar.

O SignInScreen é um widget que vem do pacote de UI do FlutterFire. Esse será o foco da próxima etapa deste codelab. Quando você executar o app neste momento, uma tela de login em branco vai aparecer.

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, eles podem tocar em "Esqueceu a senha?" e acessar um formulário para redefinir a senha.
  • Se um usuário ainda não estiver registrado, ele poderá tocar em "Registrar" e acessar outro formulário para se inscrever.

Isso requer apenas algumas linhas de código. Recupere o código no widget AuthGate:

lib/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, required this.clientId});

  final String clientId;

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return SignInScreen(providers: [EmailAuthProvider()]);  // Modify this line
        }

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

O widget SignInScreen e o argumento providers são os únicos códigos necessários para ter todas as funcionalidades mencionadas. Agora, você vai ver uma tela de login com entradas de texto "e-mail" e "senha", além de um 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ó é exibido em telas estreitas, como dispositivos móveis. Em telas grandes, você pode usar SignInScreen.sideBuilder, que será abordado mais adiante neste codelab.

Atualize o arquivo lib/auth_gate.dart com este código:

lib/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, required this.clientId});

  final String clientId;

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return SignInScreen(                                         // Modify from here...
            providers: [EmailAuthProvider()],
            headerBuilder: (context, constraints, shrinkOffset) {
              return Padding(
                padding: const EdgeInsets.all(20),
                child: AspectRatio(
                  aspectRatio: 1,
                  child: Image.asset('assets/flutterfire_300x.png'),
                ),
              );
            },
          );                                                           // To here.
        }

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

The headerBuilder argument requires a function of the type HeaderBuilder, which
is defined in the FlutterFire UI package.

```dart
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 aparece na parte de cima da tela. Neste exemplo, o novo código adiciona uma imagem à parte de cima da tela. Seu aplicativo vai ficar assim.

73d7548d91bbd2ab.png

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 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 "fazer login" ou a de "registrar".

Atualize o código em auth_gate.dart para usar o subtitleBuilder.

lib/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, required this.clientId});

  final String clientId;

  @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'),
                ),
              );
            },
            subtitleBuilder: (context, action) {                     // Add from here...
              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!'),
              );
            },                                                       // To here.
          );
        }

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

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

Adicione um rodapé à tela de login com este código.

lib/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, required this.clientId});

  final String clientId;

  @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'),
                ),
              );
            },
            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) {                       // Add from here...
              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),
                ),
              );
            },                                                       // To here.
          );
        }

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

Side Builder

O argumento SignInScreen.sidebuilder aceita um callback, e desta vez os argumentos desse callback são BuildContext e double shrinkOffset. O widget retornado por sideBuilder será exibido à esquerda do formulário de login e apenas em telas grandes. Isso significa que o widget só será exibido em computadores e apps da Web.

Internamente, o 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 Web). Especificamente, se uma tela tiver mais de 800 pixels de largura, o conteúdo do criador de sites lateral será mostrado, e o conteúdo do cabeçalho não. Se a tela tiver menos de 800 pixels de largura, o contrário será verdadeiro.

Atualize o código em auth_gate.dart para adicionar widgets sideBuilder.

lib/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, required this.clientId});

  final String clientId;

  @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'),
                ),
              );
            },
            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();
      },
    );
  }
}

Seu app vai ficar assim quando você aumentar a largura da janela (se estiver usando o Flutter Web ou o macOS).

8dc60b4e5d7dd2d0.png

Criar um usuário

Neste ponto, todo o código dessa tela está concluído. No entanto, antes de fazer login, você precisa 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. Selecione "flutterfire-ui-codelab" ou outro projeto se você usou um nome diferente. Você vai encontrar esta tabela: f038fd9a58ed60d9.png
  2. Clique no botão "Adicionar usuário". 2d78390d4c5dbbfa.png
  3. Insira um endereço de e-mail e uma senha para o novo usuário. Pode ser um e-mail e uma senha falsos, como inseri na imagem abaixo. Isso vai funcionar, mas a funcionalidade "Esqueceu a senha" não vai funcionar se você usar um endereço de e-mail falso. 62ba0feb33d54add.png
  4. Clique em "Adicionar usuário" 32b236b3ef94d4c7.png

Agora, volte ao aplicativo Flutter e faça login de um usuário usando a página de login. O app vai ficar assim:

dd43d260537f3b1a.png

6. Tela de perfil

A interface do FlutterFire também oferece um widget ProfileScreen, que oferece muita funcionalidade em poucas linhas de código.

Adicionar o widget ProfileScreen

Navegue até o arquivo home.dart no editor de texto. Atualize com este código:

lib/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: [
            SizedBox(width: 250, child: Image.asset('assets/dash.png')),
            Text('Welcome!', style: Theme.of(context).textTheme.displaySmall),
            const SignOutButton(),
          ],
        ),
      ),
    );
  }
}

O novo código da observação é o callback transmitido ao método IconButton.isPressed. Quando esse IconButton é pressionado, o aplicativo 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 pressione o ícone no canto superior direito (na barra de apps). Uma página como esta vai aparecer:

36487fc4ab4f26a7.png

Essa é a UI padrão fornecida pela página FlutterFire UI. Todos os botões e campos de texto estão conectados ao Firebase Auth e funcionam imediatamente. Por exemplo, você pode inserir um nome no campo de texto "Nome", e o FlutterFire UI vai chamar o método FirebaseAuth.instance.currentUser?.updateDisplayName, que vai salvar esse nome no Firebase.

Sair

No momento, se você pressionar o botão "Sair", o app não vai mudar. Isso vai fazer você sair, mas não vai redirecionar você de volta ao widget AuthGate. Para implementar isso, use o parâmetro ProfileScreen.actions.

Primeiro, atualize o código em home.dart.

lib/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: [
            SizedBox(width: 250, child: Image.asset('assets/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 informar ao app que ele precisa reagir a diferentes mudanças de estado de autenticação. O SignedOutAction chama uma função de callback que você fornece quando o estado de autenticação do Firebase muda para currentUser sendo nulo.

Ao adicionar um callback que chama Navigator.of(context).pop() quando SignedOutAction é acionado, o app navega até a página anterior. Neste exemplo de app, há apenas uma rota permanente, que mostra a tela 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 da conta, o app vai mostrar a tela de login.

Personalizar a página de perfil

Assim como a tela de login, a página de perfil é personalizável. Primeiro, nossa página atual não tem como voltar à página inicial depois que um usuário está na página de perfil. Para corrigir isso, dê ao widget ProfileScreen uma AppBar.

lib/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: [
            SizedBox(width: 250, child: Image.asset('assets/dash.png')),
            Text('Welcome!', style: Theme.of(context).textTheme.displaySmall),
            const SignOutButton(),
          ],
        ),
      ),
    );
  }
}

O argumento ProfileScreen.appBar aceita um widget AppBar do pacote Material do Flutter. Portanto, ele pode ser tratado como qualquer outro AppBar que você criou e transmitiu 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 Column já usado internamente para criar o ProfileScreen. Esse widget Column no método de build ProfileScreen vai colocar os filhos que você transmitir acima do botão "Sair".

Atualize o código em home.dart para mostrar o logotipo da empresa aqui, semelhante à tela de login.

lib/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: [
            SizedBox(width: 250, child: Image.asset('assets/dash.png')),
            Text('Welcome!', style: Theme.of(context).textTheme.displaySmall),
            const SignOutButton(),
          ],
        ),
      ),
    );
  }
}

Recarregue o app para ver isso na tela:

ebe5792b765dbf87.png

7. Login do Google em várias plataformas

A interface do FlutterFire também oferece widgets e funcionalidades para autenticação com provedores terceirizados, 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 vão processar o fluxo de autenticação nativo. No terminal, navegue até a raiz do seu projeto do Flutter e insira o seguinte comando:

flutter pub add google_sign_in firebase_ui_oauth_google

Ativar o provedor de Login do Google

Em seguida, ative o provedor do 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. Mova o botão "Ativar" e pressione "Salvar". e74ff86990763826.png
  5. Se um modal aparecer com informações sobre o download de 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 mostrar um botão estilizado do Login do Google na tela de login. Navegue até o arquivo auth_gate.dart e atualize o código para o seguinte:

lib/auth_gate.dart

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';  // Add this import
import 'package:flutter/material.dart';

import 'home.dart';

class AuthGate extends StatelessWidget {
  const AuthGate({super.key, required this.clientId});

  final String clientId;

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return SignInScreen(
            providers: [
              EmailAuthProvider(),
              GoogleProvider(clientId: clientId),                         // Add this line
            ],
            headerBuilder: (context, constraints, shrinkOffset) {
              return Padding(
                padding: const EdgeInsets.all(20),
                child: AspectRatio(
                  aspectRatio: 1,
                  child: Image.asset('assets/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.

Depois de adicionar isso, recarregue o app para ver um botão de login do Google.

aca71a46a011bfb5.png

Configurar o botão de login

O botão não funciona sem configuração adicional. Se você estiver desenvolvendo com o Flutter Web, esta é a única etapa que precisa adicionar para que isso funcione. Outras plataformas exigem etapas adicionais, que serão abordadas em breve.

  1. Acesse a página "Provedores de autenticação" 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 ao parâmetro nomeado clientId.
GoogleProvider(
   clientId: "YOUR_WEBCLIENT_ID"
)

Depois que o ID do cliente da Web for inserido, recarregue o app. Ao pressionar o botão "Fazer login com o Google", uma nova janela vai aparecer (se você estiver usando a Web) e 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. Acesse a tela "Configurações do projeto" no console do Firebase. Um card com seus apps do Firebase vai aparecer assim: fefa674acbf213cc.png
  2. Selecione iOS. O nome do seu aplicativo será diferente do mostrado na captura de tela. Na captura de tela, está escrito "complete", mas no seu caso vai estar "start" se você usou 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 o arquivo baixado para o diretório chamado /ios/Runner no seu projeto Flutter.
  5. Abra o Xcode executando o seguinte comando do terminal na raiz do projeto: open ios/Runner.xcworkspace
  6. Clique com o botão direito do mouse no diretório "Runner" e selecione "Adicionar arquivos a "Runner"". 858986063a4c5201.png
  7. Selecione GoogleService-Info.plist no gerenciador de arquivos.
  8. De volta ao editor de texto (que não é o Xcode), adicione os atributos CFBundleURLTypes abaixo ao arquivo 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 -->
    
  9. Substitua o GoogleProvider.clientId adicionado na configuração da Web pelo ID do cliente associado ao ID do cliente do Firebase para iOS. Primeiro, encontre esse ID no arquivo firebase_options.dart, como parte da constante iOS. Copie o valor transmitido para iOSClientId.
    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',
    );
    
  10. Cole esse valor na variável clientId no arquivo lib/main.dart.

lib/main.dart

import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';

import 'app.dart';
import 'firebase_options.dart';

const clientId = 'YOUR_CLIENT_ID'; // Replace this value with your Client ID.

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

  runApp(const MyApp(clientId: clientId));
}

Se o app do Flutter já estiver em execução no iOS, feche-o completamente e execute 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 firebase-auth-flutterfire-ui/complete do GitHub.

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

Próximas etapas

Saiba mais

O Sparky está aqui para comemorar com você!

2a0ad195769368b1.gif