Envoi et utilisation des Notifications Push sous Android

Durant la vie d’une application mobile, il arrive que nous ayons besoin de prévenir l’utilisateur d’un changement. Ce dernier peut concerner une mise à jour de l’application, une nouvelle extension ou des événements concernant l’utilisateur. Pour répondre à ce besoin, il y a le système de notifications.

Dans cet article nous allons voir les mécanismes d’envoi et de traitement des notifications pour le système Android. Pour ceux qui seraient intéressés par les notifications push dans le monde Apple, sachez que ce sera l’objet d’un autre article.

Pour utiliser les notifications dans un projet Android il faut lui ajouter les APIs GCM (Google Cloud Messaging).

Présentation de GCM

“Google Cloud Messaging for Android” est un service de Google pemettant l’envoi de notifications Push à des terminaux. Dans le monde Google, on distingue la “notification Push” de la “notification Android” qui, elle, s’affichera dans la barre des notifications. Pour utiliser GCM, il faut l’ajouter au projet dans le “Google Developer Console”. Nous verrons comment par la suite.

Cette API permet d’envoyer, au format JSON, un message d’une taille maximale de 4ko. Ce message va contenir des paramètres propres à la notification, comme sa durée de vie, le ou les destinataires, mais également des informations à traiter par le terminal.

GCM utilise deux protocoles : GCM HTTP et CCS (XMPP). Il est possible d’utiliser les deux en même temps. Les différences entre ces protocoles sont :

  1. La direction des messages :- GCM HTTP est unidirectionnel “cloud-to-device” (downstream). C’est à dire que l’application serveur envoie un message à GCM pour notifier un ou plusieurs terminaux puis GCM envoie cette notification aux terminaux.
  • CCS est multidirectionnel “device-to-cloud, cloud-to-device” (upstream, downstream). L’application server utilise une connexion persistente XMPP lui permettant d’envoyer et de recevoir des messages aux terminaux.
  1. La synchronisation :- GCM HTTP est synchrone. Tant que la réponse à la requête HTTP POST n’a pas été reçue, l’envoi de la notification suivante est bloqué.
  • CCS est asynchrone.
  1. Le flux JSON :- GCM HTTP envoi le flux JSON de manière classique via une requête HTTP POST.
  • CCS encapsule le flux JSON dans un message XMPP.

Dans le cadre de cet article nous utiliserons GCM HTTP, notre besoin étant simplement de notifier un ou plusieurs terminaux d’un nouveau message pour l’utilisateur. Une des contraintes de GCM est la limite des destinataires du message. Lors d’un appel à GCM pour l’envoi d’un message, le nombre maximal de destinataires est limité à 1000. Si l’on souhaite notifier, 25000 terminaux il faudra faire une boucle sur l’appel.

Principe de fonctionnement

Afin d’expliquer le fonctionnement de la notification Android, basons-nous sur le schéma suivant :

gcm-notification-diagramme

Via l’application Android, le terminal s’enregistre auprès du service “Google Cloud Messaging for Android”. Un numéro unique (registerId ou pushToken) est attribué et retourné au terminal. Ce dernier va ensuite le transmettre à l’application serveur afin qu’il soit sauvegardé. Lorsque l’application server voudra notifier l’utilisateur du terminal, elle enverra un message au GCM avec le “registerId” du terminal destinataire. GCM enverra une notification Push au terminal s’il est online. Dans le cas où le terminal est offline, la notification est stockée par GCM pour être délivrée à la prochaine mise en ligne. Côté terminal, notre application cliente traitera notre “notification Push”. Elle en fera une “notification Android” qui sera transmise à l’utilisateur par la barre des notifications.

Simple non ? Il manque cependant une information dont je n’ai pas encore parlé. C’est le “Project Number” ou “senderId”.

Le principe est le même qu’un envoi de courrier à une société. Si vous voulez que votre courier soit traité par le bon service il faut le préciser. Donc si le “registerId” de notre terminal est l’adresse de la société destinataire, le “Project Number”, ou “senderId”, est le nom du service qui traitera notre notification.

En pratique cela donne quoi ?

Il y a trois étapes pour gérer les notifications sous Android :

  1. Créer un projet dans le “Google Developper Center” pour récupérer le “Project Number” (ou “senderId”). Spécifier pour ce projet l’utilisation du service “Google Cloud Messaging for Android”, et générer l’API Key.
  2. Créer l’application serveur qui va envoyer les notifications.
  3. Gérer la réception et le traitement des notifications dans l’application Android.

