Blog dedicado a la programación y a la informática en general

Ir al contenido | Ir al menú | Ir a las búsquedas

Firebase Cloud Messaging: Notificaciones en Android

Muchas veces tenemos que añadir un sistema de notificaciones en nuestra aplicación Android. Google proporciona un sistema muy completo para esto, en los últimos tiempos han cambiado un par de veces, por eso, con la última versión a día de hoy voy a recopilar lo que hace falta para implementar las notificaciones push con Firebase Cloud Messaging.

entradaFCM.png

Lo primero de todo es crear un proyecto en la consola de Firebase, para ello nos vamos a https://console.firebase.google.com/ e iniciamos sesión con nuestra cuenta de Google, una vez hayamos accedido pulsamos en "Añadir proyecto".

fcm1_nuevo_proyecto.png

Nos aparecerá la siguiente pantalla donde tendremos que introducir el nombre de nuestro proyecto y seleccionar nuestro país o región.

fcm1_nuevo_proyecto_2.png

Ahora pulsamos en "Añadir Firebase a tu proyecto Android" e introduciremos el nombre del paquete de la aplicación, un nombre (opcional) y el certificado de firma SHA1. Este certificado de firma lo puedes obtener siguiendo las instrucciones de este post.

fcm2_registrar_app.png

Cuando ya tengamos todo completo pulsaremos en "REGISTRAR LA APLICACIÓN", esto generará un fichero de configuración para Firebase que tendremos que descargar y habrá que añadirlo al proyecto de Android. Pulsamos en “Descargar google-services.json”y lo ponemos en la carpeta de la aplicación del proyecto, por ejemplo, dentro de "proyecto\app\".

Ahora añadiremos las librerías de Firebase a nuestro proyecto Android: En el build.gradle de proyecto añadiremos:

buildscript {
  dependencies {
    classpath 'com.google.gms:google-services:3.1.0'
  }
}

En el build.gradle de aplicación añadiremos:

dependencies {
    ...
    compile 'com.google.firebase:firebase-messaging:11.0.4'
}
// añadir al final del fichero
apply plugin: 'com.google.gms.google-services'

Sincronizamos los cambios de estos dos ficheros y compilamos.

Nota: La versión de los componentes variarán con el tiempo, puedes ver cómo actualizarlas aquí.

Implementación de los servicios de Firebase para notificaciones

Ahora necesitamos declarar dos servicios, uno que extienda de FirebaseMessagingService para poder recibir notificaciones en segundo plano y otro que extienda de FirebaseInstanceIdService para gestionar los token de registro en el servicio de notificaciones. Declaramos los dos servicios dentro del tag <application> de nuestro fichero manifest añadiendo:

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

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

Como verás, en este caso las clases las he llamado FCMMessagingService y FCMListenerService.

FCMMessagingService

Como ya he comentado antes, este servicio se encarga de recibir las notificaciones en segundo plano, la siguiente implementación obtendrá datos de esa notificación y la mostrará en la barra de notificaciones. Creamos el fichero FCMMessagingService.java en el paquete principal con el siguiente contenido:

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.NotificationCompat;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
import org.json.JSONObject;
import java.util.Map;
import java.util.Random;

public class FCMMessagingService extends FirebaseMessagingService {

    private static int getNotificationIcon() {
        boolean useWhiteIcon = (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP);
        return useWhiteIcon ? R.mipmap.icon_silhouette : R.mipmap.ic_launcher;
    }

    @Override
    public void onMessageReceived(RemoteMessage message) {
        if (message.getNotification() != null) {
            String mensaje = message.getNotification().getBody();
            String title = message.getNotification().getTitle() != null ? message.getNotification().getTitle() : getString(R.string.app_name);

            NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);

            NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getApplicationContext())
                    .setSmallIcon(getNotificationIcon()).setContentTitle(title)
                    .setStyle(new NotificationCompat.BigTextStyle().bigText(mensaje)).setContentText(mensaje);

            Intent notificationIntent = new Intent(getApplicationContext(), ListadoTrabajosActivity_.class);
            notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
            PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent,
                    PendingIntent.FLAG_UPDATE_CURRENT);
            mBuilder.setContentIntent(contentIntent);

            Notification notification = mBuilder.build();
            notification.flags |= Notification.FLAG_AUTO_CANCEL;
            notification.flags |= Notification.DEFAULT_SOUND;
            notification.defaults |= Notification.DEFAULT_SOUND;
            notification.defaults |= Notification.DEFAULT_VIBRATE;

            Random randomGenerator = new Random();
            int randomInt = 0;
            for (int idx = 1; idx <= 10; ++idx) {
                randomInt = randomGenerator.nextInt(100);
            }

            notificationManager.notify(randomInt, notification);
        }
    }
}

En la primera función se elige entre icono de silueta o el icono de la aplicación ya que a partir de Android Lollipop el icono de la notificación debe ser un icono de silueta, este icono lo puedes generar desde aquí: https://romannurik.github.io/AndroidAssetStudio/icons-notification.html

FCMListenerService

Esta clase será la encargada de recibir el token (esto ocurrirá al iniciar la aplicación). Este token tendremos que enviarlo a nuestro servicio web y, en su caso, almacenarlo asociado al usuario para enviarle notificaciones personalizadas.

