Codelab web de AngularFire

1. Descripción general

En este codelab, aprenderás a usar AngularFire para crear aplicaciones web implementando un cliente de chat con productos y servicios de Firebase.

Una aplicación de chat en la que los usuarios hablan sobre Firebase

Qué aprenderás

  • Compila una app web con Angular y Firebase.
  • Sincronizar datos con Cloud Firestore y Cloud Storage para Firebase
  • Autentica a tus usuarios con Firebase Authentication.
  • Implementa tu app web en Firebase App Hosting.
  • Enviar notificaciones con Firebase Cloud Messaging
  • Recopila los datos de rendimiento de tu aplicación web.

Requisitos

  • Una cuenta de GitHub
  • La capacidad de actualizar tu proyecto de Firebase al plan de precios Blaze
  • El IDE o editor de texto que prefieras, como WebStorm, Sublime o VS Code
  • El administrador de paquetes npm, que suele incluirse con Node.js
  • Una terminal/consola
  • Un navegador de tu elección, como Chrome
  • El código de muestra del codelab (consulta el siguiente paso del codelab para descubrir cómo obtener el código)

2. Obtén el código de muestra

Crea un repositorio de GitHub

La fuente del codelab se puede encontrar en https://github.com/firebase/codelab-friendlychat-web. El repositorio contiene proyectos de muestra para varias plataformas. Sin embargo, en este codelab, solo se usa el directorio angularfire-start.

Copia la carpeta angularfire-start en tu propio repositorio:

  1. Con una terminal, crea una carpeta nueva en tu computadora y cambia al directorio nuevo:
    mkdir codelab-friendlyeats-web
    
    cd codelab-friendlyeats-web
    
  2. Usa el paquete npm giget para recuperar solo la carpeta angularfire-start:
    npx giget@latest gh:firebase/codelab-friendlychat-web/angularfire-start#master . --install
    
  3. Haz un seguimiento de los cambios de forma local con Git:
    git init
    
    git add .
    
    git commit -m "codelab starting point"
    
    git branch -M main
    
  4. Crea un repositorio de GitHub nuevo: https://github.com/new. Ponle el nombre que desees.
    1. GitHub te dará una nueva URL de repositorio que se verá como https://github.com/[user-name]/[repository-name].git o git@github.com:[user-name]/[repository-name].git. Copia esta URL.
  5. Envía los cambios locales a tu nuevo repositorio de GitHub. Ejecuta el siguiente comando y sustituye la URL del repositorio por el marcador de posición your-repository-url.
    git remote add origin your-repository-url
    
    git push -u origin main
    
  6. Ahora deberías ver el código de partida en tu repositorio de GitHub.

3. Crea y configura un proyecto de Firebase

Crea un proyecto de Firebase

  1. Accede a Firebase console.
  2. En Firebase console, haz clic en Agregar proyecto y, luego, asígnale el nombre FriendlyChat. Recuerda el ID de tu proyecto de Firebase.
  3. Desmarca la opción Habilitar Google Analytics para este proyecto.
  4. Haz clic en Crear proyecto.

La aplicación que compilarás usa los productos de Firebase disponibles para las apps web:

  • Firebase Authentication, a fin de permitir que los usuarios accedan a tu app con facilidad
  • Cloud Firestore, a fin de guardar datos estructurados en la nube y recibir notificaciones al instante cuando se modifiquen los datos
  • Cloud Storage para Firebase, a fin de guardar archivos en la nube
  • Firebase App Hosting para compilar, alojar y entregar la app.
  • Firebase Cloud Messaging, a fin de enviar notificaciones push y mostrar notificaciones emergentes del navegador
  • Firebase Performance Monitoring para recopilar datos de rendimiento de los usuarios de tu app

Algunos de estos productos necesitan una configuración especial o deben habilitarse mediante Firebase console.

Actualiza tu plan de precios de Firebase

Para usar App Hosting, tu proyecto de Firebase debe tener el plan de precios Blaze, lo que significa que está asociado a una cuenta de Facturación de Cloud.

  • Una cuenta de Facturación de Cloud requiere una forma de pago, como una tarjeta de crédito.
  • Si es la primera vez que usas Firebase y Google Cloud, verifica si cumples con los requisitos para obtener un crédito de USD 300 y una cuenta de Facturación de Cloud de prueba gratuita.

Para actualizar tu proyecto al plan Blaze, sigue estos pasos:

  1. En Firebase console, selecciona la opción para actualizar tu plan.
  2. En el diálogo, selecciona el plan Blaze y, luego, sigue las instrucciones en pantalla para asociar tu proyecto con una cuenta de Facturación de Cloud.
    Si necesitas crear una cuenta de Facturación de Cloud, es posible que debas volver a la actualización. en Firebase console para completar la actualización.

Agrega una app web de Firebase al proyecto

  1. Haz clic en el ícono de Web 58d6543a156e56f9.png para crear una nueva app web de Firebase.
  2. Registra la app con el sobrenombre Friendly Chat. No marques la casilla junto a Configurar Firebase Hosting para esta app también. Haz clic en Registrar app.
  3. En el siguiente paso, verás un objeto de configuración. No lo necesitas ahora mismo. Haz clic en Ir a la consola.

