Envía notificaciones para una app web con Cloud Messaging y Cloud Functions

1. Descripción general

En este codelab, aprenderás a usar Cloud Functions para Firebase y agregar funcionalidad a una app web de chat enviando notificaciones a los usuarios de la app de chat.

3b1284f5144b54f6.png

Qué aprenderás

  • Cómo usar el SDK de Firebase para crear funciones de Google Cloud Functions
  • Cómo activar funciones de Cloud Functions basadas en eventos de Auth, Cloud Storage y Cloud Firestore
  • Cómo agregar compatibilidad con Firebase Cloud Messaging a su aplicación web

Requisitos

  • Una tarjeta de crédito Cloud Functions para Firebase requiere el plan Blaze de Firebase, lo que significa que deberás habilitar la facturación en tu proyecto de Firebase con una tarjeta de crédito.
  • El IDE o editor de texto que prefieras, como WebStorm, Atom o Sublime
  • Una terminal para ejecutar comandos de shell con NodeJS v9 instalado
  • Un navegador, como Chrome
  • El código de muestra Consulta el siguiente paso para obtener más información.

2. Obtén el código de muestra

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

git clone https://github.com/firebase/friendlychat

Importa la app de partida

Con tu IDE, abre o importa el directorio android_studio_folder.pngcloud-functions-start del directorio de código de muestra. Este directorio contiene el código inicial para el codelab, que consta de una aplicación web de chat completamente funcional.

3. Crea un proyecto de Firebase y configura tu app

Crear proyecto

  1. Accede a la consola de Firebase con tu Cuenta de Google.
  2. Haz clic en el botón para crear un proyecto nuevo y, luego, ingresa un nombre (por ejemplo, FriendlyChat).
  3. Haz clic en Continuar.
  4. Si se te solicita, revisa y acepta las Condiciones de Firebase y, luego, haz clic en Continuar.
  5. (Opcional) Habilita la asistencia de IA en Firebase console (llamada "Gemini en Firebase").
  6. Para este codelab, no necesitas Google Analytics, por lo que debes desactivar la opción de Google Analytics.
  7. Haz clic en Crear proyecto, espera a que se aprovisione y, luego, haz clic en Continuar.

Actualiza al plan Blaze

Para usar Cloud Functions para Firebase y Cloud Storage para Firebase, tu proyecto de Firebase debe tener el plan de precios de pago por uso (Blaze), lo que significa que está vinculado 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.
  • Si realizas este codelab como parte de un evento, pregúntale al organizador si hay créditos de Cloud disponibles.

Si no tienes acceso a una tarjeta de crédito o no te sientes cómodo con el plan de precios Blaze, considera usar Firebase Emulator Suite, que te permitirá emular Cloud Functions de forma gratuita en tu máquina local.

Todos los proyectos de Firebase, incluidos los que tienen el plan de precios Blaze, siguen teniendo acceso a las cuotas de uso sin costo para Cloud Functions. Los pasos que se describen en este codelab se encuentran dentro de los límites de uso del nivel gratuito. Sin embargo, verás pequeños cargos (alrededor de USD 0.03) de Cloud Storage, que se usa para alojar las imágenes de compilación de Cloud Functions.

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

  1. En Firebase console, selecciona la opción para actualizar tu plan.
  2. Selecciona el plan Blaze. Sigue las instrucciones en pantalla para vincular una cuenta de Facturación de Cloud a tu proyecto.
    Si necesitas crear una cuenta de Facturación de Cloud como parte de esta actualización, es posible que debas volver al flujo de actualización en Firebase console para completar la actualización.

Habilita Google Auth

Para permitir que los usuarios accedan a la app, usaremos la autenticación de Google, que debe estar habilitada.

En Firebase console, abre la sección Compilación > Autenticación > pestaña Método de acceso (o haz clic aquí para ir allí). Luego, habilita el proveedor de acceso de Google y haz clic en Guardar. Esto permitirá que los usuarios accedan a la app web con sus Cuentas de Google.

Además, puedes establecer el nombre público de tu app como Friendly Chat:

8290061806aacb46.png

