Notificaciones con Firebase

8 minuto(s) de lectura

Toda la información oficial de Firebase la pueden encontrar aquí.

El código completo para este Post lo pueden encontrar en Github

Introducción

Una característica muy importante en las apps móviles es mantener a los usuarios involucrados con tu aplicación. También hay ciertas aplicaciones que necesitan avisar a los usuarios que suceció algún evento (un mensaje de texto o un correo electrónico fueron recibidos). Otro escenario es cuando ha habido algún cambio en los datos del usuario en el servidor y la aplicación requiere ser sincronizada nuevamente. Para todos estos escenarios se pueden utilizar notificaciones.

Firebase nos permite enviar notificaciones a dispositivos individuales o a un grupo de dispositivos suscritos a algún tema en particular. En este Post aprenderemos cómo configurar nuestra aplicación en Android para recibir notificaciones y cómo podemos enviarlas desde la consola de Firebase o lo que debemos realizar para enviarla desde un servidor.

Instalación

Para poder recibir notificaciones utilizando Firebase, necesitamos configurar nuestra app como se muestra en este Post. Además, necesitamos agregar la siguiente dependencia en el archivo build.gradle de la aplicación.

compile 'com.google.firebase:firebase-messaging:10.0.1'

Notificaciones en segundo plano para un usuario específico

Se pueden mandar notificaciones de dos maneras: segundo plano y primer plano. También se pueden mandar mensajes a usuarios específicos con el token y a grupos de usuarios. Vamos a comenzar enviando una notificación a un dispositivo en específico cuando la aplicación está en segundo plano.

Cada dispositivo tiene un token de registro. Este token de registro es el que identifica a cada usuario de tu aplicación y además es el que se deberá agregar en la consola de Firebase al momento de enviar la notificación. Este token se debería de guardar en una base de datos en la nube, para que desde tu servicio puedas enviar notificaciones a un usuario en específico.

Firebase nos proporciona un servicio, el FirebaseInstanceIdService, del cual debemos heredar para poder obtener el token al iniciar la app. También nos permite obtener el token nuevamente cuando ésta cambia (en caso de que el usuario desinstale e instale la app o de que borre los datos de la misma).

Vamos a crear el servicio ServicioDeToken que herede de FirebaseInstanceIdService. Dentro del servicio, necesitamos sobreescribir el método onTokenRefresh(). Este método se ejecuta cuando el token tiene algún cambio en su estado.

Dentro de este método podemos obtener la instancia de FirebaseInstanceId y de esta instancia podemos obtener el token mediante el método getToken(). Con esta instancia también podemos eliminar el token, o también obtener la fecha de su creación. Una vez obtenido el token, podrán enviar esta información a su servicio web.

@Override
public void onTokenRefresh() {
    FirebaseInstanceId instanciaIdFirebase = FirebaseInstanceId.getInstance();
    String tokenDeEsteDispositivo = instanciaIdFirebase.getToken();

    Log.d(TAG, "Token de este dispositivo: " + tokenDeEsteDispositivo);
    Log.d(TAG, "Creada el " + new Date(instanciaIdFirebase.getCreationTime()));

    // Enviar token a su servicio web.
}

Necesitamos registrar nuestro servicio en el manifest de la app. Hay que agregarle un intent-filter con acción INSTANCE_ID_EVENT para que se ejecute nuestro servicio.

<service
    android:name=".ServicioDeToken">
    <intent-filter>
        <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
    </intent-filter>
</service>

Ejecutamos nuestra aplicación y podemos ver en la consola el token y la fecha de creación.

Token del usuario para enviar notificaciones.

Esta configuración es suficiente para enviar notificaciones desde la consola de Firebase a un dispositivo en específico, cuando la aplicación está en segundo plano.

Es momento de enviar la notificación. En la consola de Firebase hay que ir a la sección de Notificaciones y seleccionar Enviar Tu Primer Mensaje.

Crear el primer mensaje para enviar.

Al seleccionar el botón de Enviar Tu Primer Mensaje, nos abre la consola para redactar el mensaje. Vamos a llenar los campos con el mensaje a enviar, seleccionaremos la opción para enviar ahora y por último vamos a seleccionar la opción de un único dispositivo. Al hacer esto, nos pide el Token de Registro que obtuvimos previamente. Una vez que agreguemos el token, podemos enviar el mensaje. Asegúrense de que la app está corriendo en segundo plano.

Llenando los datos para enviar el mensaje.

Pueden agregar información extra en la sección Opciones avanzadas. En la siguiente sección del Post veremos cómo utilizar esta información extra.