import android.util.Log;
import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.FirebaseInstanceIdService;

public class FCMListenerService extends FirebaseInstanceIdService {

    public static String getToken() {
        return FirebaseInstanceId.getInstance().getToken();
    }

    public void onTokenRefresh() {
        //Enviar token al servidor para almacenarlo
        Log.d("PRUEBA", "Token: " + getToken());
    }
}

Si todo va bien, al iniciar la aplicación veremos en el Monitor de Android algo parecido a esto

Token: Av3_dZi4yuw:APA91bGXtDv36eMEgAp4f3Ft7QAJ1nCMYTiiMrKwfh7MzOeNrwbabxuQ57pTzqbLF5Oam4CYXWIHEPqKv35qm3qK-8k8Cn-JegNQExhwoQfGYX_GMxJCGcORPSKymeezRBscIgoqLNag

Este será el token correspondiente a esta instalación de la aplicación para este dispositivo. Si vuelves a ejecutar la aplicación no aparecerá, ya que este método solo se ejecuta cuando hay cambios en el token, podrás obtener este valor en cualquier momento mediante FCMListenerService.getToken().

Envío de notificaciones

Para enviar notificaciones podemos probar mediante la consola de Firebase, esta utilidad se encuentra en el menú de la izquierda, apartado AMPLIACIÓN > Notifications

fcm4_notifications_firebase.png

Aparecerá una pantalla donde podremos escribir nuestro mensaje, seleccionaremos "Un único dispositivo", pegamos nuestro token en el campo correspondiente y pulsamos "Enviar mensaje".

fcm5_envio_push.png

Al enviar veremos en la aplicación el mensaje escrito:

fcm6_push_msg.png

Envío manual de notificaciones

Si queremos enviar las notificaciones mediante nuestros programas necesitaremos la APIKey de nuestra aplicación y el token del dispositivo que ya hemos obtenido en la aplicación Android.

La APIKey la podemos ver en la consola de Firebase accediendo a la configuración de nuestro proyecto, apartado "Mensajería en la nube":

fcm7_apikey.png

La APIKey de nuestra aplicación que podremos usar serán cualquiera de las dos que he marcado en la imagen y bastaría con ejecutar el siguiente código PHP para recibir la notificación (cambiando el token y la clave del servidor):

<?php
	//$tokenDispositivo = 'TOKEN_ANDROID'; // Usar para un único dispositivo
	$tokens = ['TOKEN_ANDROID_1',  'TOKEN_ANDROID_2'];

	$payloadNotificacion = [
		'body' => 'Prueba de mensaje',
		'title'	=> 'Título',
		'sound' => 'default',
		'vibrate' => 'true'
	];

	$campos = [
		//'to' => $tokenDispositivo, // Usar para un único dispositivo
		'registration_ids' => $tokens, // Usar para varios destinatarios
		'notification' => $payloadNotificacion
	];

	$cabeceras = [
		'Authorization: key='.'CLAVE_DEL_SERVIDOR',
		'Content-Type: application/json',
	];

	$ch = curl_init();
	curl_setopt($ch, CURLOPT_URL, 'https://fcm.googleapis.com/fcm/send');
	curl_setopt($ch, CURLOPT_POST, true);
	curl_setopt($ch, CURLOPT_HTTPHEADER, $cabeceras);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
	curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($campos));
	$resultado = curl_exec($ch);
	curl_close($ch);

	echo $resultado;
?>

Como verás en el código se puede enviar la notificación a un único dispositivo o una misma notificación a varios dispositivos.

Esto es todo, ya podéis enviar notificaciones sin parar!

Saludos!

Comentarios

1. El Viernes, 1 de Junio de 2018, 00:33 por Cesar

Que tal buenas tardes, excelente aporte amigo, disculpa tengo un problema al querer recibir una notificación cuando la app no esta en primer plano, en android 5, me podrias orientar me manda el error Couldn't create icon: StatusBarIcon ojala puedas ayudarme. Saludos

2. El Viernes, 1 de Junio de 2018, 09:23 por amunoz

Hola César, según he visto por Internet puede ser que estés usando un xml (drawable) como icono para las notificaciones y Android 5 no lo soporta.

Deberías usar un icono de silueta en png, intenta generar uno con este generador a ver si te funciona: https://romannurik.github.io/Androi...

Saludos!

3. El Lunes, 4 de Junio de 2018, 18:46 por Cesar

Muchas gracias amunoz me ayudo mucho la ayuda y la explicación del problema que me estaba pasando, ya funciona correctamente.

4. El Jueves, 5 de Julio de 2018, 01:35 por Luis

Hola que tal oye una pregunta, no se si me puedas ayudar al recibir notificaciones cuando el app esta en segundo plano me llega la notificacion pero en error y al momento de abrirla no hace la accion que le programe. no se puedas asesorar con eso es con un android oreo. bueno gracias

Añadir un comentario

El código HTML se muestra como texto y las direcciones web se transforman automáticamente.

Discusiones sobre el mismo tema

URL de retroenlace : https://www.dosmweb.com/blog/index.php?trackback/20

Fuente de los comentarios de esta entrada