Agrega un flujo de autenticación de usuarios a una app de Flutter con FirebaseUI

1. Antes de comenzar

En este codelab, aprenderás a agregar Firebase Authentication a tu app de Flutter con el paquete de IU de FlutterFire. Con este paquete, agregarás la autenticación con correo electrónico y contraseña y la autenticación de Acceso con Google a una app de Flutter. También aprenderás a configurar un proyecto de Firebase y a usar la CLI de FlutterFire para inicializar Firebase en tu app de Flutter.

Requisitos previos

En este codelab, se presupone que tienes experiencia en Flutter. Si no es así, te recomendamos que primero aprendas los conceptos básicos. Los siguientes vínculos son útiles:

Además, deberías tener experiencia en Firebase, pero no hay problema si nunca agregaste Firebase a un proyecto de Flutter. Si no conoces Firebase console o si eres completamente nuevo en Firebase, consulta primero los siguientes vínculos:

Qué crearás

Este codelab te guiará en la compilación del flujo de autenticación para una app de Flutter usando Firebase para Authentication. La aplicación tendrá una pantalla de acceso y la opción “Registrarse” una pantalla de recuperación de contraseña y una de perfil del usuario.

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

Qué aprenderás

En este codelab, se abarca lo siguiente:

  • Agrega Firebase a una app creada con Flutter
  • Configuración de Firebase console
  • Usa Firebase CLI para agregar Firebase a tu aplicación
  • Cómo usar la CLI de FlutterFire para generar la configuración de Firebase en Dart
  • Agrega Firebase Authentication a tu app creada con Flutter
  • Configuración de Firebase Authentication en la consola
  • Agrega un correo electrónico y una contraseña para acceder con el paquete firebase_ui_auth
  • Agrega el registro de usuario con el paquete firebase_ui_auth
  • Agregando "¿Olvidaste la contraseña?" página
  • Agregando Acceso con Google con firebase_ui_auth
  • Configurar tu app para que funcione con varios proveedores de acceso
  • Cómo agregar una pantalla de perfil de usuario a tu aplicación con el paquete firebase_ui_auth

Este codelab se enfoca específicamente en agregar un sistema de autenticación sólido mediante el paquete firebase_ui_auth. Como verás, toda esta app, con todas las funciones anteriores, se puede implementar con alrededor de 100 líneas de código.

Requisitos

  • Conocimiento práctico sobre Flutter y el SDK instalado
  • Un editor de texto (los IDE de JetBrains, Android Studio y VS Code son compatibles con Flutter)
  • El navegador Google Chrome, o bien tu otro segmento de desarrollo preferido para Flutter. (Algunos comandos de terminal de este codelab supondrán que ejecutas tu app en Chrome).

2. Crea y configura un proyecto de Firebase

Lo primero que debes completar es crear un proyecto de Firebase en la consola web de Firebase.

Crea un proyecto de Firebase

  1. Accede a Firebase.
  2. En Firebase console, haz clic en Agregar proyecto (o Crear un proyecto) y, luego, ingresa un nombre para tu proyecto de Firebase (por ejemplo, "FlutterFire-UI-Codelab").

df42a5e3d9584b48.png

  1. Haz clic para avanzar por las opciones de creación de proyectos. Si se te solicita, acepta las condiciones de Firebase. Omite la configuración de Google Analytics, ya que no usarás Analytics en esta app.

d1fcec48bf251eaa.png

Para obtener más información sobre los proyectos de Firebase, consulta la Información sobre los proyectos de Firebase.

La app que estás compilando usa Firebase Authentication para permitir que los usuarios accedan a ella. También permite que los usuarios nuevos se registren desde la aplicación de Flutter.

Firebase Authentication debe habilitarse a través de Firebase console y, luego, requiere una configuración especial.

Habilita el acceso con correo electrónico para Firebase Authentication

