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 app de chat en la que los usuarios conversan 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.
  • Implementar la aplicación web en Firebase App Hosting
  • Enviar notificaciones con Firebase Cloud Messaging
  • Recopila los datos de rendimiento de tu app 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 generalmente viene 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, este codelab solo 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 de npm giget para recuperar solo la carpeta angularfire-start:
    npx giget@latest gh:firebase/codelab-friendlychat-web/angularfire-start#master . --install
    
  3. Realiza 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 nuevo repositorio de GitHub: 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 reemplaza la URL de tu 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 asígnale el nombre FriendlyChat al proyecto. Recuerda el ID del 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 aplicaciones 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, a fin de recopilar datos sobre el rendimiento de los usuarios para 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 $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.

Agregar una app web de Firebase al proyecto

  1. Haz clic en el ícono web 58d6543a156e56f9.png para crear una nueva aplicación web de Firebase.
  2. Registra la app con el sobrenombre Friendly Chat. No marques la casilla junto a Configurar Firebase Hosting para esta app; haz clic en Registrar app.
  3. En el siguiente paso, verás un objeto de configuración. No lo necesitas en este momento. 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 aplicación web usa Cloud Firestore para guardar los 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 > 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 de forma pública sin agregar reglas de seguridad para tu base de datos.
  3. Usa la ubicación predeterminada o selecciona una que elijas.
    En el caso de una app real, te recomendamos que elijas una ubicación cercana a los usuarios. Ten en cuenta que esta ubicación no se puede cambiar más adelante y también será automáticamente la ubicación de tu bucket predeterminado de Cloud Storage (paso siguiente).
  4. Haz clic en Listo.

Habilita Cloud Storage

La aplicación web usa Cloud Storage para Firebase para almacenar, subir y compartir imágenes.

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 de forma pública sin agregar reglas de seguridad para tu bucket de Storage.
  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 v13.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 local angularfire-start de tu app.
  2. Ejecuta el siguiente comando para asociar la 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, para este codelab, solo usaremos el alias de default.

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

5. Instalar 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 envíala a tu repositorio de GitHub.

6. Crea un backend de Hosting de apps

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 Hosting de apps conectado a tu repositorio en GitHub que volverá a compilar y a 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 de 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 anteriormente.
  3. Establece la configuración de implementación:
    1. Mantén el directorio raíz como /.
    2. Establece la rama activa en main.
    3. Habilitar 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 el menú desplegable “Selecciona una app web de Firebase existente”.
  6. Haz clic en "Finalizar e 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. Cuando se complete el lanzamiento, haz clic en tu dominio gratuito en la sección “dominios”. Esto puede tardar unos minutos en comenzar a funcionar debido a la propagación de 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 compilación y un lanzamiento nuevos en Firebase console, y tu sitio se actualizará automáticamente cuando 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 la 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 del proyecto en Firebase console.
  2. En la tarjeta "Tus apps", 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 gratuito de Hosting de apps 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 del 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 hay varios métodos más disponibles de Firebase.

  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);
    })
}

Cómo hacer 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 elemento 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 navegador del encabezado, etcétera.

Prueba el acceso a la app

  1. Crea una confirmación con el mensaje de confirmación “Agregando autenticación de Google” 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. 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, deberían aparecer 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

Agrega 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;
  }
};

Prueba el envío de mensajes

  1. Crea una confirmación con el mensaje “Publicar chats nuevos en Firestore” 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. Después de acceder, ingresa 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 app web real porque aún debes implementar la recuperación de datos (la siguiente 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 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 mensajes nuevos.

Agregarás código que escucha los mensajes recién agregados 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. Además, si quieres aplicar un límite, quieres escuchar los últimos 12 mensajes con limit(12) y ordenarlos por fecha con orderBy('timestamp', 'desc') para ver 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 sobre este tema en la documentación de Cloud Firestore.

Prueba la sincronización de mensajes

  1. Crea una confirmación con el mensaje de confirmación “Mostrar chats nuevos en la IU” 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. Los cambios deberían reflejarse en la IU.

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

angularfire-2.png

11. Agregar 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 solicitud es para un proyecto de Google Cloud, pero cada proyecto de Firebase es 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 Cloud Function que se activa cada vez que se agrega 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 la extensión, establece los siguientes valores de los 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 termine de instalarse la extensión

Probar función de IA

FRIENDChat ya tiene código para leer las respuestas de la extensión de IA. Solo debes 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 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. Enviar imágenes

Ahora, agregarás una función para compartir imágenes.

Si bien Cloud Firestore es una buena opción 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, que usarás con el fin de almacenar todas 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 logra lo siguiente:

  1. Crea 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 de acceso: /<uid>/<file_name>
  3. Genera una URL de lectura pública 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 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. 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 las 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.module.ts.

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

app/app.module.ts

El service worker solo necesita 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).

Cómo solicitar permisos para mostrar notificaciones

Cuando el usuario no haya otorgado permiso a tu app para mostrar notificaciones, no se te otorgará un token de dispositivo. En este caso, debes llamar al método requestPermission(), que mostrará un diálogo del navegador en el que se solicita 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 tu token de dispositivo

  1. Crea una confirmación con el mensaje de confirmación “Agrega la capacidad de publicar imágenes” 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. 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 la parte derecha de la pantalla, haz clic en "enviar un mensaje de prueba".
  5. Ingresa el token de 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 las bases 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 las reglas de seguridad predeterminadas del "modo de prueba" para no restringir el acceso al almacén de datos. En Firebase console, en la pestaña Reglas 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.

Consulta 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 comienzo de este codelab, elegiste usar la regla de seguridad predeterminada de Cloud Storage, que solo permite que los usuarios autenticados usen Cloud Storage. Puedes ver y modificar reglas en Firebase console, en la pestaña Reglas de la sección Storage. 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 escriba solo en sus propias carpetas específicas
  • Permitir que cualquier persona lea desde Cloud Storage
  • Asegurarse 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] Aplicar de manera forzosa 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, debes habilitar la Verificación de aplicaciones y el reCAPTCHA.

Habilitación de reCAPTCHA Enterprise

  1. En la consola de Cloud, busca y selecciona reCaptcha Enterprise en Seguridad.
  2. Habilita el servicio cuando se te solicite y haz clic en Crear clave.
  3. Ingresa un nombre visible cuando se te solicite y selecciona Sitio web como tu 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 esté seleccionada.
  5. Haz clic en Crear clave y almacena la clave generada en algún lugar para protegerla. Lo necesitarás más adelante en este paso.

Habilita la Verificación de aplicaciones

  1. En Firebase console, localiza la sección Compilación 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.module.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.module.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 las 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 “Bloquea los clientes no autorizados con la Verificación de aplicaciones” 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! La Verificación de aplicaciones ahora debería funcionar en su aplicación.