
Écrits · 11 mai 2024
Développer une appli iOS native
Créer une appli de suivi pour le vélo et la course à pied
Pour un petit projet perso, glissé entre mon travail habituel, je me suis lancé dans quelque chose qui m'intéresse à titre personnel : une appli native de suivi d'entraînement pour iOS. Je voulais rendre ma montre connectée inutile en utilisant mon téléphone pour enregistrer mes entraînements. Est-ce si difficile de récupérer des données détaillées de capteurs avec les API natives de Swift ?
Contexte
Si tu suis mon blog, ça ne te surprendra pas : j'adore faire du vélo et je me suis mis récemment à la course à pied. J'ai pas mal d'expérience dans le suivi de mes entraînements, avec Garmin, Strava, Omata, Wahoo, Biostrap, Whoop et diverses applis et capteurs. Je trouve les données de santé et de forme utiles pour connaître tes performances physiques et pour avoir une sorte de garde-fou personnel (par exemple pour te motiver à continuer les entraînements).

Le geek en moi adore les gros jeux de données, et les nombreux types de capteurs disponibles sont un festin pour ma curiosité, mais ça entre en conflit avec mon envie de minimalisme et de simplicité. Faut-il vraiment toutes ces données d'entraînement ? Est-ce qu'écouter son corps ne suffit pas ? Je ne sais pas, mais j'apprécie qu'une montre connectée puisse suivre (presque) sans effort un entraînement dans les moindres détails. J'aime la façon dont l'Apple Watch peut servir à suivre les entraînements, en plus d'être une montre outil moderne et un remplaçant de smartphone. Je comprends que la plupart des gens portent leur montre connectée et s'en contentent, mais j'aime aussi les bonnes vieilles montres mécaniques comme une Rolex, une Tudor, une Grand Seiko, ou même quelque chose de sur mesure. Même si j'apprécie les deux, je penche vers les montres mécaniques quand je dois choisir entre montre connectée et montre mécanique.
L'idée de l'appli : Gran Fondo
Et s'il existait une appli pour smartphone qui récolte toutes les données d'entraînement que tu veux, sans les tracas ni le fouillis ? Je l'imaginais ainsi :
- Simple : elle doit se faire oublier, être conçue pour « simplement marcher », sans avoir à bidouiller des réglages ou des options à n'en plus finir. Tu appuies sur « démarrer » et tu commences ton entraînement.
- Flexible : utilise l'appli de différentes façons : fixe ou porte ton téléphone bien en vue pour des données en temps réel, ou mets-le dans ta poche et laisse-le travailler en arrière-plan.
- Puissante : connecte des capteurs de fréquence cardiaque, de cadence, de puissance et de vitesse en Bluetooth ; prise en charge de plusieurs capteurs, idéal si tu utilises plusieurs vélos.
- Compatible Apple Health : enregistre toutes les données dans Apple Health avec le maximum de détails, y compris les parcours et chaque mesure de puissance, de cadence et de vitesse. Tu peux ainsi analyser tes enregistrements dans n'importe quelle appli compatible Apple Health, comme Strava, WHOOP, HealthFit et bien d'autres.
- Honnête : pas de pub, pas de revente de données. Pas de compte ni d'inscription. Tes données doivent rester privées, sécurisées et sur ton appareil.
Aucune des applis de sport et de forme existantes pour smartphone ne coche toutes ces cases. La plupart sont inutilement complexes ou conçues, d'une manière ou d'une autre, pour récupérer tes données au profit du créateur de l'appli ou de sa plateforme. Pouvais-je faire mieux ?
Construire l'appli
Une fois que je savais pourquoi et quoi, je me suis mis à choisir ma méthode préférée pour la construire.
Native contre hybride/web
Pour la plupart de mon travail, je préfère utiliser des technologies web ouvertes et libres (au sens de libre), comme HTML, JavaScript et CSS, ou des logiciels serveur publiés sous une licence de logiciel libre, comme la GPL. Pour ce cas précis, il me fallait une efficacité énergétique extrême et une intégration profonde avec le système d'exploitation de mon smartphone. La meilleure manière d'y arriver sur un iPhone est d'adopter à fond le kit de développement logiciel d'Apple : créer l'appli nativement en Swift avec SwiftUI, en suivant au plus près les consignes techniques et les règles de design.
Programmation assistée par l'IA
Même si j'ai mes réserves, la programmation avec l'IA fait beaucoup parler d'elle ces derniers temps. Certains prétendent même que des technologies comme Copilot ou ChatGPT rendront les programmeurs obsolètes. Je connais bien l'IA, car je l'ai utilisée pour générer du code, j'apprends aux gens à s'en servir, mais je ne l'avais jamais utilisée pour construire une appli iOS complète. J'y ai vu l'occasion idéale de voir si l'IA est à la hauteur de quelque chose de plus complexe qu'un simple bout de script. Voyons à quel point je suis obsolète en tant que programmeur à l'ère de l'IA...
GPS et capteurs Bluetooth Low Energy
Mon environnement Xcode en place, j'ai demandé à ChatGPT d'OpenAI de me donner du code pour lire les données de localisation GPS et de générer les classes Swift nécessaires pour détecter des capteurs Bluetooth et s'y connecter. Là, je suis vraiment tombé dans le terrier du lapin !

