Notificaciones con Firebase
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.

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.

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.

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.

En el dispositivo vemos que recibimos la notificación.

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.

En nuestro dispositivo recibimos la notificación.

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

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.

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

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

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:

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

En nuestro dispositivo recibiremos la notificación.

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/.

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