Création du projet

Pour cela il vous faut un compte Google et vous rendre à l’adresse : https://cloud.google.com/console. Ensuite il suffit d’effectuer les étapes suivantes :

  1. Création du projet via le bouton “CREATE PROJECT” puis, lors du retour à la page principale, cliquez sur votre projet et vous aurez les “Project Id” et “Project Number”.
  2. Activation du service de notifications en allant dans “APIs & Auth” > “API”. Ajoutez ensuite le service “Google Cloud Messaging for Android”.
  3. Génération de l'”API Key” via le menu “APIs & Auth” > “Credentials”. Cliquez sur le bouton “Create New Key” de “Public API access”. Ensuite, générez une “Server key”. Vous pouvez laisser la zone de saisie des IPs vide, puis cliquez sur “Create”. Vous obtenez alors l'”API Key”.

Création du serveur de notification

Pour utiliser l’API Google Cloud Messaging, il vous faut soit télécharcher gcm-server.jar ici et l’importer dans votre projet. Sinon, vous pouvez le référencer dans votre “pom.xml” avec les informations suivantes :

<repositories>
  <repository>
    <id>gcm-server-repository</id>
    <url>https://github.com/slorber/gcm-server-repository/raw/master/releases/</url>
  </repository>
</repositories>

Nous souhaitons envoyer un message à un terminal donné. Partons du principe que nous avons un objet “MessageAEnvoyer” ayant pour attributs un identifiant (id), un titre, une date de création (dateMessage) et un texte. Nous allons créer notre message dans un premier temps. Dans notre code nous importons le package “com.google.android.gcm.server.Message“, puis nous créons notre objet :

Message androidMessage = new Message.Builder()
	.timeToLive(5)
	.addData("id", messageAEnvoyer.getId())
	.addData("titre", messageAEnvoyer.getTitre())
	.addData("dateCreation", Long.toString(messageAEnvoyer.getDateMessage().getTime()))
	.addData("texte", messageAEnvoyer.getTexte())
	.build();

N’oubliez pas que le message ne doit pas excéder 4 ko.

Un message à destination d’un terminal peut contenir plusieurs informations :

  • collapse_key : permet de regrouper les messages lorsque le terminal est hors ligne et ainsi de limiter les envois. Prendra pour valeur le nom du groupe (ex. : “New mail”, “Informations”).
  • delay_while_idle : indique que le message ne devra pas être envoyé immédiatement si le terminal est en veille. Lorsqu’il devient actif, c’est le dernier message “collapse_key” qui sera envoyé. Par défaut cette option est à “false”.
  • time_to_live : indique le temps, en secondes, durant lequel le message sera stocké sur le GCM storage. Par défaut la période de stockage est de 4 semaines.
  • restricted_package_name : permet d’envoyer le message uniquement aux terminaux dont le “register ID” est associé au package indiqué.
  • dry_run : permet lors du développement d’effectuer des envois sans réellement envoyer de message. Par défaut cette option est à “false”.
  • data : permet d’ajouter nos informations (payload) au message sous la forme “clé/valeur”. Les valeurs sont forcément de type “String”.

Maintenant que nous avons notre message, il nous suffit de l’envoyer. Pour cela nous allons utiliser une des méthodes de la classe “com.google.android.gcm.server.Sender“. Les méthodes disponibles sont :

  • MulticastResult send(Message message, List registerIds, int retries) : permet d’envoyer une notification à plusieurs terminaux (au plus 1000). Le paramètre “retries” indique le nombre de tentatives en cas d’indisponibilité.
  • Result send(Message message, String registerId, int retries) : permet d’envoyer un message à un terminal défini par son registerId. Le nombre de tentatives en cas d’indisponibilité est là aussi précisé.
  • Result sendNoRetry(Message message, String registerId) : envoie un message à un terminal donné sans tentative si une indisponibilité est détectée.
  • ResultMulticast sendNoRetry(Message message, List registerIds) : envoie un message à une liste de terminaux sans effectuer d’autre tentative en cas d’indisponibilité.