Captura de pantalla de Registrar app web

Configura la autenticación

Para permitir que los usuarios accedan a la app web con sus Cuentas de Google, usarás el método de acceso de Google.

  1. En Firebase console, navega a Autenticación.
  2. Haz clic en Comenzar.
  3. En la columna Proveedores adicionales, haz clic en Google > Habilitar.
  4. En el cuadro de texto Nombre público del proyecto, ingresa un nombre fácil de recordar, como My Next.js app.
  5. En el menú desplegable Correo electrónico de asistencia para el proyecto, selecciona tu dirección de correo electrónico.
  6. Haz clic en Guardar.

Habilitar Cloud Firestore

La app web usa Cloud Firestore para guardar mensajes de chat y recibir mensajes nuevos.

Deberás habilitar Cloud Firestore:

  1. En Firebase console, navega a Firestore.
  2. Haz clic en Crear base de datos > Siguiente > Iniciar en modo de prueba > A continuación.
    Más adelante en este codelab, agregarás reglas de seguridad para proteger tus datos. No distribuyas ni expongas una app de forma pública sin agregar reglas de seguridad para tu base de datos.
  3. Usa la ubicación predeterminada o selecciona la que quieras.
    Para una app real, debes elegir una ubicación que esté cerca de tus usuarios. Ten en cuenta que esta ubicación no se puede cambiar más adelante y que también será automáticamente la ubicación de tu bucket predeterminado de Cloud Storage (próximo paso).
  4. Haz clic en Listo.

Habilita Cloud Storage

La app web usa Cloud Storage para Firebase para almacenar, subir y compartir fotos.

Deberás habilitar Cloud Storage:

  1. En Firebase console, navega a Storage.
  2. Haz clic en Comenzar > Comenzar en modo de prueba > Siguiente.
    Más adelante en este codelab, agregarás reglas de seguridad para proteger tus datos. No distribuyas ni expongas una app públicamente sin agregar reglas de seguridad para tu bucket de almacenamiento.
  3. La ubicación de tu bucket ya debería estar seleccionada (debido a la configuración de Firestore en el paso anterior).
  4. Haz clic en Listo.

4. Instala la interfaz de línea de comandos de Firebase

La interfaz de línea de comandos (CLI) de Firebase te permite usar Firebase Hosting para entregar tu app web de manera local y también implementarla en tu proyecto de Firebase.

  1. Ejecuta el siguiente comando npm para instalar la CLI:
npm -g install firebase-tools@latest
  1. Ejecuta el siguiente comando para verificar que la CLI se haya instalado de forma correcta:
firebase --version

Asegúrate de que la versión de Firebase CLI sea 13.9.0 o posterior.

  1. Ejecuta el siguiente comando para autorizar Firebase CLI:
firebase login

Configuraste la plantilla de la app web para extraer la configuración de tu app para Firebase Hosting desde el directorio local de tu app (el repositorio que clonaste antes en el codelab). Sin embargo, para extraer la configuración, debes asociar la app con el proyecto de Firebase.

  1. Asegúrate de que la línea de comandos acceda al directorio angularfire-start local de la app.
  2. Ejecuta el siguiente comando para asociar tu app con el proyecto de Firebase:
firebase use --add
  1. Cuando se te solicite, selecciona el ID de tu proyecto y asígnale un alias a tu proyecto de Firebase.

Un alias es útil si tienes varios entornos (producción, etapa de pruebas, etcétera). Sin embargo, en este codelab, solo usaremos el alias de default.

  1. Sigue las instrucciones restantes en la línea de comandos.

5. Instala AngularFire

Antes de ejecutar el proyecto, asegúrate de tener configurados Angular CLI y AngularFire.

  1. En una consola, ejecuta el siguiente comando:
npm install -g @angular/cli
  1. Luego, en una consola desde el directorio angularfire-start, ejecuta el siguiente comando de la CLI de Angular:
ng add @angular/fire

Esto instalará todas las dependencias necesarias para tu proyecto.

  1. Cuando se te solicite, desmarca ng deploy -- hosting con la barra espaciadora. Selecciona las siguientes funciones con las teclas de flecha y la barra espaciadora:
    • Authentication
    • Firestore
    • Cloud Messaging
    • Cloud Storage
  2. Presiona enter y sigue las indicaciones restantes.
  3. Crea una confirmación con el mensaje de confirmación “Install AngularFire” y enviarla a tu repositorio de GitHub.

6. Crea un backend de App Hosting

En esta sección, configurarás un backend de App Hosting para mirar una rama en tu repositorio de Git.

Al final de esta sección, tendrás un backend de App Hosting conectado a tu repositorio en GitHub que volverá a compilar y lanzar automáticamente una versión nueva de tu app cada vez que envíes una confirmación nueva a tu rama main.

  1. Ve a la página Hosting de apps en Firebase console:

