6.2 Sur Android

Pour interagir avec nos objets connectés, il est intéressant de développer des applications mobiles. Les applications Android, qu’on pourra installer sur des tablettes et des téléphones, sont un bon exemple. Pour apprendre les bases du développement Android, voir ce tutoriel vidéo ou ce cours sur OpenClassrooms. Pour ceux qui sont plus à l’aise avec le développement pour iOS et qui voudraient utiliser plutôt un iPhone ou un iPad pour interagir avec leurs objets connectés, OpenClassrooms offre ce tutoriel. Celui-ci regroupe les notions qui sont nécessaires à l’interaction avec un serveur, qui peut être vote objet connecté.

Ici, on couvrira seulement les éléments pertinents pour l’interaction d’Android avec les objets connectés, c’est-à-dire la surveillance et le contrôle de ceux-ci. Nous verrons d’abord comment utiliser les objets Thread, Runnable et Handler pour gérer les interactions avec le réseau lors de l’utilisation active de l’application. Ensuite, nous verrons l’utilisation de la classe WorkManager pour l’exécution en arrière-plan. Celle-ci permet de recevoir des mises à jour de la part de nos objets et d’afficher des notifications. Nous verrons aussi comment échanger des données avec nos objets en utilisant le protocole MQTT.


6.2.1 Thread, Runnable et Handler

Les types d’objets Thread, Runnable et Handler permettent d’exécuter des actions qui prennent un certain temps, comme des échanges réseau, de façon asynchrone. Ceci permet d’éviter que l’application ne gèle, c’est-à-dire qu’elle devienne indisponible aux interactions utilisateurs. On utilise ces types d’objets pour programmer les échanges avec nos objets connectés.

Figure 104 — Code illustrant la création d’un Thread avec Runnable asynchrone

Figure 104 — Code illustrant la création d’un Thread avec Runnable asynchrone

La méthode run() de notre Thread, voir Figure 104, permet d’exécuter du code de façon asynchrone. On pourra y ajouter le code de nos requêtes pour communiquer avec nos objets. Pour les requêtes de contrôle, c’est-à-dire les commandes qu’on veut envoyer aux objets, cette méthode est suffisante.

Vidéo 66 : Programmer des thread avec Android

Par contre, pour les requêtes servant plutôt à obtenir des données de la part d’un objet, on voudra aussi afficher ces données sur l’interface utilisateur. Pour cela, on aura besoin en plus d’un objet Handler, qui peut être initialisé dans notre activité avec la commande Handler handler = new Handler(); et duquel on utilisera la méthode post(), voir Figure 106, dans la méthode run() de notre Thread asynchrone pour commander l’affichage des données reçues à l’aide d’un nouveau Runnable.

Une application crée un thread qui communique avec un handler pour ensuite retourner à l'application principale.

Figure 105 — Communication entre un thread et l’application principale

Figure 106 — Code illustrant l’utilisation d’un Handler

Figure 106 — Code illustrant l’utilisation d’un Handler


6.2.2 WorkManager

Le Thread et le Handler étaient bien utiles pour obtenir et afficher des données provenant d’un objet connecté lorsque l’utilisateur le demande activement. Cependant, si on veut que notre application surveille l’objet connecté en tout temps, que ce soit pour conserver un historique des données ou pour envoyer des notifications à l’utilisateur lorsque les données atteignent certains seuils, nous devons utiliser la classe WorkManager pour programmer nos requêtes qui seront exécutées en arrière-plan.

WorkManager permet d'effectuer des tâches planifiées et des tâches périodiques.

Figure 107 — Utilisation de WorkManager

Pour ce faire, nous devons ajouter la dépendance appropriée à work-runtime, voir Figure 108, créer une classe qui hérite de la classe abstraite Worker et redéfinir la méthode doWork() avec ce qu’on veut exécuter en arrière-plan. Voir Figure 109.

Figure 108 - Ajout de la dépendance à work-runtime

