Concevoir une application mobile qui marche en Afrique de l’Ouest
Une application testée sur fibre à Cotonou n’est pas une application qui marche à Parakou, sur un Android de 2019 en 3G intermittente. Voici les techniques concrètes — poids, cache, offline-first, files d’attente — qui font la différence sur le terrain.
Concevoir une application mobile en Afrique de l’Ouest, c’est d’abord accepter que les conditions de développement n’ont aucun rapport avec les conditions d’usage. La recette se passe bien. L’application tourne sur le portable du développeur, connecté en fibre dans un bureau de Cotonou, sur un téléphone de deux ans avec 8 Go de RAM. Tout répond en moins d’une seconde. Trois semaines plus tard, le commercial qui la teste à Parakou n’arrive pas à valider une commande : l’écran de chargement tourne, la connexion passe de 3G à rien, et quand elle revient, le formulaire s’est vidé. Entre les deux démonstrations, pas une ligne de code n’a changé : seules les conditions réelles se sont invitées.
Le problème n’est pas la qualité du code. Il est dans les hypothèses implicites : que le réseau est présent, qu’il est rapide, qu’il ne coupe pas au milieu d’une requête, que le téléphone a de la mémoire, que la batterie tiendra, que le courant reviendra. Aucune de ces hypothèses n’est fiable ici. Cet article liste ce qu’il faut faire à la place — des techniques précises, applicables sur un projet en cours, et le coût réel de chacune.
Le terrain réel : à quoi ressemble votre utilisateur
Avant les solutions, le diagnostic. L’utilisateur type d’une application métier au Bénin, au Togo ou au Burkina n’est pas celui qu’on imagine depuis une maquette.
- Un terminal d’entrée de gamme acheté entre 40 000 et 90 000 FCFA : 2 à 4 Go de RAM, un processeur modeste, un stockage souvent presque plein.
- Une version d’Android ancienne, fréquemment plusieurs générations en retard, avec un navigateur qui ne suit pas toujours les dernières API.
- Un forfait data compté en mégaoctets, rechargé par petites tranches. Une application qui consomme 30 Mo pour afficher un tableau de bord sera désinstallée.
- Un réseau qui ment : le téléphone affiche quatre barres, la requête part et n’aboutit jamais. C’est plus fréquent et plus destructeur que l’absence franche de réseau.
- Des coupures de courant qui interrompent une saisie en cours, éteignent le poste, ou coupent la box du bureau.
- Des utilisateurs peu formés au numérique, pour qui une erreur technique non expliquée signifie « l’application est cassée ».
Concevoir une application mobile pour l’Afrique de l’Ouest commence par un budget de poids
Sur une 3G réellement dégradée, le débit utile tourne autour de 300 à 500 kbit/s avec une latence de plusieurs centaines de millisecondes. Un premier chargement de 2 Mo prend alors entre trente et soixante secondes. Personne n’attend une minute.
Fixez donc un budget de poids dès la conception, et traitez-le comme une contrainte non négociable, au même titre qu’un délai. Des cibles qui tiennent la route :
| Élément | Cible |
|---|---|
| Premier chargement complet d’une application web | moins de 500 Ko compressés |
| Code chargé au démarrage | moins de 150 Ko compressés |
| Image principale d’un écran | moins de 80 Ko |
| Réponse d’API pour une liste paginée | moins de 30 Ko |
| Taille du fichier d’installation Android | moins de 20 Mo |
| Affichage utile sur 3G lente | moins de 5 secondes |
Les leviers pour y arriver sont connus et peu coûteux à mettre en place :
- Servir les images dans un format moderne et compressé, en plusieurs tailles adaptées à la taille réelle de l’écran : on divise couramment le poids par deux à trois par rapport à une photo brute, sans perte visible sur un écran de téléphone.
- Charger les images hors écran seulement quand l’utilisateur y arrive : tous les navigateurs savent le faire nativement depuis plusieurs années.
- Activer la compression la plus efficace côté serveur sur tout ce qui est du texte : on gagne couramment 15 à 20 % de plus qu’avec la compression activée par défaut, sans toucher une ligne de code.
- Utiliser les polices du système plutôt qu’une police distante. Une famille de polices chargée depuis un service externe, c’est une résolution DNS, une négociation TLS et 100 à 300 Ko sur le chemin critique.
- Découper le code par écran et ne charger que ce que l’écran affiché exige.
- Compter les dépendances. Chaque bibliothèque ajoutée pour une seule fonction se paie en secondes sur le terrain. Une date formatée à la main coûte moins cher qu’une bibliothèque de 70 Ko.
Offline-first : concevoir pour l’absence de réseau, pas pour sa présence
La bascule mentale la plus importante : l’état normal de l’application n’est pas « connectée », c’est « déconnectée avec une synchronisation qui arrive ». Une application offline-first ouvre, affiche des données et accepte des saisies sans réseau. Le réseau devient un service opportuniste, pas une condition de fonctionnement.
La lecture : un cache qui affiche toujours quelque chose
Sur une application web comme sur une application installée, un cache local permet trois stratégies simples à combiner. Le squelette de l’application — la mise en page, les styles, le code d’interface, les icônes — est servi depuis le cache en priorité, avec une mise à jour en arrière-plan. Les données métier sont servies depuis le cache puis rafraîchies dès que le réseau répond. Les ressources non essentielles sont ignorées hors ligne plutôt que de bloquer l’écran.
Le principe à retenir : afficher une donnée d’hier avec la mention « dernière mise à jour : hier 17 h 12 » est infiniment supérieur à un écran de chargement infini. L’utilisateur décide lui-même si la donnée est assez fraîche pour son besoin.
L’écriture : une file d’attente, pas un formulaire qui échoue
C’est le point où la plupart des applications se cassent. Une saisie faite hors ligne doit être acceptée, stockée localement, puis rejouée quand le réseau revient. Concrètement :
- Stocker les écritures en attente dans une file locale sur le terminal, horodatées, quel que soit l’environnement retenu pour l’application.
- Générer les identifiants côté terminal plutôt que d’attendre celui du serveur. L’objet existe et se manipule avant même d’avoir été envoyé.
- Rendre chaque écriture idempotente : une clé d’idempotence envoyée avec la requête permet au serveur de reconnaître un rejeu et de ne pas créer deux fois la même commande. Sans cela, une connexion instable produit des doublons — le défaut le plus coûteux à corriger après coup.
- Afficher le statut de chaque élément : en attente, envoyé, refusé. L’utilisateur doit voir ce qui n’est pas encore parti.
- Définir à l’avance la règle de conflit : dernier écrivain gagne, ou fusion champ par champ, ou arbitrage humain. Ne pas trancher revient à trancher au hasard.
La synchronisation : envoyer le moins possible
Ne rapatriez jamais un jeu de données complet à chaque ouverture. Une synchronisation par delta — le client envoie la date de sa dernière synchro, le serveur ne renvoie que ce qui a changé depuis — transforme 4 Mo en 20 Ko. Ajoutez une pagination stricte, des champs limités au strict nécessaire dans les réponses d’API, et un ordre de synchronisation par priorité : d’abord les écritures en attente, ensuite les données critiques, enfin le reste.
Le réseau ne tombe pas, il ment
Une requête qui n’obtient pas de réponse est plus difficile à gérer qu’une erreur franche. Trois règles suffisent à rendre une application robuste face à ça.
- Des délais d’attente courts et explicites. Dix secondes suffisent : au-delà, il faut annuler et informer, pas laisser tourner.
- Des tentatives espacées avec du hasard. On réessaie après 1 s, 2 s, 4 s, 8 s, avec une variation aléatoire, pour éviter que tous les terminaux d’une équipe ne rechargent en même temps à la seconde où le réseau revient.
- Un plafond de tentatives au-delà duquel l’élément reste en file locale et attend une action manuelle. Une boucle de réessais infinie vide la batterie et le forfait data.
Les coupures de courant sont un cas de conception, pas un accident
Une saisie interrompue par une coupure et perdue, c’est un utilisateur qui n’ouvrira plus l’application le lendemain. Les parades sont simples et coûtent quelques heures de développement :
- Sauvegarde automatique locale de tout formulaire long, à chaque champ quitté, et restauration à la réouverture.
- Reprise d’état : l’application rouvre là où elle s’est arrêtée, avec les données déjà saisies.
- Découpage des opérations longues en étapes courtes validées une par une, plutôt qu’un traitement de trois minutes qu’une coupure annule entièrement.
- Côté serveur, des traitements reprenables : un import de 5 000 lignes interrompu doit repartir de la ligne 3 200, pas de zéro.
Terminaux d’entrée de gamme et Android ancien
Un téléphone à 50 000 FCFA n’exécute pas le même code au même prix qu’un modèle récent. Quelques réflexes concrets : limiter les animations coûteuses et les ombres complexes, éviter les longues listes rendues intégralement au profit d’une liste virtualisée, ne pas garder de grosses images décodées en mémoire, ne livrer à chaque terminal que ce qui correspond à son modèle plutôt qu’un paquet unique qui embarque tout, et fixer une version minimale d’Android réaliste plutôt que la dernière en date.
Deux points d’interface souvent négligés : des zones tactiles d’au moins 44 pixels de côté, parce qu’on utilise ces applications debout, en marchant, avec une seule main ; et un contraste élevé, parce qu’un écran d’entrée de gamme en plein soleil de midi à Cotonou n’affiche pratiquement rien en gris clair sur blanc.
Le paiement Mobile Money : là où l’à-peu-près ne pardonne pas
Le paiement est le moment où l’instabilité réseau devient un problème d’argent. La règle absolue : ne jamais considérer un paiement comme validé parce que l’utilisateur est revenu sur une page de confirmation. Il peut avoir fermé le navigateur, perdu le réseau, ou été renvoyé trop tôt.
- La source de vérité est la notification serveur à serveur (webhook) envoyée par l’agrégateur, complétée par une vérification active du statut de la transaction.
- Toute transaction doit porter une référence unique générée par vous, réutilisée à chaque vérification.
- Prévoir explicitement l’état « en attente de confirmation » dans l’interface, avec un message compréhensible plutôt qu’une erreur technique.
- Prévoir une réconciliation quotidienne entre vos enregistrements et ceux de l’agrégateur : sur du Mobile Money, quelques transactions par mois restent dans un état ambigu, et il faut un processus pour les traiter.
Tester dans les vraies conditions
Aucune de ces techniques ne se vérifie sur un poste de développement. La recette doit inclure, au minimum : un test sur un vrai téléphone d’entrée de gamme acheté pour ça, un test avec le mode avion activé en pleine saisie, un test avec bridage réseau à 400 kbit/s et 400 ms de latence, et un test de coupure brutale pendant l’envoi d’un formulaire. Ce sont quatre scénarios, ils prennent une demi-journée, et ils révèlent plus de défauts que trois semaines de tests unitaires.
Ces quatre scénarios ne servent pas qu’au mobile. Sur l’ERP PÈNATO que nous éditons chez IK’ART, une application web hébergée en instance dédiée par client — et qui exige donc une connexion pour être utilisée —, nous les jouons de la même manière : l’isolation par instance évite qu’un incident chez un client n’atteigne les autres et garantit que ses données ne sont mises en commun avec personne, et les opérations d’écriture sont conçues pour être rejouées sans créer de doublon, avec des traitements serveur qui reprennent là où une coupure les a interrompus au lieu de repartir de zéro. C’est la leçon transposable : ce qui rend un logiciel utilisable dans nos conditions réseau, ce n’est pas une autonomie hors ligne promise à la légère, c’est le fait qu’une session interrompue ne détruise jamais le travail déjà fait. Sur une application mobile, cette même exigence prend la forme de la file d’attente locale décrite plus haut.
Par où commencer sur une application existante
Si votre application est déjà en production et souffre sur le terrain, l’ordre d’attaque suivant donne le plus de résultat pour le moins de travail :
- Mesurez d’abord. Poids de la première page, temps d’affichage utile sur réseau bridé, taille des trois réponses d’API les plus appelées. Sans chiffres de départ, vous ne saurez pas si vous progressez.
- Traitez les images et les polices. C’est souvent 60 % du poids, et cela ne demande aucune modification de logique métier.
- Ajoutez la sauvegarde locale des formulaires. Peu de code, effet immédiat sur la confiance des utilisateurs.
- Passez la lecture en cache-puis-rafraîchissement sur les deux ou trois écrans les plus consultés.
- Rendez les écritures idempotentes et mettez-les en file d’attente. C’est le chantier le plus lourd, faites-le en dernier, mais faites-le : c’est lui qui élimine les doublons et les pertes de saisie.
Rien de ce qui précède ne dépend d’un environnement de développement particulier. Ce sont des décisions de conception, et elles se transposent au web comme au mobile, sur la technologie que votre projet impose et, si vous avez déjà un existant, sur le vôtre. C’est d’ailleurs la seule bonne façon de poser la question à un prestataire : non pas « avec quoi codez-vous », mais « que se passe-t-il, écran par écran, quand le réseau tombe ».
Une application qui fonctionne en Afrique de l’Ouest n’est pas une application allégée par défaut. C’est une application dont on a décidé, écran par écran, ce qui doit encore marcher quand le réseau, le courant et le téléphone font défaut en même temps. Cette décision se prend au moment de la conception, ou elle se paie deux fois plus cher six mois après la mise en production.