El estado cero de la consola de App Hosting, con un botón "Comenzar"

  1. Haz clic en "Comenzar". para iniciar el flujo de creación del backend. Configura tu backend de la siguiente manera:
  2. Sigue las indicaciones del primer paso para conectar el repositorio de GitHub que creaste antes.
  3. Establece la configuración de implementación:
    1. Conserva el directorio raíz como /
    2. Establece la rama activa en main.
    3. Habilitar los lanzamientos automáticos
  4. Asigna el nombre friendlychat-codelab a tu backend.
  5. En “Crea o asocia una app web de Firebase”, elige la app web que configuraste anteriormente en “Selecciona una app web de Firebase existente”. del menú desplegable.
  6. Haz clic en “Finalizar y, luego, implementar”. Después de un momento, se te dirigirá a una nueva página, en la que podrás ver el estado de tu nuevo backend de Hosting de apps.
  7. Una vez que se complete el lanzamiento, haz clic en tu dominio gratuito en "dominios". Es posible que tarde unos minutos en comenzar a funcionar debido a la propagación del DNS.

Implementaste la app web inicial. Cada vez que envíes una confirmación nueva a la rama main de tu repositorio de GitHub, verás que comienza una nueva compilación y lanzamiento en Firebase console, y tu sitio se actualizará automáticamente una vez que se complete el lanzamiento.

El estado cero de la consola de App Hosting, con un botón "Comenzar"

Deberías ver la pantalla de acceso de tu app de FriendlyChat, que (aún) no funciona.

La app no puede realizar ninguna acción en este momento, pero, con tu ayuda, lo hará pronto.

Ahora compilemos una app de chat en tiempo real.

7. Importa y configura Firebase

Configura Firebase

Deberás configurar el SDK de Firebase para indicarle qué proyecto de Firebase estás usando.

  1. Ve a la configuración de tu proyecto en Firebase console.
  2. En la sección "Tus apps" tarjeta, selecciona el sobrenombre de la app para la que necesitas un objeto de configuración.
  3. Selecciona “Configuración” en el panel de fragmentos del SDK de Firebase.

Verás que se generó un archivo de entorno /angularfire-start/src/environments/environment.ts para ti.

  1. Copia el fragmento del objeto de configuración y, luego, agrégalo a angularfire-start/src/firebase-config.js.

environment.ts

export const environment = {
  firebase: {
    apiKey: "API_KEY",
    authDomain: "PROJECT_ID.firebaseapp.com",
    projectId: "PROJECT_ID",
    storageBucket: "PROJECT_ID.appspot.com",
    messagingSenderId: "SENDER_ID",
    appId: "APP_ID",
  },
};

Ver la configuración de AngularFire

Verás que las funciones que seleccionaste en la consola se agregaron automáticamente en el archivo /angularfire-start/src/app/app.config.ts. Esto permite que tu app use las funciones de Firebase.

8. Configura el acceso de los usuarios

AngularFire ahora debería estar listo para usarse, ya que se importó y se inicializó en app.config.ts. Ahora, implementarás el acceso de usuarios con Firebase Authentication.

Agregar un dominio autorizado

Firebase Authentication solo permite accesos desde una lista establecida de dominios que controlas. Agrega tu dominio de App Hosting gratuito a la lista de dominios:

  1. Navega a App Hosting.
  2. Copia el dominio de tu backend.
  3. Navega a Configuración de autenticación.
  4. Elige la pestaña Dominios autorizados.
  5. Haz clic en Agregar dominio y pega el dominio de tu backend de Hosting de apps.

Autentica a tus usuarios con Acceso con Google

En la app, cuando un usuario hace clic en el botón Acceder con Google, se activa la función login. En este codelab, debes autorizar a Firebase para que use Google como proveedor de identidad. Usarás una ventana emergente, pero Firebase tiene varios métodos más disponibles.

  1. En el subdirectorio /src/app/services/, abre chat.service.ts.
  2. Busca la función login.
  3. Reemplaza toda la función por el siguiente código.

chat.service.ts

// Signs-in Friendly Chat.
login() {
    signInWithPopup(this.auth, this.provider).then((result) => {
        const credential = GoogleAuthProvider.credentialFromResult(result);
        this.router.navigate(['/', 'chat']);
        return credential;
    })
}

La función logout se activa cuando el usuario hace clic en el botón Salir.

  1. Regresa al archivo src/app/services/chat.service.ts.
  2. Busca la función logout.
  3. Reemplaza toda la función por el siguiente código.

chat.service.ts

// Logout of Friendly Chat.
logout() {
    signOut(this.auth).then(() => {
        this.router.navigate(['/', 'login'])
        console.log('signed out');
    }).catch((error) => {
        console.log('sign out error: ' + error);
    })
}

Realiza un seguimiento del estado de autenticación

Para actualizar nuestra IU según corresponda, necesitas una forma de comprobar si el usuario accedió o salió. AngularFire proporciona una función para obtener un observable que se actualiza cada vez que cambia el estado de autenticación. Ya se implementó, pero vale la pena observarlo.

  1. Regresa al archivo src/app/services/chat.service.ts.
  2. Busca la asignación de variable user$.

chat.service.ts

// observable that is updated when the auth state changes
user$ = user(this.auth);