Para permitir que los usuarios accedan a la aplicación web, primero debes usar el método de acceso con Correo electrónico/Contraseña. Más adelante, agregarás el método de Acceso con Google.

  1. En Firebase console, expande el menú Compilación en el panel izquierdo.
  2. Haz clic en Authentication, en el botón Get Started y, luego, a la pestaña Sign-in method (o haz clic aquí para ir directamente a la pestaña Sign-in method).
  3. Haz clic en Correo electrónico/Contraseña en la lista de Proveedores de acceso, activa la opción Habilitar y, luego, haz clic en Guardar. 58e3e3e23c2f16a4.png

3. Configura una app de Flutter

Debes descargar el código de partida y, luego, instalar Firebase CLI antes de comenzar.

Obtén el código de partida

Clona el repositorio de GitHub desde la línea de comandos:

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

Como alternativa, si tienes instalada la herramienta CLI de GitHub , haz lo siguiente:

gh repo clone flutter/codelabs flutter-codelabs

El código de muestra se debe clonar en el directorio flutter-codelabs de tu máquina, que contiene el código de una colección de codelabs. El código de este codelab se encuentra en el subdirectorio flutter-codelabs/firebase-auth-flutterfire-ui.

El directorio flutter-codelabs/firebase-auth-flutterfire-ui contiene dos proyectos de Flutter. Uno se llama complete y el otro se llama start. El directorio start contiene un proyecto incompleto, en el que pasarás la mayor parte del tiempo.

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

Si deseas adelantar o ver cómo debería verse algo cuando se complete, busca en el directorio llamado complete para hacer una referencia cruzada.

Si deseas continuar con el codelab y agregar código por tu cuenta, debes comenzar con la app de Flutter en flutter-codelabs/firebase-auth-flutterfire-ui/start y agregar código a ese proyecto durante todo el codelab. Abre o importa ese directorio a tu IDE preferido.

Instala Firebase CLI

Firebase CLI proporciona herramientas para administrar tus proyectos de Firebase. La CLI es necesaria para la CLI de FlutterFire, que instalarás más adelante.

Existen varias formas de instalar la CLI. La forma más sencilla, si usas macOS o Linux, es ejecutar este comando desde la terminal:

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

Después de instalar la CLI, debes autenticarte con Firebase.

  1. Accede a Firebase con tu Cuenta de Google ejecutando el siguiente comando:
firebase login
  1. Este comando conecta tu máquina local a Firebase y te otorga acceso a tus proyectos de Firebase.
  1. Enumera tus proyectos de Firebase para probar que la CLI esté instalada correctamente y que tenga acceso a tu cuenta. Ejecuta el siguiente comando:
firebase projects:list
  1. La lista que se muestra debe ser la misma que los proyectos de Firebase enumerados en Firebase console. Deberías ver al menos flutterfire-ui-codelab.

Instala la CLI de FlutterFire

La CLI de FlutterFire es una herramienta que facilita el proceso de instalación de Firebase en todas las plataformas compatibles con tu app de Flutter. Se basa en Firebase CLI.

Primero, instala la CLI:

dart pub global activate flutterfire_cli

Asegúrate de que se haya instalado la CLI. Ejecuta el siguiente comando y asegúrate de que la CLI muestre el menú de ayuda.

flutterfire -—help

Agrega el proyecto de Firebase a tu app creada con Flutter

Configura FlutterFire

Puedes usar FlutterFire para generar el código de Dart necesario para usar Firebase en tu app de Flutter.

flutterfire configure

Cuando se ejecute este comando, se te pedirá que selecciones el proyecto de Firebase que quieres usar y las plataformas que deseas configurar.

Las siguientes capturas de pantalla muestran las indicaciones que deberás responder.

  1. Selecciona el proyecto que deseas usar. En este caso, usa flutterfire-ui-codelab 1359cdeb83204baa.png.
  2. Selecciona las plataformas que deseas usar. En este codelab, sigues los pasos que te permitirán configurar Firebase Authentication para Flutter en la Web, iOS y Android, pero puedes configurar tu proyecto de Firebase de modo que use todas las opciones. 301c9534f594f472.png
  3. En esta captura de pantalla, se muestra el resultado al final del proceso. Si estás familiarizado con Firebase, notarás que no tuviste que crear aplicaciones de plataforma (por ejemplo, una aplicación para Android) en la consola, y la CLI de FlutterFire lo hizo por ti. 12199a85ade30459.png