Figure 108 – Ajout de la dépendance à work-runtime

Figure 109 — Code de la classe qui hérite de Worker

Figure 109 — Code de la classe qui hérite de Worker

Ensuite, on doit prévoir son exécution dans notre activité en créant une requête récurrente qu’on fait exécuter par le WorkManager. C’est ici qu’on choisit à quelle fréquence notre code est exécuté en arrière-plan. Voir Figure 110.

Figure 110 — Code pour préparer l’exécution du Worker

Figure 110 — Code pour préparer l’exécution du Worker

Vidéo 67 : Utilisation du WorkManager avec Android


6.2.3 Envoi de requêtes GET et POST avec données JSON

Après avoir appris à créer des Threads et des travaux en arrière-plan, nous sommes maintenant prêts à envoyer des requêtes à notre objet connecté. On verra comment on peut envoyer des requêtes HTTP GET pour obtenir des données de nos objets et des requêtes HTTP POST pour leur envoyer des commandes. Nous allons prendre l’exemple avec des données en format JSON bien que les autres formats soient aussi possibles. Pour les besoins d’apprentissage, on utilise HTTP plutôt que HTTPS. Par contre, en production, il faudrait choisir l’option sécurisée. Dans notre application Android, la première chose à faire est d’aller chercher les permissions pour accéder à Internet et autoriser les requêtes non cryptées. Ça se fait en ajoutant dans le fichier de manifeste la ligne dans la balise et la ligne android:usesCleartextTraffic= »true » dans la balise.

6.2.3.1 Obtention de données à l’aide de requêtes HTTP GET

La Figure 111 illustre le code d’une méthode permettant d’obtenir des données d’un objet dont on connaît l’adresse URL. On peut appeler cette méthode soit dans la méthode run() d’un Thread, soit dans la méthode doWork() d’une classe héritant de Worker selon qu’on veut obtenir les données de notre objet une fois au démarrage de notre application, suite à un évènement de clic sur un bouton ou plutôt périodiquement suivant un intervalle de temps défini.

Figure 111 — Méthode pour obtenir des données à l’aide d’une requête GET

Figure 111 — Méthode pour obtenir des données à l’aide d’une requête GET

Ensuite, on veut traiter les données JSON qu’on a obtenues et les afficher, soit dans une notification si c’était un travail en arrière-plan, soit quelque part sur l’interface utilisateur si c’était dans un Thread. Dans ce dernier cas, on utilisera un Handler. Dans l’exemple illustré à la Figure 112, les données reçues ont le format {« humidite »:734, »temperature »:586} qu’on peut transformer en objet JSON pour en extraire les valeurs de température et d’humidité à afficher.

Figure 112 — Code pour afficher les données JSON reçues à l’aide du Handler

Figure 112 — Code pour afficher les données JSON reçues à l’aide du Handler

Vidéo 68 : Programmer un client Android qui reçoit des données

6.2.3.2 Envoi de commande à l’aide de requêtes HTTP POST

Les requêtes HTTP GET nous permettent d’obtenir des données de nos objets connectés, autrement dit de les surveiller. À l’inverse, voyons maintenant les requêtes HTTP POST qui nous permettent de contrôler nos objets connectés en leur envoyant des commandes. La Figure 113 illustre une méthode pour envoyer une commande JSON dans une requête POST à un serveur ou à un objet connecté dont on connaît l’adresse URL.

Figure 113 — Méthode pour envoyer une commande par une requête POST à un objet connecté

Figure 113 — Méthode pour envoyer une commande par une requête POST à un objet connecté

Dans cet exemple, la réponse du serveur est affichée seulement dans un log, mais on voudrait probablement aussi informer l’utilisateur du succès de l’envoi de la requête. Cette méthode doit être appelée dans un nouveau Thread, voir Figure 114, comme toute interaction avec le réseau. On pourrait y ajouter un Handler pour gérer l’affichage de la réponse, comme on l’a fait pour les requêtes GET.