Configura Cloud Storage para Firebase

La app usa Cloud Storage para subir imágenes.

Sigue estos pasos para configurar Cloud Storage para Firebase en tu proyecto de Firebase:

  1. En el panel izquierdo de Firebase console, expande Compilación y, luego, selecciona Storage.
  2. Haz clic en Comenzar.
  3. Selecciona una ubicación para tu bucket de Storage predeterminado.
    Los buckets en US-WEST1, US-CENTRAL1 y US-EAST1 pueden aprovechar el nivel “Siempre gratuito” para Google Cloud Storage. Los buckets de todas las demás ubicaciones siguen los precios y el uso de Google Cloud Storage.
  4. Haz clic en Comenzar en modo de prueba. Lee la renuncia de responsabilidad sobre las reglas de seguridad.
    No distribuyas ni expongas una app de forma pública sin agregar reglas de seguridad para tu bucket de Storage.
  5. Haz clic en Crear.

Cómo agregar una app web

En Firebase Console, agrega una app web. Para ello, ve a Configuración del proyecto y desplázate hacia abajo hasta Agregar app. Elige la opción web como plataforma y marca la casilla para configurar Firebase Hosting. Luego, registra la app y haz clic en Siguiente para completar los pasos restantes y, por último, haz clic en Ir a la consola.

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

La interfaz de línea de comandos (CLI) de Firebase te permitirá publicar la app web a nivel local y, luego, implementar tu app web y Cloud Functions.

Para instalar o actualizar la CLI, ejecuta el siguiente comando npm:

npm -g install firebase-tools

Para verificar que la CLI se haya instalado correctamente, abre una consola y ejecuta el siguiente comando:

firebase --version

Asegúrate de que la versión de Firebase CLI sea superior a 4.0.0 para que tenga todas las funciones más recientes que se requieren para Cloud Functions. De lo contrario, ejecuta npm install -g firebase-tools para actualizarlo, como se muestra arriba.

Ejecuta el siguiente comando para autorizar Firebase CLI:

firebase login

Asegúrate de estar en el directorio cloud-functions-start y, luego, configura Firebase CLI para usar tu proyecto de Firebase:

firebase use --add

A continuación, selecciona el ID de tu proyecto y sigue las instrucciones. Cuando se te solicite, puedes elegir cualquier alias, como codelab.

5. Implemente y ejecute la aplicación web

Ahora que importaste y configuraste tu proyecto, puedes ejecutar la app web por primera vez. Abre una ventana de terminal, navega a la carpeta cloud-functions-start y, luego, implementa la app web en Firebase Hosting con el siguiente comando:

firebase deploy --except functions

Este es el resultado que debería ver en la consola:

i deploying database, storage, hosting
  database: rules ready to deploy.
i  storage: checking rules for compilation errors...
  storage: rules file compiled successfully
i  hosting: preparing ./ directory for upload...
  hosting: ./ folder uploaded successfully
 storage: rules file compiled successfully
 hosting: 8 files uploaded successfully
i starting release process (may take several minutes)...

 Deploy complete!

Project Console: https://console.firebase.google.com/project/friendlychat-1234/overview
Hosting URL: https://friendlychat-1234.firebaseapp.com

Abrir la app web

La última línea debe mostrar la URL de hosting. Ahora, la app web debería publicarse desde esta URL, que debería tener el formato https://<project-id>.firebaseapp.com. Ábrela. Deberías ver la IU en funcionamiento de una app de chat.

Utiliza el botón ACCEDER CON GOOGLE para acceder a la app y agregar algunos mensajes y publicar imágenes:

3b1284f5144b54f6.png

Si accedes a la app por primera vez en un navegador nuevo, asegúrate de permitir las notificaciones cuando se te solicite: 8b9d0c66dc36153d.png

Deberemos habilitar las notificaciones más adelante.

Si hiciste clic en Bloquear por accidente, puedes cambiar este parámetro de configuración. Para ello, haz clic en el botón 🔒 Seguro que está a la izquierda de la URL en la barra multifunción de Chrome y activa la barra junto a Notificaciones:

e926868b0546ed71.png

Ahora, agregaremos algunas funcionalidades con el SDK de Firebase para Cloud Functions.

6. El directorio de Functions

Cloud Functions te permite ejecutar código en la nube fácilmente sin necesidad de configurar un servidor. Veremos cómo compilar funciones que reaccionen a eventos de Firebase Auth, Cloud Storage y la base de datos de Firebase Firestore. Comencemos con Auth.

Cuando uses el SDK de Firebase para Cloud Functions, tu código de Functions residirá en el directorio functions (de forma predeterminada). Tu código de Functions también es una aplicación de Node.js y, por lo tanto, necesita un package.json que brinde información sobre tu aplicación y una lista de las dependencias.

Para que te resulte más fácil, ya creamos el archivo functions/index.js en el que se incluirá tu código. Puedes inspeccionar este archivo antes de continuar.

cd functions
ls

Si no conoces Node.js, te recomendamos que obtengas más información sobre él antes de continuar con el codelab.

El archivo package.json ya muestra dos dependencias requeridas: el SDK de Firebase para Cloud Functions y el SDK de Firebase Admin. Para instalarlos de forma local, ve a la carpeta functions y ejecuta el siguiente comando:

npm install

Ahora, veamos el archivo index.js:

index.js

/**
 * Copyright 2017 Google Inc. All Rights Reserved.
 * ...
 */

// TODO(DEVELOPER): Import the Cloud Functions for Firebase and the Firebase Admin modules here.

// TODO(DEVELOPER): Write the addWelcomeMessage Function here.

// TODO(DEVELOPER): Write the blurImages Function here.

// TODO(DEVELOPER): Write the sendNotification Function here.

Importaremos los módulos necesarios y, luego, escribiremos tres funciones en lugar de los TODO. Comencemos por importar los módulos de Node obligatorios.

7. Importe los módulos de Cloud Functions y Firebase Admin

Durante este codelab, se requerirán dos módulos: firebase-functions permite escribir registros y activadores de Cloud Functions, mientras que firebase-admin permite usar la plataforma de Firebase en un servidor con acceso de administrador para realizar acciones como escribir en Cloud Firestore o enviar notificaciones de FCM.

En el archivo index.js, reemplaza el primer TODO por lo siguiente:

index.js

/**
 * Copyright 2017 Google Inc. All Rights Reserved.
 * ...
 */

// Import the Firebase SDK for Google Cloud Functions.
const functions = require('firebase-functions');
// Import and initialize the Firebase Admin SDK.
const admin = require('firebase-admin');
admin.initializeApp();

// TODO(DEVELOPER): Write the addWelcomeMessage Function here.

// TODO(DEVELOPER): Write the blurImages Function here.

// TODO(DEVELOPER): Write the sendNotification Function here.

El SDK de Firebase Admin se puede configurar automáticamente cuando se implementa en un entorno de Cloud Functions o en otros contenedores de Google Cloud Platform, y esto sucede cuando llamamos a admin.initializeApp() sin argumentos.

Ahora, agreguemos una función que se ejecute cuando un usuario acceda por primera vez a la app de chat y agreguemos un mensaje de chat para darle la bienvenida.

8. Deles la bienvenida a los usuarios nuevos

Estructura de los mensajes de chat

Los mensajes que se publican en el feed de chat de FriendlyChat se almacenan en Cloud Firestore. Veamos la estructura de datos que usamos para un mensaje. Para ello, publica un nuevo mensaje en el chat que diga "Hello World":

11f5a676fbb1a69a.png

Debería aparecer de esta manera:

fe6d1c020d0744cf.png

En Firebase console, haz clic en Firestore Database en la sección Build. Deberías ver la colección de mensajes y un documento que contiene el mensaje que escribiste:

442c9c10b5e2b245.png

Como puedes ver, los mensajes de chat se almacenan en Cloud Firestore como un documento con los atributos name, profilePicUrl, text y timestamp agregados a la colección messages.

Cómo agregar mensajes de bienvenida