La gestion des cas d’erreurs se fait grâce à la classe “com.google.android.gcm.server.Constants” qui contient les codes des erreurs présentes dans les objets “Result” et “MulticastResult”. Il est ainsi possible de savoir, par exemple, qu’un terminal n’a pas été notifié car l’application a été désinstallée. N’étant plus enregistré comme destinataire valide, il peut être retiré de la liste des contacts.

L’envoi de notre message au GCM à destination d’un terminal, avec trois tentatives, se fera de la manière suivante :

Sender sender = new Sender(apikey) // l'apikey qui a été générée précédemment

Result resultat = sender.send(messageAndroid, regIdTerminal, 3);

Une fois notre message envoyé au GCM, ce dernier l’envoie au terminal. Trois cas sont possibles :

  1. Le terminal est connecté au réseau et actif : la notification est envoyée instantanément.
  2. Le terminal est connecté au réseau mais inactif (mode IDLE) : là, on joue avec les paramètres “delay_while_idle” et “collapse_key“. Si “delay_while_idle” est “false”, le message est délivré instantanément, sinon il est stocké. Dans ce cas, si le message est “collapsé”, si une nouvelle notification arrivait, elle remplacerait la notification stockée. Si le message est “non collapsé”, alors les nouvelles notifications sont stockées avec les anciennes dans la limite de 100 messages. A la réception du 101ème message, la file d’attente est remise à zéro.
  3. Le terminal n’est pas connecté au réseau : les messages sont stockés par GCM et stockés dans la limites de 100 messages en fonction de la présence du “collapse_key“.

Et côté client ?

Côté client, il y a deux choses à faire. La première est la partie permettant au terminal de s’enregistrer auprès du service “Google Cloud Messaging”. La seconde est le traitement de la notification.

Pré-requis à l’application Android

En pré-requis, il faut, dans le SDK Android, avoir :

  1. Google Play Services
  2. Google APIs
  3. Le projet Google Play Services Lib en tant que dépendance Android

Ensuite il faut modifier le manifest de l’application afin d’y ajouter :

  • com.google.android.c2dm.permission.RECEIVE : permet à l’application d’enregistrer et recevoir des messages.
  • android.permission.INTERNET : permet à l’application Android d’envoyer le registerId à l’application server.
  • android.permission.GET_ACCOUNTS : autorise GCM à requérir un compte Google. Cette option est nécessaire uniquement sur les systèmes inférieurs à Android 4.0.4.
  • android.permission.WAKE_LOCK : permet de laisser l’application en veille à la réception d’un message.
  • votreApplicationPackage + “.permission.C2D_MESSAGE” : empêche les autres applications de s’enregistrer pour recevoir les messages de notre application.
  • Un récepteur pour com.google.android.c2dm.intent.RECEIVE. Il devra avoir une permission “com.google.android.c2dm.SEND“, de sorte que seul GCM puisse lui envoyer un message. Si votre application utilise un “IntentService” ce récepteur doit être une instance de “WakefulBroadcastReceiver”.
  • Un “Service” (en général un “IntentService”) auquel le “WakefulBroadcastReceiver” donnera le traitement du message, empêchant ainsi le terminal de se remettre en veille.

Votre “ApplicationManifest.xml” contiendra quelque chose du style :

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"  package="com.ippon.fr.android"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <permission  android:name="com.javapapers.android.permission.C2D_MESSAGE" android:protectionLevel="signature" />

    <uses-permission android:name="com.ippon.fr.android.permission.C2D_MESSAGE" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.VIBRATE" />

    <application ...>
        <receiver
            android:name=".GcmBroadcastReceiver"
            android:permission="com.google.android.c2dm.permission.SEND" >
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
                <category android:name="com.ippon.fr.android" />
            </intent-filter>
        </receiver>
        <service android:name=".GCMNotificationIntentService" />
    </application>
</manifest>

Enregistrement du terminal

Commençons par enregistrer notre terminal auprès du GCM. On récupère une instance de la classe “com.google.android.gms.gcm.GoogleCloudMessaging” puis nous ferons appel à la méthode “register()”. Ce qui nous donne le code suivant :

GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context); // context étant le context de l'activité
String registerId = gcm.register(SENDER_ID);

Le “senderId” ou “project number” est passé en paramètre de la méthode “register()” pour spécifier que le terminal s’enregistre au service GCM de notre projet. On récupère ainsi le “registerId” du terminal qu’il faudra transmettre à application server via un WebService par exemple.