Le truc avec la programmation assistée par l'IA, c'est que OUI, ça marche ; mais seulement EN PARTIE. Elle te donne des morceaux qui fonctionnent, mais qui ne s'emboîtent pas parfaitement et ne marchent pas forcément ensemble. Voir le code qu'elle génère, c'est comme entendre l'écho d'une super chanson ; tu reconnais que ça ressemble à quelque chose, mais ça n'a rien à voir avec le groupe qui joue en direct, et encore moins avec le fait de la chanter toi-même !
J'ai pris les morceaux de l'IA et je suis parti lire moi-même la documentation pertinente, ce qui s'est avéré bien plus efficace, car j'ai ainsi pu comprendre ce que le mécanisme devait faire. L'IA m'a aidé à trouver ce que je devais apprendre. Le suivi de la position GPS a été étonnamment facile avec CoreLocation d'Apple. Connecter le capteur Bluetooth à l'appli s'est avéré bien plus difficile, car cela comprend plusieurs étapes distinctes :
- Détecter les appareils Bluetooth : scanner les environs pour trouver tous les appareils disponibles qui émettent
- Se connecter à un appareil Bluetooth : établir et maintenir une connexion entre l'appli et l'appareil
- Découvrir les caractéristiques de l'appareil Bluetooth : un appareil Bluetooth simple, ça n'existe pas ; il faut faire soi-même la « découverte » des capacités et des fonctions de l'appareil ; beaucoup d'appareils émettent plusieurs signaux différents, pour les données du capteur, les mécanismes de contrôle et les paramètres de fonctionnement comme le niveau de batterie.
- S'abonner aux caractéristiques : au final, tu t'abonnes à un flux de données en réglant les radios Bluetooth sur une caractéristique Bluetooth donnée.
- Décoder les données : vu sa nature économe en énergie, tu reçois un minimum de données en bits bruts ; tu dois décoder les paquets toi-même ; le plus dur, c'est que chaque capteur, chez chaque fabricant, encode ses données à sa façon.
Prends par exemple un capteur relativement « simple » comme un capteur de cadence que tu fixes sur la pédale de ton vélo, et qui sert à déterminer le nombre de tours par minute pendant une sortie. Qu'est-ce que ça peut avoir de compliqué ? Je pensais que la spécification Bluetooth officielle me donnerait tous les détails nécessaires... PAS DU TOUT ! Un simple capteur de cadence est étonnamment complexe :
- Profil Bluetooth combiné pour la vitesse et la cadence à vélo : un capteur de cadence s'annonce toujours comme capteur de vitesse et de cadence, et tu dois découvrir ses capacités « à la volée ».
- Paquets de données différents : le contenu des données dépend des capacités actuelles du capteur (par exemple s'il a détecté quelque chose) ; tu dois interpréter le paquet bit par bit, en vérifiant d'éventuels indicateurs qui disent ce que représente le bit suivant.
- Données non triviales : ne t'attends pas à une valeur nette pour la « cadence » ; le capteur te donne un nombre cumulé de tours et un horodatage rudimentaire du dernier changement détecté ; tu dois utiliser ces valeurs pour calculer la mesure que tu cherches.
L'IA m'a fourni du code d'exemple, mais il ne fonctionnait pas avec mon capteur. Avec une appli de débogage Bluetooth, Bluefy, j'ai pu mieux comprendre les données que transmettait le capteur. J'ai trouvé un morceau de code Java sur le blog officiel de Bluetooth qui m'a donné des pistes pour interpréter les données des capteurs. J'ai adapté ce code à différents profils de capteurs et je l'ai traduit en Swift. Ça m'a donné un premier prototype fonctionnel.

Design UI/UX
L'une des principales raisons pour lesquelles j'aime l'appli d'entraînement de l'Apple Watch, c'est que son interface utilisateur (UI) est conçue pour offrir une expérience utilisateur (UX) agréable. L'appli de la montre a de gros boutons sur lesquels tu appuies pour lancer un enregistrement, et c'est à peu près tout. Elle a peu d'options, son design assume ses partis pris, mais il est bien pensé. C'est un contraste énorme avec des appareils comme Garmin, qui proposent une tonne d'options de personnalisation. Le truc, c'est de trouver le bon équilibre entre la flexibilité des usages et une configuration par défaut qui fonctionne bien.

Avec un système de fixation comme Quad Lock, tu peux attacher solidement ton smartphone au guidon de ton vélo. L'iPhone peut ainsi remplacer ton Garmin comme compteur de vélo. Les iPhone récents ont un écran toujours allumé qui peut afficher des informations en consommant peu, à condition d'utiliser le kit de développement d'Apple, qui intègre diverses optimisations. Après de très, très nombreux kilomètres avec mon compteur Garmin, j'ai fini par choisir un écran avec des champs de données en temps réel pour la vitesse, la puissance et la fréquence cardiaque. Ce que j'aime dans les appareils Garmin Edge plus avancés, c'est qu'ils peuvent tracer un graphique. Tu gardes ainsi les yeux sur la route quand c'est important, et tu jettes un œil à l'historique un peu plus tard.



Pour maximiser l'efficacité énergétique, j'ai décidé d'utiliser les bibliothèques de graphiques d'Apple : Swift Charts. Un problème rencontré pendant le développement : les mesures des capteurs arrivent à des intervalles et des moments différents. Il faut créer une sorte de mécanisme de synchronisation pour que les points de données correspondent à des horodatages communs, afin de pouvoir comparer et relier les valeurs. J'ai conçu ce mécanisme pour synchroniser aussi les mises à jour de l'interface : tous les graphiques et points de données sont mis à jour en un seul rafraîchissement, ce qui optimise les performances du processeur et du graphisme (et donc la batterie). En bonus, j'ai ajouté la prise en charge de différentes échelles de temps : les graphiques peuvent montrer les données de la dernière minute, des 5 dernières minutes, des 15 dernières minutes, de la dernière heure ou de tout l'entraînement.

L'appli affiche automatiquement les graphiques disponibles selon les capteurs connectés, ce qui évite de devoir changer de configuration quand tu as plusieurs vélos. Si tu touches un graphique, il s'agrandit ou se réduit. Si tu touches l'échelle de données (par exemple « les 5 dernières minutes »), tu passes d'une échelle à l'autre. L'appli retient ta configuration et te prépare automatiquement pour le prochain entraînement. Comme toutes les zones tactiles et tous les boutons sont assez grands, ils fonctionnent bien avec des mains en sueur ou des gants.
Dans la poche : optimiser pour l'arrière-plan et la consommation d'énergie
Je voyais une autre façon d'utiliser l'appli : depuis ma poche, en tâche de fond. Cela permettrait une collecte de données discrète : tu lances l'appli et tu ranges ton téléphone. J'adore l'idée d'avoir un « jeu de données complet » pour toutes mes sorties à vélo et à pied, sans devoir avoir l'appli au premier plan tout le temps. Beaucoup d'entraînements et de sorties ne sont pas si intéressants.

Par défaut, le système d'exploitation iOS d'Apple limite strictement ce que les applis peuvent faire en arrière-plan. Cela maximise l'autonomie de la batterie et la vie privée de l'utilisateur. Si tu suis les consignes d'Apple et demandes correctement les autorisations nécessaires à l'utilisateur, tu peux concevoir ton appli pour qu'elle fonctionne parfaitement en arrière-plan. J'ai vraiment fini par apprécier les efforts d'Apple pour optimiser toute la pile, ce qui permet à ton appli d'être plus économe en énergie. En gros, le système d'exploitation applique le principe « ne nous appelez pas, on vous appellera » : il garde la main sur le moment où ton appli fait son travail, ce qui lui permet de synchroniser, regrouper et traiter par lots les différentes tâches sur les cœurs (économes en énergie) des puces Apple Silicon.
Lors d'un test avec une version prototype de l'appli, j'ai pu collecter plus de 127 mille (!!) points de données pendant une sortie longue distance de 8 heures, sur une seule charge de batterie d'iPhone, avec l'écran allumé en permanence. Si tu respectes les règles d'Apple, tu as vraiment du jus (si j'ose dire). Développer cette appli m'a vraiment mené quelque part, ha !

Les vrais artistes livrent
L'enfer est pavé de bonnes intentions, dit-on... C'est pour cela que j'aime vraiment finir mes projets. Pour une appli, cela veut dire qu'elle doit être publiée dans l'App Store. La préparer pour l'examen d'Apple et la faire approuver par les examinateurs de l'App Store est une étape supplémentaire. C'est important, parce que ça t'oblige à réfléchir à l'accueil (des nouveaux utilisateurs) et au modèle de revenus.
L'accueil des utilisateurs
Une tâche particulièrement délicate quand on construit une appli est d'expliquer aux nouveaux venus comment s'en servir. Une excellente interface aide, mais vu l'intégration poussée de l'appli avec Apple Health, la localisation et les capteurs Bluetooth, il faut en plus demander poliment des autorisations.

Tu dois concevoir le parcours pour qu'il ne plante pas quand les gens refusent certaines autorisations. Apple est très strict là-dessus : les gens ont le droit de refuser. C'est ton travail de faire fonctionner l'appli avec aucune autorisation ou seulement une partie. C'est un défi de plus.
Un modèle de revenus pour financer le développement
Je ne peux pas surestimer l'importance du logiciel libre, au sens de libre, mais je ne peux pas ignorer que j'ai une famille à nourrir. Et surtout, trouver des gens prêts à payer pour ton produit peut servir de validation supplémentaire de ton idée. Sois ouvert et honnête sur ton modèle de revenus, ça t'aidera à financer ton propre projet ; ne compte pas sur des investisseurs ou du capital-risque, finance ton propre développement !

Tu n'as pas besoin de payer pour essayer l'appli. L'écran de paiement n'apparaît que quand les gens utilisent vraiment l'appli (et on peut toujours le fermer). Pourquoi ne pas l'essayer toi-même, tu peux trouver l'appli ici.
Et la suite
Utilise toi-même ton produit (le fameux « dogfooding »), dit-on : je vais continuer à développer l'appli en l'utilisant moi-même. Je ne m'attends pas à ce que ce projet soit un gain (financier) rapide, mais s'il me sert concrètement, il y a de bonnes chances que quelqu'un d'autre le trouve utile aussi.

Ce que j'aime dans ce projet, c'est qu'il demande peu d'efforts pour continuer, puisque j'aime m'entraîner. Déboguer les nouvelles versions de cette appli passe souvent par une sortie de course à pied ou de vélo. Qui a dit que le développement logiciel était un métier sédentaire ?!
Conclusion
Beaucoup de gens ont des « idées géniales », peu les réalisent vraiment. C'est ce qui distingue ceux qui font des choses des autres. J'aime fabriquer des choses, car le processus oblige à vraiment plonger dans le sujet. Tu apprends énormément et tu acquiers une expérience que les autres n'auront pas. Allez, construis-le toi-même, fais-en ton projet !