La primera Cloud Function agrega un mensaje que les da la bienvenida al chat a los usuarios nuevos. Para ello, podemos usar el activador functions.auth().onCreate, que ejecuta la función cada vez que un usuario accede por primera vez a la app de Firebase. Agrega la función addWelcomeMessages a tu archivo index.js:

index.js

// Adds a message that welcomes new users into the chat.
exports.addWelcomeMessages = functions.auth.user().onCreate(async (user) => {
  functions.logger.log('A new user signed in for the first time.');
  const fullName = user.displayName || 'Anonymous';

  // Saves the new welcome message into the database
  // which then displays it in the FriendlyChat clients.
  await admin.firestore().collection('messages').add({
    name: 'Firebase Bot',
    profilePicUrl: '/images/firebase-logo.png', // Firebase logo
    text: `${fullName} signed in for the first time! Welcome!`,
    timestamp: admin.firestore.FieldValue.serverTimestamp(),
  });
  functions.logger.log('Welcome message written to database.');
});

En Node, esta función, que es necesaria para Cloud Functions, se agrega al objeto especial exports a fin de que se pueda acceder a ella desde fuera del archivo actual.

En la función anterior, agregamos un nuevo mensaje de bienvenida publicado por "Firebase Bot" a la lista de mensajes de chat. Para ello, usamos el método add en la colección messages de Cloud Firestore, que es donde se almacenan los mensajes del chat.

Dado que esta es una operación asíncrona, debemos devolver el objeto Promise que indica cuándo finalizó la escritura de Cloud Firestore para que Cloud Functions no se ejecute demasiado pronto.

Implementa Cloud Functions con los siguientes comandos:

Las Cloud Functions solo estarán activas después de que las implementes. Para ello, ejecuta el siguiente comando en la línea de comandos:

firebase deploy --only functions

Este es el resultado que debería ver en la consola:

i  deploying functions
i  functions: ensuring necessary APIs are enabled...
  functions: missing necessary APIs. Enabling now...
i  env: ensuring necessary APIs are enabled...
  env: missing necessary APIs. Enabling now...
i  functions: waiting for APIs to activate...
i  env: waiting for APIs to activate...
  env: all necessary APIs are enabled
  functions: all necessary APIs are enabled
i  functions: preparing functions directory for uploading...
i  functions: packaged functions (X.XX KB) for uploading
  functions: functions folder uploaded successfully
i  starting release process (may take several minutes)...
i  functions: creating function addWelcomeMessages...
  functions[addWelcomeMessages]: Successful create operation. 
  functions: all functions deployed successfully!

  Deploy complete!

Project Console: https://console.firebase.google.com/project/friendlypchat-1234/overview

Prueba la función