El código anterior llama a la función user de AngularFire, que muestra un usuario observable. Se activará cada vez que cambie el estado de autenticación (cuando el usuario acceda o salga). Los componentes de las plantillas de Angular en FRIENDChat usan este observable para actualizar la IU y redireccionar, mostrar el usuario en el panel de navegación del encabezado, etcétera.

Prueba el acceso a la app

  1. Crea una confirmación con el mensaje de confirmación “Agrega la autenticación de Google” y enviarla a tu repositorio de GitHub.
  2. Abre la página de Hosting de apps en Firebase console y espera a que se complete el lanzamiento nuevo.
  3. En la app web, actualiza la página y accede a la app con el botón de acceso y tu Cuenta de Google. Si ves un mensaje de error que indica auth/operation-not-allowed, asegúrate de haber habilitado el Acceso con Google como proveedor de autenticación en Firebase console.
  4. Después de acceder, se deberían mostrar tu foto de perfil y nombre de usuario: angularfire-3.png

9. Escriba mensajes en Cloud Firestore

En esta sección, escribirás algunos datos en Cloud Firestore para poder propagar la IU de la app. Puedes hacerlo de forma manual con Firebase console, pero hazlo en la misma app para demostrar una escritura básica de Cloud Firestore.

Modelo de datos

Los datos de Cloud Firestore se dividen en colecciones, documentos, campos y subcolecciones. Almacenarás cada mensaje del chat como un documento en una colección de nivel superior llamada messages.

688d7bc5fb662b57.png

Cómo agregar mensajes a Cloud Firestore

Para almacenar los mensajes de chat que escriben los usuarios, usarás Cloud Firestore.

En esta sección, agregarás la funcionalidad para que los usuarios escriban mensajes nuevos en tu base de datos. Los usuarios que hagan clic en el botón ENVIAR activarán el fragmento de código que aparece abajo. Este agrega un objeto de mensaje con el contenido de los campos de mensaje a tu instancia de Cloud Firestore en la colección messages. El método add() agrega a la colección un documento nuevo con un ID generado automáticamente.

  1. Regresa al archivo src/app/services/chat.service.ts.
  2. Busca la función addMessage.
  3. Reemplaza toda la función por el siguiente código.

chat.service.ts

// Adds a text or image message to Cloud Firestore.
addMessage = async (
  textMessage: string | null,
  imageUrl: string | null,
): Promise<void | DocumentReference<DocumentData>> => {
  // ignore empty messages
  if (!textMessage && !imageUrl) {
    console.log(
      "addMessage was called without a message",
      textMessage,
      imageUrl,
    );
    return;
  }

  if (this.currentUser === null) {
    console.log("addMessage requires a signed-in user");
    return;
  }

  const message: ChatMessage = {
    name: this.currentUser.displayName,
    profilePicUrl: this.currentUser.photoURL,
    timestamp: serverTimestamp(),
    uid: this.currentUser?.uid,
  };

  textMessage && (message.text = textMessage);
  imageUrl && (message.imageUrl = imageUrl);

  try {
    const newMessageRef = await addDoc(
      collection(this.firestore, "messages"),
      message,
    );
    return newMessageRef;
  } catch (error) {
    console.error("Error writing new message to Firebase Database", error);
    return;
  }
};