Datos extra en tu mensaje.

En el dispositivo vemos que recibimos la notificación.

Notificación recibida en segundo plano.

Al dar clic sobre la notificación, Firebase está configurado para abrir nuestra aplicación.

Notificaciones en Primer Plano para un usuario específico

Para poder manejar las notificaciones en primer plano (cuando el usuario está interactuando con la app) necesitamos agregar un servicio que herede de FirebaseMessagingService.

Debemos registrar el servicio en nuestro Manifest. Necesitamos agregar el intent-filter de MESSAGING_EVENT para que se ejecute cuando recibamos una notificación.

<service
    android:name=".ServicioDeMensajes">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT"/>
    </intent-filter>
</service>

De igual manera podemos agregar un ícono y un color por default para nuestras notificaciones.

<meta-data
    android:name="com.google.firebase.messaging.default_notification_icon"
    android:resource="@android:drawable/ic_dialog_info" />

<meta-data
    android:name="com.google.firebase.messaging.default_notification_color"
    android:resource="@color/colorAccent" />

En nuestro servicio ServicioDeMensajes debemos sobreescribir el método onMessageReceived(), que es el método que se ejecuta cuando se recibe una notificación. También en ese método recibimos un objeto RemoteMessage el cual tiene toda la información que se envió con la notificación.

public class ServicioDeMensajes extends FirebaseMessagingService {

    @Override
    public void onMessageReceived(RemoteMessage mensajeRemoto) {
        enviarNotificacion(mensajeRemoto);
    }
}

En este método, podemos procesar la información que recibimos. Podemos enviar distintos tipos de mensajes, unos que le pidan a la aplicación hacer algo (sincronizar alguna información) y que no necesite de ninguna notificación gráfica o interacción del usuario.

Un caso de uso muy común es mostrar una notificación en el dispositivo. Aquí es dónde se haría eso y es lo que haremos en este ejemplo.

Podemos obtener los datos extras que enviamos en nuestra notificación con mensajeRemoto.getData(). En este ejemplo agregamos cada valor al intent para mostrarlo posteriormente en la actividad principal. Para obtener la información de la notificación tenemos el método mensajeRemoto.getNotification(). Con este método podemos obtener el título y el cuerpo de la notificación, si fueron enviados.

El método enviarNotifiacion() quedaría de la siguiente manera.

private void enviarNotificacion(RemoteMessage mensajeRemoto) {

    Intent intent = new Intent(this, MainActivity.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

    if (mensajeRemoto.getData().size() > 0) {
        for (String llave : mensajeRemoto.getData().keySet()) {
            intent.putExtra(llave, mensajeRemoto.getData().get(llave));
        }
    }

    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);

    Uri uriDefaultDeSonido = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
    NotificationCompat.Builder builderDeNotificacion = new NotificationCompat.Builder(this)
            .setSmallIcon(android.R.drawable.ic_dialog_info)
            .setContentTitle(mensajeRemoto.getNotification().getTitle()) /* getNotification() nos da la información del título y el cuerpo que se recibió. */
            .setContentText(mensajeRemoto.getNotification().getBody())
            .setAutoCancel(true)
            .setSound(uriDefaultDeSonido)
            .setContentIntent(pendingIntent);

    NotificationManager manejadorDeNotificaciones = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    manejadorDeNotificaciones.notify(0 /* ID de la notificación */, builderDeNotificacion.build());
}

Por último, en la actividad principal, obtenemos los extras y creamos una cadena con cada llave y valor y lo mostramos como Toast.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if (getIntent().getExtras() != null) {
        StringBuilder datosRecibidos = new StringBuilder();
        for (String llave : getIntent().getExtras().keySet()) {
            datosRecibidos.append(llave);
            datosRecibidos.append(":");
            datosRecibidos.append(getIntent().getExtras().get(llave));
            datosRecibidos.append(",");
        }
        Toast.makeText(this, datosRecibidos.toString(), Toast.LENGTH_SHORT).show();
    }
}

Enviar Notificaciones a un Tema

Firebase nos proporciona la opción de suscribir a usuarios a algún tema en particular, y que estos usuarios reciban notificaciones enviadas específicamente del tema seleccionado.

Para este ejemplo, vamos a crear tres botones con los cuales podremos suscribirnos a un tema en específico.

<Button
    android:id="@+id/botonNoticias"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/suscribirse_a_noticias" />

<Button
    android:id="@+id/botonDeportes"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/suscribirse_a_deportes" />

<Button
    android:id="@+id/botonEntretenimiento"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/suscribirse_a_entretenimiento" />