Cuando termines, consulta la app de Flutter en tu editor de texto. La CLI de FlutterFire generó un archivo nuevo llamado firebase_options.dart. Este archivo contiene una clase llamada FirebaseOptions, que tiene variables estáticas que contienen la configuración de Firebase necesaria para cada plataforma. Si seleccionaste todas las plataformas cuando ejecutaste flutterfire configure, verás valores estáticos llamados web, android, ios y 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.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',
 );
}

Firebase usa la palabra “aplicación” para referirse a una compilación específica para una plataforma específica en un proyecto de Firebase. Por ejemplo, el proyecto de Firebase llamado FlutterFire-ui-codelab tiene varias aplicaciones: una para Android, una para iOS, una para macOS y otra para la Web.

El método DefaultFirebaseOptions.currentPlatform usa la enum TargetPlatform que expone Flutter para detectar la plataforma en la que se ejecuta tu app y, luego, muestra los valores de configuración de Firebase necesarios para la aplicación correcta de Firebase.

Agrega paquetes de Firebase a la app creada con Flutter

El paso de configuración final es agregar los paquetes de Firebase relevantes a tu proyecto de Flutter. El archivo firebase_options.dart debería tener errores, ya que se basa en paquetes de Firebase que aún no se agregaron. En la terminal, asegúrate de estar en la raíz del proyecto de Flutter en flutter-codelabs/firebase-emulator-suite/start. Luego, ejecuta los tres comandos siguientes:

flutter pub add firebase_core
flutter pub add firebase_auth
flutter pub add firebase_ui_auth

Estos son los únicos paquetes que necesitas en este momento.

Inicializa Firebase

Para usar los paquetes agregados y DefaultFirebaseOptions.currentPlatform,, actualiza el código en la función main del archivo main.dart.

main.dart

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


 runApp(const MyApp());
}

Este código hace dos cosas.

  1. WidgetsFlutterBinding.ensureInitialized() le indica a Flutter que no comience a ejecutar el código del widget de la aplicación hasta que el framework de Flutter se inicie por completo. Firebase usa canales de plataforma nativos, que requieren que el framework se ejecute.
  2. Firebase.initializeApp establece una conexión entre la app de Flutter y el proyecto de Firebase. Se importa el DefaultFirebaseOptions.currentPlatform de nuestro archivo firebase_options.dart generado. Este valor estático detecta en qué plataforma se está ejecutando y pasa las claves de Firebase correspondientes.

4. Agrega la página de autenticación inicial de la IU de Firebase

La IU de Firebase para Auth proporciona widgets que representan pantallas completas en tu aplicación. Estas pantallas manejan diferentes flujos de autenticación en toda la aplicación, como Acceder, Registro, ¿Olvidaste la contraseña?, Perfil de usuario, etc. Para comenzar, agrega una página de destino a tu app que actúe como protección de autenticación de la aplicación principal.

App de Material o Cupertino

La IU de FlutterFire requiere que tu aplicación esté unida a una MaterialApp o CupertinoApp. Según tu elección, la IU reflejará automáticamente las diferencias de los widgets de Material o Cupertino. En este codelab, usa MaterialApp, que ya se agregó a la app en 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(),
   );
 }
}

Verifica el estado de autenticación

Antes de mostrar una pantalla de acceso, debes determinar si el usuario está autenticado actualmente. La forma más común de comprobarlo es escuchar los authStateChanges de FirebaseAuth mediante el complemento de Firebase Auth.

En la muestra de código anterior, MaterialApp compila un widget AuthGate en su método de compilación. (Este es un widget personalizado, no proporcionado por la IU de FlutterFire).