Cómo probar el envío de mensajes

  1. Crea una confirmación con el mensaje “Publicar chats nuevos en Firestore” y enviarla a tu repositorio de GitHub.
  2. Abre la página de Hosting de apps en Firebase console y espera a que se complete el lanzamiento nuevo.
  3. Actualiza FriendlyChat. Después de acceder, escribe un mensaje, como "Hola", y haz clic en ENVIAR. Esta acción escribirá el mensaje en Cloud Firestore. Sin embargo, aún no verás los datos en tu aplicación web real porque todavía debes implementar la opción para recuperar los datos (en la próxima sección del codelab).
  4. En Firebase console, puede ver el mensaje nuevo que agregó. Abre la IU de Emulator Suite. En la sección Compilación, haz clic en Base de datos de Firestore (o haz clic aquí para ver la colección Mensajes con el mensaje que acabas de agregar:

6812efe7da395692.png

10. Lea los mensajes

Sincronizar mensajes

Para leer los mensajes en la app, deberás agregar un observable que se active cuando cambien los datos y, luego, crear un elemento de la IU que muestre los mensajes nuevos.

Agregarás código que detecte los mensajes agregados recientemente desde la app. En este código, recuperarás la instantánea de la colección messages. Solo mostrarás los últimos 12 mensajes del chat para evitar mostrar un historial muy largo durante la carga.

  1. Regresa al archivo src/app/services/chat.service.ts.
  2. Busca la función loadMessages.
  3. Reemplaza toda la función por el siguiente código.

chat.service.ts

// Loads chat message history and listens for upcoming ones.
loadMessages = () => {
  // Create the query to load the last 12 messages and listen for new ones.
  const recentMessagesQuery = query(collection(this.firestore, 'messages'), orderBy('timestamp', 'desc'), limit(12));
  // Start listening to the query.
  return collectionData(recentMessagesQuery);
}

Para escuchar los mensajes en la base de datos, crea una consulta en una colección con la función collection para especificar en qué colección se encuentran los datos que deseas escuchar. En el código anterior, estás escuchando los cambios dentro de la colección messages, que es donde se almacenan los mensajes de chat. También se aplica un límite: solo se escuchan los últimos 12 mensajes con limit(12) y se ordenan los mensajes por fecha con orderBy('timestamp', 'desc') para obtener los 12 más recientes.

La función collectionData usa instantáneas de forma interna. Esta se activará cuando se realicen cambios en los documentos que coincidan con la consulta, por ejemplo, cuando se borra, se modifica o se agrega un mensaje. Puedes obtener más información al respecto en la documentación de Cloud Firestore.

Prueba la sincronización de mensajes

  1. Crea una confirmación con el mensaje "Show new chats in the UI" y envíala a tu repositorio de GitHub.
  2. Abre la página de Hosting de apps en Firebase console y espera a que se complete el lanzamiento nuevo.
  3. Actualiza FriendlyChat. Los mensajes que creaste anteriormente en la base de datos deberían mostrarse en la IU de FriendlyChat (consulta a continuación). Siéntete libre de escribir mensajes nuevos. deberían aparecer al instante.
  4. (Opcional) Puedes intentar borrar, modificar o agregar mensajes nuevos de forma manual directamente en la sección Firestore de Emulator Suite. cualquier cambio debe reflejarse en la IU.

¡Felicitaciones! Estás leyendo documentos de Cloud Firestore en tu app.

angularfire-2.png

11. Agrega funciones basadas en IA

Usarás la IA de Google para agregar funciones asistivas útiles a la app de chat.

Obtén una clave de API de Google AI

  1. Navega a Google AI Studio y haz clic en Crear clave de API.
  2. Selecciona el proyecto de Firebase que creaste para este codelab. La instrucción es para un proyecto de Google Cloud, pero todos los proyectos de Firebase son proyectos de Google Cloud.
  3. Haz clic en Crear clave de API en un proyecto existente.
  4. Copia la clave de API resultante

Instala una extensión

Esta extensión implementará una función de Cloud que se activará cada vez que se agregue un documento nuevo a la colección messages en Firestore. La función llamará a Gemini y escribirá su respuesta en el campo response del documento.

  1. Haz clic en Instalar en Firebase console en la página de extensión Compila un chatbot con la API de Gemini.
  2. Sigue las indicaciones. Cuando llegues al paso Configurar extensión, establece los siguientes valores de parámetros:
    • Proveedor de la API de Gemini: Google AI
    • Clave de API de IA de Google: Pega la clave que creaste anteriormente y haz clic en Crear secreto.
    • Ruta de acceso a la colección de Firestore: messages
    • Campo de instrucción: text
    • Campo de respuesta: response
    • Campo de pedido: timestamp
    • Contexto: Keep your answers short, informal, and helpful. Use emojis when possible.
  3. Haz clic en Instalar extensión.
  4. Espera a que se termine de instalar la extensión.

Prueba la función de IA

FriendlyChat ya tiene código para leer respuestas de la extensión de IA. Solo tienes que enviar un nuevo mensaje de chat para probarlo.

  1. Abre FriendlyChat y envía un mensaje.
  2. Después de un momento, deberías ver una respuesta emergente junto a tu mensaje. Tiene una nota ✨ ai generated al final para dejar en claro que se creó con IA generativa, no con un usuario real.

12. Cómo enviar imágenes

Ahora, agregarás una función que comparta imágenes.

Si bien Cloud Firestore es bueno para almacenar datos estructurados, Cloud Storage es más adecuado para almacenar archivos. Cloud Storage para Firebase es un servicio de almacenamiento de archivos y BLOB, y lo usarás para almacenar las imágenes que un usuario comparta con nuestra app.

Guarde imágenes en Cloud Storage

En este codelab, ya agregaste un botón que activa un diálogo del selector de archivos. Después de seleccionar un archivo, se llama a la función saveImageMessage y puedes obtener una referencia al archivo seleccionado. La función saveImageMessage realiza las siguientes acciones:

  1. Creará un mensaje de chat "marcador de posición" en el feed del chat para que los usuarios vean una animación de "Cargando" mientras subes la imagen.
  2. Sube el archivo de imagen a Cloud Storage en esta ruta: /<uid>/<file_name>
  3. Genera una URL legible públicamente para el archivo de imagen.
  4. Actualiza el mensaje de chat con la URL del archivo de imagen recién subido en lugar de la imagen de carga temporal.

Ahora, agregarás la funcionalidad para enviar una imagen:

  1. Regresa al archivo src/chat.service.ts.
  2. Busca la función saveImageMessage.
  3. Reemplaza toda la función por el siguiente código.

chat.service.ts

// Saves a new message containing an image in Firestore.
// This first saves the image in Firebase storage.
saveImageMessage = async(file: any) => {
  try {
    // 1 - Add a message with a loading icon that will get updated with the shared image.
    const messageRef = await this.addMessage(null, this.LOADING_IMAGE_URL);

    // 2 - Upload the image to Cloud Storage.
    const filePath = `${this.auth.currentUser?.uid}/${file.name}`;
    const newImageRef = ref(this.storage, filePath);
    const fileSnapshot = await uploadBytesResumable(newImageRef, file);

    // 3 - Generate a public URL for the file.
    const publicImageUrl = await getDownloadURL(newImageRef);

    // 4 - Update the chat message placeholder with the image's URL.
    messageRef ?
    await updateDoc(messageRef, {
      imageUrl: publicImageUrl,
      storageUri: fileSnapshot.metadata.fullPath
    }): null;
  } catch (error) {
    console.error('There was an error uploading a file to Cloud Storage:', error);
  }
}

Prueba el envío de imágenes

  1. Crea una confirmación con el mensaje de confirmación “Agrega la capacidad de publicar imágenes” y enviarla a tu repositorio de GitHub.
  2. Abre la página de Hosting de apps en Firebase console y espera a que se complete el lanzamiento nuevo.
  3. Actualiza FRIENDChat. Después de acceder, haz clic en el botón para subir imágenes que se encuentra en la esquina inferior izquierda angularfire-4.png y selecciona un archivo de imagen con el selector de archivos. Si estás buscando una imagen, no dudes en usar esta bonita imagen de una taza de café.
  4. Debería aparecer un mensaje nuevo en la IU de la app con la imagen que seleccionaste: angularfire-2.png

Si intentas agregar una imagen sin haber accedido, deberías ver un error que indica que debes acceder para agregar imágenes.

13. Mostrar notificaciones

Ahora, agregarás compatibilidad con notificaciones del navegador. La app notificará a los usuarios cuando se publiquen mensajes nuevos en el chat. Firebase Cloud Messaging (FCM) es una solución de mensajería multiplataforma que le permite enviar mensajes y notificaciones de forma segura y gratuita.

Agrega el service worker de FCM

La aplicación web necesita un service worker que reciba y muestre las notificaciones web.

El proveedor de mensajería ya debería estar configurado cuando se agregó AngularFire. Asegúrate de que exista el siguiente código en la sección de importaciones de /angularfire-start/src/app/app.config.ts.

provideMessaging(() => {
    return getMessaging();
}),

app/app.config.ts

El service worker solo debe cargar e inicializar el SDK de Firebase Cloud Messaging, que se encargará de mostrar las notificaciones.

Obtén tokens de dispositivo de FCM

Cuando las notificaciones estén habilitadas en un dispositivo o navegador, recibirá un token de dispositivo. Este token de dispositivo es el que usas para enviar una notificación a un dispositivo o navegador determinados.

Cuando el usuario accede, llamas a la función saveMessagingDeviceToken. Allí obtendrás el token de dispositivo de FCM del navegador y lo guardarás en Cloud Firestore.

chat.service.ts

  1. Busca la función saveMessagingDeviceToken.
  2. Reemplaza toda la función por el siguiente código.

chat.service.ts

// Saves the messaging device token to Cloud Firestore.
saveMessagingDeviceToken= async () => {
    try {
      const currentToken = await getToken(this.messaging);
      if (currentToken) {
        console.log('Got FCM device token:', currentToken);
        // Saving the Device Token to Cloud Firestore.
        const tokenRef = doc(this.firestore, 'fcmTokens', currentToken);
        await setDoc(tokenRef, { uid: this.auth.currentUser?.uid });
 
        // This will fire when a message is received while the app is in the foreground.
        // When the app is in the background, firebase-messaging-sw.js will receive the message instead.
        onMessage(this.messaging, (message) => {
          console.log(
            'New foreground notification from Firebase Messaging!',
            message.notification
          );
        });
      } else {
        // Need to request permissions to show notifications.
        this.requestNotificationsPermissions();
      }
    } catch(error) {
      console.error('Unable to get messaging token.', error);
    };
}

Sin embargo, este código no funcionará en un principio. Para que tu app pueda recuperar el token de dispositivo, el usuario debe otorgarle permiso para mostrar notificaciones (el siguiente paso del codelab).

Solicita permisos para mostrar notificaciones

Si el usuario aún no le otorgó permiso a tu app para mostrar notificaciones, no se te proporcionará un token de dispositivo. En este caso, debes llamar al método requestPermission(), que mostrará un diálogo del navegador en el que se solicitará este permiso (en navegadores compatibles).

8b9d0c66dc36153d.png

  1. Regresa al archivo src/app/services/chat.service.ts.
  2. Busca la función requestNotificationsPermissions.
  3. Reemplaza toda la función por el siguiente código.

chat.service.ts

// Requests permissions to show notifications.
requestNotificationsPermissions = async () => {
    console.log('Requesting notifications permission...');
    const permission = await Notification.requestPermission();
    
    if (permission === 'granted') {
      console.log('Notification permission granted.');
      // Notification permission granted.
      await this.saveMessagingDeviceToken();
    } else {
      console.log('Unable to get permission to notify.');
    }
}

Obtén el token de tu dispositivo

  1. Crea una confirmación con el mensaje de confirmación “Agrega la capacidad de publicar imágenes” y enviarla a tu repositorio de GitHub.
  2. Abre la página de Hosting de apps en Firebase console y espera a que se complete el lanzamiento nuevo.
  3. Actualiza FRIENDChat. Después de acceder, debería aparecer el diálogo de permiso de notificaciones: bd3454e6dbfb6723.png
  4. Haz clic en Permitir.
  5. Abre la Consola de JavaScript de tu navegador. Deberías ver el siguiente mensaje: Got FCM device token: cWL6w:APA91bHP...4jDPL_A-wPP06GJp1OuekTaTZI5K2Tu
  6. Copia el token de dispositivo. Lo necesitarás para la siguiente etapa del codelab.

Cómo enviar una notificación a tu dispositivo

Ahora que tienes tu token de dispositivo, puedes enviar una notificación.

  1. Abre la pestaña Cloud Messaging de Firebase console.
  2. Haz clic en "Nueva notificación".
  3. Ingresa un título y un texto para la notificación.
  4. En el lado derecho de la pantalla, haz clic en "Enviar un mensaje de prueba".
  5. Ingresa el token del dispositivo que copiaste de la Consola de JavaScript de tu navegador y, luego, haz clic en el signo más ("+").
  6. Haz clic en "Probar".

Si la app está en primer plano, verás la notificación en la Consola de JavaScript.

Si tu app está en segundo plano, debería aparecer una notificación en el navegador, como en este ejemplo:

de79e8638a45864c.png

14. Reglas de seguridad de Cloud Firestore

Consulta las reglas de seguridad de la base de datos.

Cloud Firestore usa un lenguaje de reglas específico para definir los derechos de acceso, la seguridad y las validaciones de datos.

Cuando configuraste el proyecto de Firebase al comienzo de este codelab, elegiste usar el "Modo de prueba" reglas de seguridad predeterminadas para no restringir el acceso al almacén de datos. En Firebase console, en la pestaña Rules de la sección Database, puedes ver y modificar estas reglas.

En este momento, deberías ver las reglas predeterminadas, que no restringen el acceso al almacén de datos. Esto significa que cualquier usuario puede leer y escribir en cualquier colección de tu almacén de datos.

rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write;
    }
  }
}