Résumé en deux lignes de code, cela semble simple. Dans la pratique, dans l'”Activity” faisant l’enregistrement du terminal, on vérifie la disponibilité des PlayServices. Si ces derniers sont actifs, alors on cherche à récupérer le “registerId” dans les SharedPreferences de l’application. S’il n’existe pas, l’enregistrement est effectué. Le contrôle de la version de l’application Android serait un plus. Il semblerait que GCM, lors de l’enregistrement du terminal, associe ce dernier à une version de l’application cliente. Du coup, lors d’un changement de version, le “register Id” du terminal ne serait plus valide.

Voici un exemple de code d’Activity et de méthodes permettant de faire l’enregistrement auprès du GCM :

public class GCMRegisterActivity extends Activity {
    GoogleCloudMessaging gcm;
    Context context;
    String regId;
    public static final String REG_ID = "regId";
    private static final String APP_VERSION = "appVersion";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_register);
        context = getApplicationContext();

        [...]
        if (TextUtils.isEmpty(regId)) {
            // Récupération du registerId du terminal ou enregistrement de ce dernier
            regId = registerGCM();
            Log.d("GCM RegId: " + regId);
        } else {
            Toast.makeText(getApplicationContext(), "Déjà enregistré sur le GCM Server!", Toast.LENGTH_LONG).show();
        }
        [...]
    }

    /**************
     * Cette méthode récupère le registerId dans les SharedPreferences via
     * la méthode getRegistrationId(context). 
     * S'il n'existe pas alors on enregistre le terminal via
     * la méthode registerInBackground()
     */
    public String registerGCM() {
        gcm = GoogleCloudMessaging.getInstance(this);
        regId = getRegistrationId(context);

        if (TextUtils.isEmpty(regId)) {
            registerInBackground();
            Log.d( "registerGCM - enregistrement auprès du GCM server OK - regId: " + regId);
        } else {
            Toast.makeText(getApplicationContext(), "RegId existe déjà. RegId: " + regId, Toast.LENGTH_LONG).show();
        }
        return regId;
    }

    private String getRegistrationId(Context context) {
        final SharedPreferences prefs = getSharedPreferences(
            MainActivity.class.getSimpleName(), Context.MODE_PRIVATE);
            String registrationId = prefs.getString(REG_ID, "");
        if (registrationId.isEmpty()) {
            Log.i(TAG, "registrationId non trouvé.");
            return "";
        }
       // On peut aussi ajouter un contrôle sur la version de l'application.
       // Lors d'un changement de version d'application le register Id du terminal ne sera plus valide.
       // Ainsi, s'il existe un registerId dans les SharedPreferences, mais que la version
       // de l'application a évolué alors on retourne un registrationId="" forçant ainsi
       // l'application à enregistrer de nouveau le terminal.
       return registrationId;
    }

    /**
     * Cette méthode permet l'enregistrement du terminal
     */
    private void registerInBackground() {
        new AsyncTask<Void, Void, String>() {
            @Override
            protected String doInBackground(Void... params) {
                String msg = "";
                try {
                    if (gcm == null) {
                        gcm = GoogleCloudMessaging.getInstance(context);
                    }
                    regId = gcm.register(PROJECT_NUMBER);
                    msg = "Terminal enregistré, register ID=" + regId;
                    // On enregistre le registerId dans les SharedPreferences
                    storeRegistrationId(context, regId);
                } catch (IOException ex) {
                    msg = "Error :" + ex.getMessage();
                    Log.d("Error: " + msg);
                }
                return msg;
            }
        }.execute(null, null, null);
    }
 }

Notre terminal étant enregistré, nous allons nous occuper du traitement de la notification. Lorsque l’application server envoie un message à un terminal, ce message n’est pas directement affiché dans la barre de notifications. Notre application Android doit récupérer le message, le traiter et générer une notification (dans l’univers Google, c’est une “Intent”) qui apparaîtra alors dans la barre de notification. Le message envoyé par l’application server est d’abord détecté par “WakefulBroadcastReceiver” qui le fera traiter par notre “IntentService”. Le traitement par l'”IntentService” n’est pas obligatoire et pourrait se faire via le “BroadcastReceiver”. Cependant, l’utilisation de l'”IntentService” s’est généralisée.