Se debe actualizar el widget para incluir el flujo de authStateChanges.

La API de authStateChanges muestra un Stream con el usuario actual (si accedió) o un valor nulo si no lo está. Para suscribirte a este estado en nuestra aplicación, puedes usar el widget StreamBuilder de Flutter y pasarle la transmisión.

StreamBuilder es un widget que se compila a sí mismo según la instantánea más reciente de datos de una transmisión que le pasas. Se vuelve a compilar automáticamente cuando la transmisión emite una nueva instantánea.

Actualiza el código en auth_gate.dart.

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: [],
          );
        }

        return const HomeScreen();
      },
    );
  }
}
  • A StreamBuilder.stream se le pasa FirebaseAuth.instance.authStateChanged, la transmisión mencionada anteriormente, que mostrará un objeto User de Firebase si el usuario se autenticó. De lo contrario, mostrará null.
  • A continuación, el código usa snapshot.hasData para verificar si el valor del flujo contiene el objeto User.
  • Si no la hay, se mostrará un widget SignInScreen. Actualmente, esa pantalla no hará nada. Se actualizará en el siguiente paso.
  • De lo contrario, muestra un HomeScreen, que es la parte principal de la aplicación a la que solo pueden acceder los usuarios autenticados.

El SignInScreen es un widget que proviene del paquete de IU de FlutterFire. Este será el enfoque del siguiente paso de este codelab. En este punto, cuando ejecutes la app, deberías ver una pantalla de acceso en blanco.

5. Pantalla de acceso

El widget SignInScreen, que proporciona la IU de FlutterFire, agrega la siguiente funcionalidad:

  • Permite que los usuarios accedan.
  • Si los usuarios olvidaron la contraseña, pueden presionar "¿Olvidó la contraseña?" y ser llevados a un formulario para que restablezcan su contraseña
  • Si un usuario aún no se registró, puede presionar "Registrarse" para que se lo dirija a otro formulario que le permita hacerlo.

Nuevamente, esto requiere solo unas pocas líneas de código. Recupera el código en el widget 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();
      },
    );
  }
}

El widget de SignInScreen y su argumento providers es el único código necesario para obtener toda la funcionalidad mencionada anteriormente. Ahora deberías ver una pantalla de acceso con "correo electrónico". y "password" entradas de texto y la opción de "Acceder" .

Si bien es funcional, carece de estilo. El widget expone parámetros para personalizar el aspecto de la pantalla de acceso. Por ejemplo, es posible que desees agregar el logotipo de tu empresa.

Personaliza la pantalla de acceso

Creador de encabezados

Con el argumento SignInScreen.headerBuilder, puedes agregar los widgets que quieras arriba del formulario de acceso. Este widget solo se muestra en pantallas estrechas, como dispositivos móviles. En pantallas anchas, puedes usar SignInScreen.sideBuilder, que se analiza más adelante en este codelab.

Actualiza el archivo auth_gate.dart con 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();
     },
   );
 }
}

El argumento headerBuilder requiere una función del tipo HeaderBuilder, que se define en el paquete de IU de FlutterFire.

typedef HeaderBuilder = Widget Function(
 BuildContext context,
 BoxConstraints constraints,
 double shrinkOffset,
);

Como se trata de una devolución de llamada, expone valores que puedes usar, como BuildContext y BoxConstraints, y requiere que muestres un widget. El widget que muestres se mostrará en la parte superior de la pantalla. En este ejemplo, el código nuevo agrega una imagen en la parte superior de la pantalla. Ahora, tu aplicación debería verse de la siguiente manera:

73d7548d91bbd2ab.png

Creador de subtítulos

La pantalla de acceso muestra tres parámetros adicionales que te permiten personalizarla: subtitleBuilder, footerBuilder y sideBuilder.