En nuestra actividad, agregaremos un listener a cada botón para suscribirnos al tema correspondiente. Para inscribirse a un tema obtenemos la instancia de FirebaseMessaging y utilizamos el método de subscribeToTopic(). En el método inicializarVistas() pueden encontrar este código.

private void inicializarVistas() {
    Button botonNoticias = (Button) findViewById(R.id.botonNoticias);
    Button botonDeportes = (Button) findViewById(R.id.botonDeportes);
    Button botonEntretenimiento = (Button) findViewById(R.id.botonEntretenimiento);

    botonNoticias.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            FirebaseMessaging.getInstance().subscribeToTopic("noticias");
        }
    });

    botonDeportes.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            FirebaseMessaging.getInstance().subscribeToTopic("deportes");
        }
    });

    botonEntretenimiento.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            FirebaseMessaging.getInstance().subscribeToTopic("entretenimiento");
        }
    });
}

De igual manera, agregaremos tres botones más para cancelar la suscripción a cada tema.

<Button
    android:id="@+id/botonCancelarNoticias"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/cancelar_suscripci_n_a_noticias" />

<Button
    android:id="@+id/botonCancelarDeportes"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/cancelar_suscripci_n_a_deportes" />

<Button
    android:id="@+id/botonCancelarEntretenimiento"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/cancelar_suscripci_n_a_entretenimiento" />

El código que debemos de utilizar para cancelar la suscripción es

FirebaseMessaging.getInstance().unsubscribeFromTopic("noticias");

Una vez que presionemos alguno de los botones para suscribirnos, puede tardar hasta 24 horas en aparecer ese tema en la consola de Firebase.

En la consola, entramos a la opción de Notificaciones y crear un nuevo mensaje. Seleccionamos la opción de Tema y podemos comenzar a mandar notificaciones a los usuarios suscritos a ese tema.

Enviar mensaje a un tema.

En nuestro dispositivo recibimos la notificación.

Mensaje recibido al tema noticias.

Si decidimos cancelar la suscripción a un tema y tratamos de enviar la notificación nuevamente, no recibiremos nada.

Enviar Notificaciones a un dispositivo desde un Servidor

Además de la consola de Notificaciones de Firebase, podemos tener la necesidad de enviar notificaciones desde nuestro servidor. Como la implementación es muy específica dependiendo del lenguaje de programación que utilice el servicio, vamos a utilizar una aplicación llamda Postman para ver cómo se debe de crear la petición para enviar las notificaciones. Esta aplicación la pueden instalar en Google Chrome en este link.

Necesitamos crear una petición POST a la siguiente URL: https://fcm.googleapis.com/fcm/send

Liga para enviar POST para notificaciones.

Posteriormente necesitamos agregar dos encabezados. El encabezado Content-Type tendrá como valor application/json. Para el encabezado Authorization necesitamos ir a la consola de Firebase para obtener su valor. En la consola al entrar en su proyecto, seleccionamos el engrane de opciones y vamos a la sección de Configuración del Proyecto.

Configuración del proyecto.

Una vez en Configuración del Proyecto, seleccionamos la pestaña de Mensajería en la Nube. Ahí podemos encontrar la Clave de Servidor.

Clave de Servidor.

Copiamos ese valor y de regerso en Postman, agregamos el encabezado Authorization con el valor de key=<la Clave de Servidor>.

Encabezados.

Por último, agregaremos el cuerpo del mensaje en la sección de Body. Necesitamos agregar un JSON con la siguiente información:

  • to: es el Token Id del dispositivo
  • notification: es el objeto que deberá tener los atributos title, que será el título de nuestra notificación, y el atributo body, que será el cuerpo de nuestra notificación.
  • data: este objeto opcional tendrá atributos u objetos que podremos obtener dentro de nuestra app.

En Postman seleccionaremos la opción de Body y la opción de raw y pegaremos nuestro JSON:

JSON a enviar.

Una vez presionamos el botón Send nuestra notificación será enviada. Obtendremos la siguiente respuesta de Firebase Cloud Messaging:

Respuesta recibida al enviar la notificación.

En nuestro dispositivo recibiremos la notificación.

Notificación recibida.

Con esta información pueden desarrollar código en su lenguaje de programación web o framework preferido que genere esta petición POST.

Para enviar notificaciones a un tema, solamente debemos de asignar en el valor del atributo to el tema al que queramos enviarla precedido de la cadena /topics/.

Enviar notificaciones a temas desde Postman.

Pueden utilizar esta opción para probar las notificaciones a temas antes de que el tema aparezca en la consola de Firebase.

Deja un comentario