Nous allons donc créer une classe “BroadcastReceiver” et une classe “GcmIntentService” qui hériteront des attributs et méthodes des classes “android.support.v4.content.WakefulBroadcastReceiver” et “android.app.IntentService“.

Notre “BroadcastReceiver” :

public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        ComponentName comp = new ComponentName(context.getPackageName(),
                GCMNotificationIntentService.class.getName());
        startWakefulService(context, (intent.setComponent(comp)));
        setResultCode(Activity.RESULT_OK);
    }
}

Notre “GcmIntentService” :

public class GcmIntentService extends IntentService {
    public static final int NOTIFICATION_ID = 1;
    private NotificationManager mNotificationManager;
    NotificationCompat.Builder builder;

    /*
     * Constantes permettant la récupération des informations
     * du message dans les extras de la notification envoyée
     * par le serveur de notification.
     */
    // Récupération de l'identification du message
    static final String MESSAGE_ID = "id";
    // Récupération du nom du message
    static final String MESSAGE_TITRE = "titre";
    // Récupération de la date et heure du message
    static final String MESSAGE_DATE_CREATION = "dateCreation";
    // Récupération du texte du message
    static final String MESSAGE_TEXTE = "texte";

    public GcmIntentService() {
        super("GcmIntentService");
    }
    public static final String TAG = "GCM Demo";

    @Override
    protected void onHandleIntent(Intent intent) {
        Bundle extras = intent.getExtras();
        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
        // Le paramètre intent de la méthode getMessageType() est la notification push
        // reçue par le BroadcastReceiver.
        String messageType = gcm.getMessageType(intent);

        if (!extras.isEmpty()) {
            /*
             * On filtre le message (ou notification) sur son type.
             * On met de côté les messages d'erreur pour nous concentrer sur
             * le message de notre notification.
             */
            if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
                sendNotification("Send error: " + extras.toString());
            } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) {
                sendNotification("Deleted messages on server: " + extras.toString());
            // Si c'est un message "classique".
            } else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
                // Cette boucle représente le travail qui devra être effectué.
                for (int i = 0; i < 5; i++) {
                    Log.i(TAG, "Working... " + (i + 1)
                            + "/5 @ " + SystemClock.elapsedRealtime());
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                    }
                }
                Log.i(TAG, "Completed work @ " + SystemClock.elapsedRealtime());
                // Traite les informations se trouvant dans l'extra de l'intent
                // pour générer une notifiation android que l'on enverra.
                sendMessageNotification(extras);
                Log.i(TAG, "Received: " + extras.toString());
            }
        }
        // On indique à notre broadcastReceiver que nous avons fini le traitement.
        GcmBroadcastReceiver.completeWakefulIntent(intent);
    }

    /**
     * Cette méthode permet de créer une notification à partir
     * d'un message passé en paramètre.
     */
    private void sendNotification(String msg) {
        Log.d(TAG, "Preparing to send notification...: " + msg);
        mNotificationManager = (NotificationManager)
                this.getSystemService(Context.NOTIFICATION_SERVICE);

        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
                new Intent(this, LoggedActivity.class), 0);

        NotificationCompat.Builder mBuilder =
                new NotificationCompat.Builder(this)
        .setSmallIcon(R.drawable.ic_stat_gcm)
        .setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
        .setContentText(msg)
        .setDefaults(Notification.DEFAULT_ALL);

        mBuilder.setContentIntent(contentIntent);
        mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
        Log.d(TAG, "Notification ID = " + NOTIFICATION_ID);
        Log.d(TAG, "Notification sent successfully.");
    }

    /**
     * Cette méthode permet à partir des informations envoyées par le serveur
     * de notification de créer le message et la notification à afficher sur
     * le terminal de l'utilisateur.
     *
     * @param extras les extras envoyés par le serveur de notification
     */
    private void sendMessageNotification(Bundle extras) {
        Log.d(TAG, "Preparing to send notification with message...: " + extras.toString());
        // On crée un objet Message à partir des informations récupérées dans 
        // le flux JSON du message envoyé par l'application server
        Message msg = extractMessageFromExtra(extras);
        // On associe notre notification à une Activity. Ici c'est l'activity
        // qui affiche le message à l'utilisateur
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
                new Intent(this, MessageActivity_.class).putExtra(MessageActivity_.MESSAGE_ARG, msg), 0);

        // On récupère le gestionnaire de notification android
        mNotificationManager = (NotificationManager)
                this.getSystemService(Context.NOTIFICATION_SERVICE);

        NotificationCompat.Builder mBuilder =
                new NotificationCompat.Builder(this)
                        .setSmallIcon(R.drawable.ic_launcher)
                        .setContentTitle("Le nom de l'application par exemple")
                        .setStyle(new NotificationCompat.BigTextStyle().bigText(msg.getTexte()))
                        .setContentText(extras.getString(MESSAGE_TEXTE))
                        .setAutoCancel(true)
                        .setDefaults(Notification.DEFAULT_SOUND);

        mBuilder.setContentIntent(contentIntent);
        mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
        Log.d(TAG, "Notification sent successfully.");
    }

    /**
     * Cette méthode permet d'extraire les informations du message de la notification
     * afin de créer un message.
     * @param extras l'objet contenant les informations du message.
     * @return le message
     */
    private Message extractMessageFromExtra(Bundle extras) {
        Message msg = null;
        if (extras != null) {
            msg = new Message();
            final String id = extras.getString(MESSAGE_ID);
            try {
                msg.setId(Long.parseLong(id));
            } catch (NumberFormatException nfe) {
                Log.e("error : le message n'a pas un identifiant valide. ",nfe.getMessage());
                nfe.printStackTrace();
            }
            final String dateTime = extras.getString(MESSAGE_DATE_CREATION);
            try {
                msg.setDateMessage(new Date(Long.parseLong(dateTime)));
            } catch (NumberFormatException nfe) {
                Log.e("error : le message n'a pas une date valide. ",nfe.getMessage());
                nfe.printStackTrace();
            }
            msg.setTitre(extras.getString(MESSAGE_TITRE));
            msg.setTexte(extras.getString(MESSAGE_TEXTE));
        }
        Log.d(TAG, "extractMessageFromExtra - fin");
        return msg;
    }

}