subtitleBuilder es ligeramente diferente en el sentido de que los argumentos de devolución de llamada incluyen una acción, que es del tipo AuthAction. AuthAction es una enumeración que puedes usar para detectar si la pantalla en la que se encuentra el usuario es la de "acceso". o el botón de registro en la pantalla.

Actualiza el código en auth_gate.dart para usar subtitleBuilder.

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

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

Vuelve a cargar la aplicación, que debería verse así

El argumento footerBuilder es el mismo que el de subtitleBuilder. No expone BoxConstraints ni shrinkOffset, ya que están diseñados para texto y no imágenes. (aunque puedes agregar cualquier widget que desees).

Agrega un pie de página a la pantalla de acceso con 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('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();
     },
   );
 }}

Side Builder

El argumento SignInScreen.sidebuilder acepta una devolución de llamada y, esta vez, los argumentos para esa devolución de llamada son BuildContext y double shrinkOffset. El widget que devuelve sideBuilder se mostrará a la izquierda del formulario de acceso y solo en pantallas anchas. Eso significa que el widget solo se mostrará en computadoras y apps web.

Internamente, la IU de FlutterFire utiliza un punto de interrupción para determinar si se debe mostrar el contenido del encabezado (en pantallas altas, como en dispositivos móviles) o si se debe mostrar el contenido lateral (en pantallas panorámicas, computadoras de escritorio o la Web). Específicamente, si una pantalla tiene más de 800 píxeles de ancho, se muestra el contenido del compilador lateral, pero no el del encabezado. Si la pantalla tiene menos de 800 píxeles de ancho, ocurre lo contrario.

Actualiza el código en auth_gate.dart para agregar widgets de 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();
     },
   );
 }
}

Ahora, tu app debería tener el siguiente aspecto cuando expandas el ancho de la ventana (si usas Flutter web o MacOS).

8dc60b4e5d7dd2d0.png

Crea un usuario

En este punto, todo el código de esta pantalla está listo. Sin embargo, para poder acceder, debes crear un usuario. Puedes hacerlo con la opción "Register" pantalla o puedes crear un usuario en Firebase console.

Para usar la consola, haz lo siguiente:

  1. Ve a "Usuarios". en Firebase console.
  2. Haz clic aquí
  3. Selecciona "flutterfire-ui-codelab". (o en otro proyecto si usaste un nombre diferente). Verás la siguiente tabla:

f038fd9a58ed60d9.png

  1. Haz clic en el botón "Agregar usuario" .

2d78390d4c5dbbfa.png

  1. Ingresa una dirección de correo electrónico y una contraseña para el usuario nuevo. Puede ser una contraseña y un correo electrónico falsos, como ingresé en la imagen a continuación. Eso funcionará, pero el mensaje "¿Olvidaste la contraseña?" esta función no funcionará si usas una dirección de correo electrónico falsa.

62ba0feb33d54add.png

  1. Haz clic en "Agregar usuario".

32b236b3ef94d4c7.png

Ahora, puedes volver a tu aplicación de Flutter y hacer que un usuario acceda a través de la página de acceso. Tu app debería verse de la siguiente manera:

dd43d260537f3b1a.png

6. Pantalla de perfil

La IU de FlutterFire también proporciona un widget ProfileScreen, que, de nuevo, te brinda mucha funcionalidad en unas pocas líneas de código.

Agrega el widget ProfileScreen

Navega al archivo home.dart en tu editor de texto. Actualízala con 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(),
          ],
        ),
      ),
    );
  }
}

El nuevo código de nota es la devolución de llamada que se pasa a IconButton.isPressed method.. Cuando se presiona ese IconButton, tu aplicación crea una nueva ruta anónima y navega a ella. Esa ruta mostrará el widget de ProfileScreen, que se muestra en la devolución de llamada de MaterialPageRoute.builder.

Vuelve a cargar tu app y envía el ícono en la parte superior derecha (en la barra de la app), y se mostrará una página como la siguiente:

36487fc4ab4f26a7.png