Cuando la función se haya implementado correctamente, necesitarás que un usuario acceda por primera vez.

  1. Abre la app en tu navegador con la URL de Hosting (con el formato https://<project-id>.firebaseapp.com).
  2. Con un usuario nuevo, accede por primera vez a tu app con el botón Acceder.

262535d1b1223c65.png

  1. Después de acceder, debería mostrarse automáticamente un mensaje de bienvenida:

1c70e0d64b23525b.png

9. Moderación de imágenes

Los usuarios pueden subir todo tipo de imágenes al chat, y siempre es importante moderar las imágenes ofensivas, sobre todo en plataformas sociales públicas. En FriendlyChat, las imágenes que se publican en el chat se almacenan en buckets de Cloud Storage.

Con Cloud Functions, puedes detectar las cargas de imágenes nuevas con el activador functions.storage().onFinalize. Este activador se ejecutará cada vez que se suba un archivo nuevo a Cloud Storage o se modifique.

Para moderar imágenes, seguiremos el siguiente proceso:

  1. Utilice la API de Cloud Vision a fin de comprobar si la imagen se marcó como contenido violento o para adultos.
  2. Si la imagen se marcó, descárgala en la instancia de Functions que está en ejecución.
  3. Use ImageMagick para desenfocar la imagen.
  4. Suba la imagen desenfocada a Cloud Storage.

Habilite la API de Cloud Vision

Como usaremos la API de Google Cloud Vision en esta función, debes habilitarla en tu proyecto de Firebase. Sigue este vínculo, selecciona tu proyecto de Firebase y habilita la API:

5c77fee51ec5de49.png

Instale dependencias

Para moderar imágenes, usaremos la biblioteca cliente de Google Cloud Vision para Node.js, @google-cloud/vision, para analizar las imágenes con la API de Cloud Vision y detectar las que sean inapropiadas.

Para instalar este paquete en tu app de Cloud Functions, ejecuta el siguiente comando de npm install --save. Asegúrate de hacerlo desde el directorio functions.

npm install --save @google-cloud/vision@2.4.0

De este modo, el paquete se instalará de forma local y se agregará como una dependencia declarada en tu archivo package.json.

Importa y configura dependencias

Para importar las dependencias que se instalaron y algunos módulos principales de Node.js (path, os y fs) que necesitaremos en esta sección, agrega las siguientes líneas en la parte superior de tu archivo index.js:

index.js

const Vision = require('@google-cloud/vision');
const vision = new Vision.ImageAnnotatorClient();
const {promisify} = require('util');
const exec = promisify(require('child_process').exec);

const path = require('path');
const os = require('os');
const fs = require('fs');

Como la función se ejecutará dentro de un entorno de Google Cloud, no es necesario configurar las bibliotecas de Cloud Storage y Cloud Vision: se configurarán automáticamente para usar tu proyecto.

Cómo detectar imágenes inapropiadas

Usarás el activador functions.storage.onChange de Cloud Functions, que ejecuta tu código en cuanto se crea o modifica un archivo o una carpeta en un bucket de Cloud Storage. Agrega la función blurOffensiveImages a tu archivo index.js:

index.js

// Checks if uploaded images are flagged as Adult or Violence and if so blurs them.
exports.blurOffensiveImages = functions.runWith({memory: '2GB'}).storage.object().onFinalize(
    async (object) => {
      const imageUri = `gs://${object.bucket}/${object.name}`;
      // Check the image content using the Cloud Vision API.
      const batchAnnotateImagesResponse = await vision.safeSearchDetection(imageUri);
      const safeSearchResult = batchAnnotateImagesResponse[0].safeSearchAnnotation;
      const Likelihood = Vision.protos.google.cloud.vision.v1.Likelihood;
      if (Likelihood[safeSearchResult.adult] >= Likelihood.LIKELY ||
          Likelihood[safeSearchResult.violence] >= Likelihood.LIKELY) {
        functions.logger.log('The image', object.name, 'has been detected as inappropriate.');
        return blurImage(object.name);
      }
      functions.logger.log('The image', object.name, 'has been detected as OK.');
    });

Ten en cuenta que agregamos cierta configuración de la instancia de Cloud Functions que ejecutará la función. Con .runWith({memory: '2GB'}), solicitamos que la instancia obtenga 2 GB de memoria en lugar de la cantidad predeterminada, ya que esta función consume mucha memoria.

Cuando se activa la función, la imagen se analiza con la API de Cloud Vision para detectar si se marca como contenido violento o para adultos. Si se detecta que la imagen es inapropiada según estos criterios, la desenfocamos, lo que se hace en la función blurImage, como veremos a continuación.

Cómo desenfocar la imagen

Agrega la siguiente función blurImage en tu archivo index.js:

index.js

// Blurs the given image located in the given bucket using ImageMagick.
async function blurImage(filePath) {
  const tempLocalFile = path.join(os.tmpdir(), path.basename(filePath));
  const messageId = filePath.split(path.sep)[1];
  const bucket = admin.storage().bucket();

  // Download file from bucket.
  await bucket.file(filePath).download({destination: tempLocalFile});
  functions.logger.log('Image has been downloaded to', tempLocalFile);
  // Blur the image using ImageMagick.
  await exec(`convert "${tempLocalFile}" -channel RGBA -blur 0x24 "${tempLocalFile}"`);
  functions.logger.log('Image has been blurred');
  // Uploading the Blurred image back into the bucket.
  await bucket.upload(tempLocalFile, {destination: filePath});
  functions.logger.log('Blurred image has been uploaded to', filePath);
  // Deleting the local file to free up disk space.
  fs.unlinkSync(tempLocalFile);
  functions.logger.log('Deleted local file.');
  // Indicate that the message has been moderated.
  await admin.firestore().collection('messages').doc(messageId).update({moderated: true});
  functions.logger.log('Marked the image as moderated in the database.');
}

En la función anterior, el objeto binario de la imagen se descarga desde Cloud Storage. Luego, la imagen se desenfoca con la herramienta convert de ImageMagick, y la versión desenfocada se vuelve a subir al bucket de Storage. A continuación, borramos el archivo en la instancia de Cloud Functions para liberar espacio en disco, y lo hacemos porque se puede volver a utilizar la misma instancia de Cloud Functions y, si no se limpian los archivos, podría quedarse sin espacio en disco. Por último, agregamos un valor booleano al mensaje de chat, que indica que se moderó la imagen. Esto activará una actualización del mensaje en el cliente.

Implementa la función

La función solo estará activa después de que la implementes. En la línea de comandos, ejecuta firebase deploy --only functions:

firebase deploy --only functions

Este es el resultado que debería ver en la consola:

i  deploying functions
i  functions: ensuring necessary APIs are enabled...
  functions: all necessary APIs are enabled
i  functions: preparing functions directory for uploading...
i  functions: packaged functions (X.XX KB) for uploading
  functions: functions folder uploaded successfully
i  starting release process (may take several minutes)...
i  functions: updating function addWelcomeMessages...
i  functions: creating function blurOffensiveImages...
  functions[addWelcomeMessages]: Successful update operation.
  functions[blurOffensiveImages]: Successful create operation.
  functions: all functions deployed successfully!

  Deploy complete!

Project Console: https://console.firebase.google.com/project/friendlychat-1234/overview

Prueba la función

Cuando la función se haya implementado correctamente, siga estos pasos:

  1. Abre la app en tu navegador con la URL de Hosting (con el formato https://<project-id>.firebaseapp.com).
  2. Una vez que accedas a la app, sube una imagen: 4db9fdab56703e4a.png
  3. Elige la mejor imagen ofensiva para subir (o puedes usar la de este zombi que come carne humana). Después de un momento, deberías ver que tu publicación se actualiza con una versión desenfocada de la imagen: 83dd904fbaf97d2b.png

10. Notificaciones de mensajes nuevos

En esta sección, agregarás una función de Cloud Functions que envíe notificaciones a los participantes del chat cuando se publique un mensaje nuevo.

Con Firebase Cloud Messaging (FCM), puedes enviar notificaciones de forma confiable a los usuarios en todas las plataformas. Para enviarle una notificación a un usuario, necesitas su token de dispositivo de FCM. La aplicación web de chat que estamos usando ya recopila tokens de dispositivo de los usuarios cuando estos abren la aplicación por primera vez en un nuevo navegador o dispositivo. Estos tokens se almacenan en Cloud Firestore en la colección fcmTokens.

Si quieres aprender a obtener tokens de dispositivos de FCM en una app web, puedes realizar el Codelab de Firebase Web.

Enviar notificaciones

Para detectar cuándo se publican mensajes nuevos, usarás el activador functions.firestore.document().onCreate de Cloud Functions, que ejecuta tu código cuando se crea un objeto nuevo en una determinada ruta de Cloud Firestore. Agrega la función sendNotifications a tu archivo index.js:

index.js

// Sends a notifications to all users when a new message is posted.
exports.sendNotifications = functions.firestore.document('messages/{messageId}').onCreate(
  async (snapshot) => {
    // Notification details.
    const text = snapshot.data().text;
    const payload = {
      notification: {
        title: `${snapshot.data().name} posted ${text ? 'a message' : 'an image'}`,
        body: text ? (text.length <= 100 ? text : text.substring(0, 97) + '...') : '',
        icon: snapshot.data().profilePicUrl || '/images/profile_placeholder.png',
        click_action: `https://${process.env.GCLOUD_PROJECT}.firebaseapp.com`,
      }
    };

    // Get the list of device tokens.
    const allTokens = await admin.firestore().collection('fcmTokens').get();
    const tokens = [];
    allTokens.forEach((tokenDoc) => {
      tokens.push(tokenDoc.id);
    });

    if (tokens.length > 0) {
      // Send notifications to all tokens.
      const response = await admin.messaging().sendToDevice(tokens, payload);
      await cleanupTokens(response, tokens);
      functions.logger.log('Notifications have been sent and tokens cleaned up.');
    }
  });

En la función anterior, recopilamos los tokens de dispositivo de todos los usuarios de la base de datos de Cloud Firestore y enviamos una notificación a cada uno de ellos con la función admin.messaging().sendToDevice.

Limpia los tokens

Por último, queremos quitar los tokens que ya no son válidos. Esto sucede cuando el navegador o el dispositivo ya no usan el token que alguna vez obtuvimos del usuario. Por ejemplo, esto sucede si el usuario revocó el permiso de notificaciones para la sesión del navegador. Para ello, agrega la siguiente función cleanupTokens en tu archivo index.js:

index.js

// Cleans up the tokens that are no longer valid.
function cleanupTokens(response, tokens) {
 // For each notification we check if there was an error.
 const tokensDelete = [];
 response.results.forEach((result, index) => {
   const error = result.error;
   if (error) {
     functions.logger.error('Failure sending notification to', tokens[index], error);
     // Cleanup the tokens that are not registered anymore.
     if (error.code === 'messaging/invalid-registration-token' ||
         error.code === 'messaging/registration-token-not-registered') {
       const deleteTask = admin.firestore().collection('fcmTokens').doc(tokens[index]).delete();
       tokensDelete.push(deleteTask);
     }
   }
 });
 return Promise.all(tokensDelete);
}

Implementa la función

La función solo estará activa después de que la implementes. Para ello, ejecuta este comando en la línea de comandos:

firebase deploy --only functions

Este es el resultado que debería ver en la consola:

i  deploying functions
i  functions: ensuring necessary APIs are enabled...
  functions: all necessary APIs are enabled
i  functions: preparing functions directory for uploading...
i  functions: packaged functions (X.XX KB) for uploading
  functions: functions folder uploaded successfully
i  starting release process (may take several minutes)...
i  functions: updating function addWelcomeMessages...
i  functions: updating function blurOffensiveImages...
i  functions: creating function sendNotifications...
  functions[addWelcomeMessages]: Successful update operation.
  functions[blurOffensiveImages]: Successful updating operation.
  functions[sendNotifications]: Successful create operation.
  functions: all functions deployed successfully!

  Deploy complete!

Project Console: https://console.firebase.google.com/project/friendlychat-1234/overview

Prueba la función

  1. Una vez que la función se haya implementado correctamente, abre la app en tu navegador con la URL de Hosting (con el formato https://<project-id>.firebaseapp.com).
  2. Si accedes a la app por primera vez, asegúrate de permitir las notificaciones cuando se te solicite: 8b9d0c66dc36153d.png
  3. Cierra la pestaña de la app de chat o muestra una pestaña diferente: Las notificaciones solo aparecen si la app está en segundo plano. Si quieres saber cómo recibir mensajes mientras la app está en primer plano, consulta nuestra documentación.
  4. Con otro navegador (o una ventana de incógnito), accede a la aplicación y publica un mensaje. Deberías ver que se muestra una notificación en la primera sesión del navegador: 45282ab12b28b926.png

11. ¡Felicitaciones!

Utilizó el SDK de Firebase para Cloud Functions y agregó componentes del lado del servidor a una aplicación de chat.

Temas abordados

  • Cómo crear funciones de Cloud Functions con el SDK de Firebase para Cloud Functions
  • Cómo activar funciones de Cloud Functions basadas en eventos de Auth, Cloud Storage y Cloud Firestore
  • Cómo agregar compatibilidad con Firebase Cloud Messaging a su aplicación web
  • Implementar Cloud Functions con Firebase CLI

Próximos pasos

Más información