Figure 114 — Appel de la méthode sendPost dans un thread

Figure 114 — Appel de la méthode sendPost dans un thread

Vidéo 69 : Programmer un client Android qui envoi des commandes


6.2.4 Échange de données avec le protocole MQTT

Sur Android, on doit aussi installer la bibliothèque Paho dans notre projet. Pour ce faire, il faut d’abord ajouter son adresse URL dans le fichier build.gradle de notre projet, voir Figure 115.

Figure 115 — Ajout de la bibliothèque Paho au projet

Figure 115 — Ajout de la bibliothèque Paho au projet

Ensuite, on doit ajouter la bibliothèque à nos dépendances dans le fichier build.gradle du module, voir Figure 116. Puis on doit déclarer la permission d’utiliser internet et le service MQTT dans le fichier Manifest, voir Figure 117.

Figure 116 — Ajout des dépendances à la bibliothèque Paho

Figure 116 — Ajout des dépendances à la bibliothèque Paho

Figure 118 — Code pour créer un client MQTT Android et s’abonner à un sujet

Figure 117 – Déclarations dans le Manifest.

6.2.4.1 S’abonner aux données MQTT

Avec cette bibliothèque, on pourra créer un client MQTT dans notre activité, voir Figure 118, et implémenter les méthodes de rappel nécessaires, voir Figure 119.

Figure 117 - Déclarations dans le Manifest.

Figure 118 — Code pour créer un client MQTT Android et s’abonner à un sujet

Vidéo 70 : Utiliser MQTT sur Android pour s’abonner aux données

6.2.4.2 Publier des messages MQTT

Finalement, si nous voulons utiliser notre application pour publier des messages MQTT auxquels nos objets connectés pourraient s’abonner, nous utilisons la méthode publish() de notre client MQTT, voir Figure 120 où client est un objet de type MqttClient.

Figure 120 — Publication d'un message MQTT avec Android

Figure 120 — Publication d’un message MQTT avec Android

Vidéo 71 : Utiliser MQTT sur Android pour publier des messages


6.2.5 Notifications

Après avoir vu plusieurs façons d’échanger des données avec nos objets, nous voici prêts à utiliser le système de notifications d’Android pour avertir l’utilisateur des données reçues. Celles-ci peuvent être utilisées dans la méthode doWork() d’une classe héritant de Worker pour être envoyées même en arrière-plan quand l’utilisateur n’est pas actif, ou dans la méthode de rappel du client MQTT qui lui aussi continue à recevoir des messages en arrière-plan et où on pourrait les transmettre à l’utilisateur.

Pour envoyer une notification Android, il faut d’abord créer un canal de notifications. Voir la Figure 121 qui présente une méthode pour créer un canal, où CHANNEL_ID est une constante d’identification de type String et context est le contexte de l’application. On peut appeler cette méthode au démarrage de l’application ou avant d’envoyer une notification, voir Figure 122.

Figure 121 — Méthode pour créer un canal de notifications

Figure 121 — Méthode pour créer un canal de notifications

Figure 122 — Code pour créer le canal au démarrage de l’application

Figure 122 — Code pour créer le canal au démarrage de l’application

Ensuite, on peut préparer et afficher notre notification. Voir la Figure 123 qui présente une méthode pour le faire. On doit utiliser le même contexte et le même CHANNEL_ID et on appele cette méthode autant de fois qu’on veut avec des paramètres différents pour afficher plusieurs notifications, ou avec le même id pour en modifier une, voir la Figure 124.

Figure 123 — Méthode pour préparer et afficher une notification

Figure 123 — Méthode pour préparer et afficher une notification

Figure 124 — Appel de la méthode pour afficher une notification

Figure 124 — Appel de la méthode pour afficher une notification

Vidéo 72 : Programmer des notifications avec Android

Vidéo 73 : Intégration de la programmation d’une application de contrôle et de surveillance avec Android


6.2.6 Exercices avec Android