Esta es la IU estándar que se proporciona en la página de IU de FlutterFire. Todos los botones y campos de texto están conectados a Firebase Auth y funcionan de forma inmediata. Por ejemplo, puedes ingresar un nombre en el campo "Nombre". textfield, y la IU de FlutterFire llamará al método FirebaseAuth.instance.currentUser?.updateDisplayName, que guardará ese nombre en Firebase.

Salir

Si presionas el botón "Salir" , la aplicación no cambiará. Saldrás de tu cuenta, pero no se te dirigirá nuevamente al widget de AuthGate. Para implementar esto, usa el parámetro ProfileScreen.actions.

Primero, actualiza el código en 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(),
          ],
        ),
      ),
    );
  }
}

Ahora, cuando crees una instancia de ProfileScreen, también le pasarás una lista de acciones al argumento ProfileScreen.actions. Estas acciones son del tipo FlutterFireUiAction. Hay muchas clases diferentes que son subtipos de FlutterFireUiAction y, en general, las usas para indicarle a tu app que reaccione a diferentes cambios de estado de autenticación. SignedOutAction llama a una función de devolución de llamada que le proporcionas cuando el estado de autenticación de Firebase cambia a currentUser siendo nulo.

Cuando se agrega una devolución de llamada que llama a Navigator.of(context).pop() cuando se activa SignedOutAction, la app navega a la página anterior. En esta app de ejemplo, solo hay una ruta permanente, que muestra la página de acceso si no hay un usuario registrado, y la página principal si hay un usuario. Como esto sucede cuando el usuario sale de su cuenta, la app mostrará la página de acceso.

Personaliza la página de perfil

Al igual que la página de acceso, la página de perfil se puede personalizar. En primer lugar, nuestra página actual no tiene manera de volver a la página principal una vez que un usuario está en la página de perfil. Para solucionar este problema, otorga una AppBar al widget de 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(),
         ],
       ),
     ),
   );
 }
}

El argumento ProfileScreen.appBar acepta un widget AppBar del paquete de Material de Flutter, por lo que se puede tratar como cualquier otro AppBar que hayas compilado y pasado a un Scaffold. En este ejemplo, la funcionalidad predeterminada para agregar automáticamente un “atrás” botón se mantiene, y la pantalla ahora tiene un título.

Agregar hijos o hijas a la pantalla de perfil

El widget ProfileScreen tiene también un argumento opcional denominado "child". Este argumento acepta una lista de widgets, que se colocarán verticalmente dentro de un widget de columna que ya se usa internamente para crear la ProfileScreen. Este widget de columna en el método de compilación de ProfileScreen colocará a los elementos secundarios que pases sobre el botón "Salir". .

Actualiza el código en home.dart para que muestre el logotipo de la empresa aquí, similar a la pantalla de acceso.

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

Vuelve a cargar la app y verás lo siguiente en la pantalla:

ebe5792b765dbf87.png

7. Acceso multiplataforma con Google Auth

La IU de FlutterFire también proporciona widgets y funciones para la autenticación con proveedores externos, como Google, Twitter, Facebook, Apple y GitHub.

Para realizar la integración con la autenticación de Google, instala el complemento oficial firebase_ui_oauth_google y sus dependencias, que se encargarán del flujo de autenticación nativo. En la terminal, navega a la raíz de tu proyecto Flutter y, luego, ingresa el siguiente comando:

flutter pub add google_sign_in
flutter pub add firebase_ui_oauth_google

Habilitar el proveedor de acceso con Google

A continuación, habilita el proveedor de Google en Firebase console:

  1. Navega a la pantalla Proveedores de acceso de Authentication en la consola.
  2. Haz clic en “Agregar proveedor nuevo”. 8286fb28be94bf30.png
  3. Selecciona "Google". c4e28e6f4974be7f.png
  4. Activa el interruptor con la etiqueta “Habilitar” y presiona “Guardar”. e74ff86990763826.png
  5. Si aparece una ventana modal con información sobre la descarga de archivos de configuración, haz clic en "Listo".
  6. Confirma que se haya agregado el proveedor de acceso con Google. 5329ce0543c90d95.png