Actualizarás las reglas de restricción con las siguientes reglas:

firestore.rules

rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
    // Messages:
    //   - Anyone can read.
    //   - Authenticated users can add and edit messages.
    //   - Validation: Check name is same as auth token and text length below 300 char or that imageUrl is a URL.
    //   - Deletes are not allowed.
    match /messages/{messageId} {
      allow read;
      allow create, update: if request.auth != null
                    && request.resource.data.name == request.auth.token.name
                    && (request.resource.data.text is string
                      && request.resource.data.text.size() <= 300
                      || request.resource.data.imageUrl is string
                      && request.resource.data.imageUrl.matches('https?://.*'));
      allow delete: if false;
    }
    // FCM Tokens:
    //   - Anyone can write their token.
    //   - Reading list of tokens is not allowed.
    match /fcmTokens/{token} {
      allow read: if false;
      allow write;
    }
  }
}

Las reglas de seguridad deberían actualizarse automáticamente a tu Emulator Suite.

Cómo ver las reglas de seguridad de Cloud Storage

Cloud Storage para Firebase usa un lenguaje de reglas específico para definir los derechos de acceso, la seguridad y las validaciones de datos.

Cuando configuraste el proyecto de Firebase al principio de este codelab, elegiste usar la regla de seguridad predeterminada de Cloud Storage que solo permite que los usuarios autenticados utilicen Cloud Storage. En Firebase console, en la pestaña Rules de la sección Storage, puedes ver y modificar las reglas. Deberías ver la regla predeterminada que permite que cualquier usuario que haya accedido lea y escriba cualquier archivo en tu bucket de almacenamiento.