Lors de l’arrivée d’une “intent”, on récupère ses informations dans un objet “Bundle”. On regarde dans un premier temps si c’est un message d’erreur ou bien un message que nous pouvons traiter et afficher à l’utilisateur.

Dans le cas du message d’erreur, l’utilisateur verra une notification portant le message d’erreur et le contenu du bundle.

Si c’est un message à traiter, nous allons créer notre notification. Dans un premier temps, on extrait les données utiles grace à la méthode “extractMessageFromExtra”. Dans notre exemple, on crée un objet “Message” contenant un identifiant, un titre, une date de création et un texte. Ensuite, on va associer ce message à l’Activity qui aura la charge de l’afficher à l’utilisateur. Ainsi lorsque l’utilisateur tapera la notification, l’Activity sera lancée et affichera le message. Nous récupérons le gestionnaire de notification Android puis on crée la notre. Lors de la création de notre notification via “NotificationCompat.Builder”, il est possible d’ajouter des boutons d’actions, un son, faire vibrer le terminal, modifier l’icône, préciser que la notification doit disparaître après avoir été tapée, etc. Vous aurez la liste détaillée dans l’API Google ici. Je vous conseille aussi cette page qui vous montrera les possibilités d’affichage des notifications. Dans notre exemple nous faisons :

  • setSmallIcon : pour remplacer l’icône,
  • setContentTitle : pour changer le titre de la notification afin que l’utilisateur sache quelle application la reçoit,
  • setStyle(new NotificationCompat.BigTextStyle().bigText(...)) : pour pouvoir afficher un texte de grande longueur,
  • setContentText : pour afficher notre texte,
  • setAutoCancel : pour que la notification disparaisse une fois tapée,
  • setDefaults(Notification.DEFAULT_SOUND) : pour jouer le son par défaut du terminal lors de la réception.

En conclusion

Le système de notification sous Android est assez simple à mettre en place. Il permet facilement d’alerter l’utilisateur de la disponibilité de nouvelles informations. La taille du payload fixée à 4 kilo-octets permet à l’application serveur d’envoyer des données à l’application cliente Android de manière simple. De plus, le fait de différencier la “notification Push” de la “notification Android” (cette dernière étant créée par l’application cliente Android) permet la transmission de données sans en avertir l’utilisateur.