Agrega el botón de Acceso con Google

Con el Acceso con Google habilitado, agrega el widget necesario para mostrar un botón estilizado de Acceso con Google en la página de acceso. Navega al archivo auth_gate.dart y actualiza el código con la siguiente información:

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

El único código nuevo aquí es la adición de GoogleProvider(clientId: "YOUR_WEBCLIENT_ID") a la configuración del widget de SignInScreen.

Una vez que lo agregues, vuelve a cargar la app y verás un botón de Acceso con Google.

ACA71a46a011bfb5.png

Configurar el botón de acceso

El botón no funciona sin una configuración adicional. Si estás desarrollando con Flutter Web, este es el único paso que debes agregar para que funcione. Otras plataformas requieren pasos adicionales, que se explican más adelante.

  1. Navega a la página de proveedores de Authentication en Firebase console.
  2. Haz clic en el proveedor de Google. 9b3a325c5eca6e49.png
  3. Haz clic en "Web SDK configuration" panel de expansión.
  4. Copia el valor de "Web client ID" 711a79f0d931c60f.png
  5. Regresa al editor de texto y actualiza la instancia de GoogleProvider en el archivo auth_gate.dart pasando este ID al parámetro con nombre clientId.
GoogleProvider(
   clientId: "YOUR_WEBCLIENT_ID"
)

Una vez que hayas ingresado el ID de cliente web, vuelve a cargar la app. Cuando presionas "Acceder con Google" , aparecerá una ventana nueva (si usas la versión web) que te guiará por el flujo de Acceso con Google. Inicialmente, se verá de la siguiente manera:

14e73e3c9de704bb.png

Configura iOS

Para que funcione en iOS, existe un proceso de configuración adicional.

  1. Ve a la pantalla Configuración del proyecto en Firebase console. Verás una tarjeta en la que se enumeran tus apps de Firebase con un aspecto similar al siguiente: fefa674acbf213cc.png
  2. Haz clic en iOS. Ten en cuenta que el nombre de tu aplicación será diferente al mío. Cuando el mío dice “completo” el tuyo dirá "start" si usaste el proyecto flutter-codelabs/firebase-auth-flutterfire-ui/start para continuar con este codelab.
  3. Haz clic en el botón "GoogleServices-Info.plist". para descargar el archivo de configuración necesario. f89b3192871dfbe3.png
  4. Arrastra y suelta el archivo descargado en el directorio llamado ./ios/Runner en tu proyecto de Flutter.
  5. Abre Xcode; para ello, ejecuta el siguiente comando de terminal desde la raíz de tu proyecto:

abre ios/Runner.xcworkspace

  1. Haz clic con el botón derecho en el directorio Runner y selecciona Add Files to "Runner". 858986063a4c5201.png
  2. Selecciona GoogleService-Info.plist en el administrador de archivos.
  3. En el editor de texto (que no es Xcode), agrega los siguientes atributos CFBundleURLTypes al archivo [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 -->

Si tu app de Flutter ya se ejecuta en iOS, debes cerrarla por completo y, luego, volver a ejecutarla. De lo contrario, ejecuta la app en iOS.

8. ¡Felicitaciones!

Completaste el codelab de la IU de Firebase Auth para Flutter . Puedes encontrar el código completo de este codelab en la sección “complete” Directorio en GitHub: Codelabs de Flutter

Temas abordados

  • Cómo configurar una app de Flutter para usar Firebase
  • Configura un proyecto de Firebase en Firebase console
  • CLI de FlutterFire
  • Firebase CLI
  • Usa Firebase Authentication
  • Cómo usar la IU de FlutterFire para administrar fácilmente la autenticación de Firebase en tu app de Flutter

Próximos pasos

Más información

Sparky está aquí para celebrar contigo.

2a0ad195769368b1.gif