rules_version = '2';

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if request.auth != null;
    }
  }
}

Deberás actualizar las reglas para hacer lo siguiente:

  • Permitir que cada usuario solo escriba en sus propias carpetas específicas
  • Permitir que cualquier persona lea desde Cloud Storage
  • Asegúrate de que los archivos subidos sean imágenes
  • Restringir el tamaño de las imágenes que se pueden subir a 5 MB como máximo

Esto se puede implementar con las siguientes reglas:

storage.rules

rules_version = '2';

// Returns true if the uploaded file is an image and its size is below the given number of MB.
function isImageBelowMaxSize(maxSizeMB) {
  return request.resource.size < maxSizeMB * 1024 * 1024
      && request.resource.contentType.matches('image/.*');
}

service firebase.storage {
  match /b/{bucket}/o {
    match /{userId}/{messageId}/{fileName} {
      allow write: if request.auth != null && request.auth.uid == userId && isImageBelowMaxSize(5);
      allow read;
    }
  }
}

15. ¡Felicitaciones!

Usaste Firebase para compilar una aplicación web de chat en tiempo real.

Temas abordados

  • Firebase App Hosting
  • Firebase Authentication
  • Cloud Firestore
  • SDK de Firebase para Cloud Storage
  • Firebase Cloud Messaging
  • Firebase Performance Monitoring

Próximos pasos

Más información

16. [Opcional] Aplica la política con la Verificación de aplicaciones

La Verificación de aplicaciones de Firebase ayuda a proteger tus servicios del tráfico no deseado y a proteger tu backend de los abusos. En este paso, agregarás la validación de credenciales y bloquearás a los clientes no autorizados con la Verificación de aplicaciones y reCAPTCHA Enterprise.

Primero, deberás habilitar la Verificación de aplicaciones y reCAPTCHA.

Habilitación de reCAPTCHA Enterprise

  1. En la consola de Cloud, busca y selecciona reCaptcha Enterprise en Seguridad.
  2. Habilita el servicio según se te solicite y haz clic en Create Key.
  3. Ingresa un nombre visible según se te solicite y selecciona Sitio web como el tipo de plataforma.
  4. Agrega las URLs que implementaste a la Lista de dominios y asegúrate de que la opción “Usar el desafío de la casilla de verificación” no se seleccionó la opción.
  5. Haz clic en Create Key y almacena la clave generada en un lugar seguro. Lo necesitarás más adelante en este paso.

Habilita la Verificación de aplicaciones

  1. En Firebase console, busca la sección Build en el panel izquierdo.
  2. Haz clic en Verificación de aplicaciones y, luego, en la pestaña Método de acceso para navegar a Verificación de aplicaciones.
  3. Haz clic en Register, ingresa tu clave de reCAPTCHA Enterprise cuando se te solicite y, luego, haz clic en Save.
  4. En la vista de APIs, selecciona Almacenamiento y haz clic en Aplicar. Haz lo mismo con Cloud Firestore.

Ahora la Verificación de aplicaciones debe aplicarse de manera forzosa. Actualiza la app y trata de ver o enviar mensajes de chat. Deberías recibir el siguiente mensaje de error:

Uncaught Error in snapshot listener: FirebaseError: [code=permission-denied]: Missing or insufficient permissions.

Esto significa que la Verificación de aplicaciones bloquea las solicitudes no validadas de forma predeterminada. Ahora, agreguemos la validación a tu app.

Navega a tu archivo environment.ts y agrega reCAPTCHAEnterpriseKey al objeto environment.

export const environment = {
  firebase: {
    apiKey: 'API_KEY',
    authDomain: 'PROJECT_ID.firebaseapp.com',
    databaseURL: 'https://PROJECT_ID.firebaseio.com',
    projectId: 'PROJECT_ID',
    storageBucket: 'PROJECT_ID.appspot.com',
    messagingSenderId: 'SENDER_ID',
    appId: 'APP_ID',
    measurementId: 'G-MEASUREMENT_ID',
  },
  reCAPTCHAEnterpriseKey: {
    key: "Replace with your recaptcha enterprise site key"
  },
};

Reemplaza el valor de key por tu token de reCaptcha Enterprise.

Luego, navega al archivo app.config.ts y agrega las siguientes importaciones:

import { getApp } from '@angular/fire/app';
import {
  ReCaptchaEnterpriseProvider,
  initializeAppCheck,
  provideAppCheck,
} from '@angular/fire/app-check';

En el mismo archivo app.config.ts, agrega la siguiente declaración de variable global:

declare global {
  var FIREBASE_APPCHECK_DEBUG_TOKEN: boolean;
}

@NgModule({ ...

En las importaciones, agrega la inicialización de la Verificación de aplicaciones con ReCaptchaEnterpriseProvider y establece isTokenAutoRefreshEnabled en true para permitir que los tokens se actualicen automáticamente.

imports: [
BrowserModule,
AppRoutingModule,
CommonModule,
FormsModule,
provideFirebaseApp(() => initializeApp(environment.firebase)),
provideAppCheck(() => {
const appCheck = initializeAppCheck(getApp(), {
  provider: new ReCaptchaEnterpriseProvider(
  environment.reCAPTCHAEnterpriseKey.key
  ),
  isTokenAutoRefreshEnabled: true,
  });
  if (location.hostname === 'localhost') {
    self.FIREBASE_APPCHECK_DEBUG_TOKEN = true;
  }
  return appCheck;
}),

Para permitir pruebas locales, establece self.FIREBASE_APPCHECK_DEBUG_TOKEN en true. Cuando actualices tu app en localhost, se registrará un token de depuración en la consola similar al siguiente:

App Check debug token: CEFC0C76-7891-494B-B764-349BDFD00D00. You will need to add it to your app's App Check settings in the Firebase console for it to work.

Ahora, ve a la vista de apps de la Verificación de aplicaciones en Firebase console.

Haz clic en el menú ampliado y selecciona Administrar tokens de depuración.

Luego, haz clic en Agregar token de depuración y pega el token de depuración de tu consola cuando se te solicite.

Navega al archivo chat.service.ts y agrega la siguiente importación:

import { AppCheck } from '@angular/fire/app-check';

En el mismo archivo chat.service.ts, inserta la Verificación de aplicaciones junto con los otros servicios de Firebase.

export class ChatService {
appCheck: AppCheck = inject(AppCheck);
...
  1. Crea una confirmación con el mensaje "Bloquear clientes no autorizados con App Check" y envíala a tu repositorio de GitHub.
  2. Abre la página de Hosting de apps en Firebase console y espera a que se complete el lanzamiento nuevo.

¡Felicitaciones! App Check ahora debería funcionar en tu app.