Retour d'expérience sur la mise à jour d'une application iOS qui n'avait pas évolué depuis 2018. Cet article parcourt les aspects techniques de la démarche, les étapes et les processus d'amélioration mais rappelle également à quel point ne pas maintenir une application mobile pendant des années n'est clairement pas une bonne idée.
Contexte
Mi-octobre 2021, j'ai pris une semaine de vacances. Le samedi matin, première grâce matinée (qui n'en est jamais vraiment une avec des enfants), je découvre un email d'Apple :
Hello,
On September 1, 2016, we announced that we will be implementing an ongoing process of evaluating and removing apps that no longer function as intended, don’t follow current review guidelines, or are outdated.
We noticed that your app has not been updated in a significant amount of time.
Next Steps: To keep your app on the App Store, submit an updated version for review and make sure it follows the latest App Review Guidelines. If you are unable to submit an update within 30 days, your app will be removed from the App Store until you submit an update, and it is approved.
Ça annonce la couleur et me fait d'entrée miroiter de belles vacances ! Fort heureusement, il s'agit d'une application que j'ai développée à titre privé et qui n'est pas très conséquente. Le travail ne devrait pas être insurmontable. Bien qu'elle ne soit pas beaucoup utilisée, je veux quand même la garder disponible sur l'App Store, il faut donc que je mette la main à la pâte.
J'écris cet article car je ne pense pas être le seul dans ce cas. Des applications sont souvent développées, publiées, puis peu (voire pas) maintenues. Cela peut donner une idée du travail à qui doit se lancer dans une telle démarche.
D'où partons-nous ?
Avant de commencer, il est important de donner quelques informations sur l'application : ses fonctionnalités et sa configuration initiale.
Il s'agit de PCi Tracker. Une application que j'ai créée à titre privé pour le contexte de la Protection Civile. Son but est de pouvoir géolocaliser les astreints déployés sur les lieux d'un sinistre et de pouvoir les suivre depuis le Poste de Commandement d'Engagement (PCE) afin de conduire une intervention. L'application envoie régulièrement la position GPS de l'utilisateur sur un serveur web. Ce dernier affiche la position de tous les utilisateurs de l'intervention en cours sur une carte. Il est possible également d'envoyer au PCE des photos et de courts textes pour décrire la situation du terrain.
Cette application est donc utilisée que rarement - pendant des interventions ou des exercices - et par un nombre restreint d'utilisateurs. Ce qui en fait un cas exceptionnel comparé à des applications téléchargées et utilisées massivement à travers le monde. Il est important de garder cela en tête pendant tout le processus de migration car cela permet de le simplifier. Les raccourcis que j'ai pu prendre ne sont pas possibles dans la majeure partie des cas et votre application nécessitera peut-être plus de travail en cas de migration.
L'application est composée de huit vues (connexion à l'intervention, lecteur QRCode pour ouvrir une intervention, écran principal du suivi (listant les positions transmises au PCE), envoi d'une photo, envoi d'une position manuelle avec message, visualisation d'une position, réglages, et une page sur la confidentialité des données). Elle utilise une librairie externe pour gérer les pop-ups de chargement. De plus, elle est accompagnée d'une application pour Apple Watch permettant d'activer le suivi depuis la montre.
La dernière version en production, datant de septembre 2018 et servant donc de point de départ à cette migration, a comme version cible de déploiement iOS 11 et watchOS 4.3. Elle est compilée avec le SDK iOS 12 (fraichement sorti à l'époque). Elle est développée à 100% en Objective-C et utilise UIKit pour son interface.
Changement de SDK et de deployment target
En ouvrant le projet en 2021 (3 ans après la dernière release), la première étape consiste à compiler l'application avec le dernier SDK (iOS 15 en l'occurrence) et voir ce qui se passe. Dans ce cas, première bonne nouvelle : elle est vivante compile ! Ce n'est pas toujours le cas.
J'ai pris la décision, aux vues du petit nombre d'utilisateurs, de réduire la version minimale d'iOS nécessaire pour utiliser l'application (deployment target). Actuellement définie pour iOS 11, je l'ai définie pour iOS 14 (une version de moins que la version actuelle du système mobile d'Apple). Idem pour la partie Apple Watch de l'application, en passant de watchOS 4.3 à watchOS 7.
C'est généralement après avoir changé les deployment targets, au moment de la compilation, que les difficultés commencent ...
Des deprecated partout !
Changer de SDK et changer les deployment targets permettent d'assurer le fonctionnement de l'application sur les dernières plateformes mais également de prendre en charge les nouveautés introduites ces dernières années. C'est donc plutôt agréable, pour un développeur (et pour les utilisateurs in fine), de pouvoir bénéficier des nouveautés offertes par les SDKs récents.
Mais attention. iOS est en constante évolution. Une fonction introduite dans iOS 11 par Apple peut tout à fait être retirée dans iOS 15, rendant ainsi le code de l'application inopérant.
D'expérience, si on laisse trainer une application une année ou deux, on obtient surtout des avertissements (warnings) indiquant qu'une fonction est dépréciée (deprecated en anglais), rarement une erreur complète de compilation. Bien que ces avertissements permettent la compilation, il est très fortement déconseillé de les laisser trainer. Et d'ailleurs, je connais peu de développeurs qui se satisfassent d'un code fonctionnel avec des warnings.
Résultat dans le cas de PCi Tracker : 16 dépréciations. (Honnêtement, ce n'est pas immense, j'ai eu parfois des changements de SDK introduisant plus de 200 dépréciations.)
Une analyse de ces avertissements et du code m'a permis d'identifier deux sources de problèmes : Des modifications sur les méthodes permettant d'accéder aux autorisations du GPS, et les fonctions utilisées par la librairie externe que j'utilise.
La conversion du code lié au GPS n'a pas été très compliquée, d'autant que je l'avais déjà implémenté dans le cadre d'autres applications. Les méthodes pour demander l'autorisation d'accéder aux informations de localisation de l'utilisateur ont changé, notamment depuis l'effort d'Apple dans la protection des données personnelles. Ceci implique quelques changements sur comment accéder aux autorisations, mais sans impacter la structure du code de l'application ou remettre en compte une partie de sa logique.
Pour la librairie externe, MBProgressHUD, une mise à jour depuis le repository a permis de nettoyer pratiquement tous les avertissements. Il m'a suffit de retoucher un peu le code pour m'affranchir des derniers.
Petite note à ce propos : en intégrant à votre projet des librairies externes, votre application devient dépendante de la mise à jour régulière de ces dernières. Pensez-y au moment d'ajouter une nouvelle librairie ...
La correction de ces éléments a pris du temps mais n'était, dans ce cas, pas particulièrement compliquée. Une fois terminée, la partie fonctionnelle de l'application est opérationnelle. Néanmoins, avant de crier victoire, j'ai dû m'attarder sur l'interface utilisateur (UI).
Mode sombre
Depuis iOS 13 (2019), Apple a introduit un mode sombre dans l'ensemble de son système. Il permet d'assombrir l'interface de l'appareil dans certaines conditions (le soir par exemple). Ce comportement est natif et global à tout le système et les applications. Néanmoins, une application développée avant iOS 13 ne bénéficie pas de ces changements automatiquement. Ce n'était donc pas le cas de mon application en 2018.
J'ai alors testé l'application sur le simulateur iOS en mode sombre. Le résultat était quelque peu aléatoire. Avec certaines parties claires, d'autres foncées.
C'est assez logique : Avant l'introduction du mode sombre, une vue avait comme couleur de fond le blanc par défaut. Dès iOS 13, la couleur de fond par défaut est devenue System Background Color. Il s'agit d'une couleur double : blanche lorsque le mode clair est activé, gris foncé lorsque le mode sombre est activé.
Ainsi, la majorité des éléments utilisé pour composer l'interface avait des couleurs fixes (le blanc par défaut) qui ne changeaient pas lorsque l'appareil passait en mode sombre. Il a fallu ainsi changer toutes les anciennes couleurs pour utiliser celles prévues pour supporter le nouveau mode. Un travail facile mais long qui nécessite de tester toutes les interfaces dans les deux modes, tout en assurant la cohérence visuelle.
Heureusement, dans mon cas, l'application utilise uniquement des composants natifs proposés par iOS (UIKit). La conversion a donc été assez facile. Néanmoins, c'est une autre histoire lorsqu'une application possède une interface personnalisée n'utilisant peu ou pas les composants natifs ... Le travail devient très conséquent ! À garder en tête si votre application, certes très jolie et plus personnalisée que les composants classiques, possède une interface qui lui est propre.
Amélioration de l'interface utilisateur
Une fois les précédentes étapes terminées, l'application aurait pu être mise à jour sur l'App Store en l'état. Néanmoins, en me replongeant dans son code mais surtout son interface, je me suis rendu compte qu'il était possible de l'améliorer. J'ai donc décidé de faire quelques changements d'UI (User Interface).
N'étant moi-même pas designer, et n'ayant vraiment pas ni le coup d'oeil ni la fibre du graphisme, il n'est pas évident de concevoir des UIs jolies. J'insiste sur le terme "jolies", car je suis tout à fait capable de créer des interfaces orientées sur l'utilisation et le bon fonctionnement d'une application. Mais moins de les rendre agréables visuellement (couleurs, superpositions d'éléments, polices, etc.). Il est bon de noter que designer d'interface utilisateur est un métier à part entière, ce n'est pas pour rien !
Je me suis donc basé sur les interfaces développées par Apple qui utilisent en grande partie les éléments natifs de UIKit (et récemment de SwiftUI) :
- Utilisation de polices et de tailles standards proposées par le systèmes (Body, Callout, Caption, Footnote, Headline, etc.). Ceci permet d'avoir des textes s'approchant de ce que fait Apple dans ses applications. Non pas qu'ils ont la science infuse et qu'il faille obligatoirement faire "comme Apple". Mais simplement parce que ça s'intègre très bien dans le système iOS dans son ensemble.
- Utilisation d'éléments d'interface plus grands, notamment les boutons d'action. C'est le cas du bouton de connexion à une intervention ou de démarrage du suivi, par exemple. Ces boutons étaient trop discrets, ne sachant pas à l'époque comment les designer. Je les ai agrandis et rendus plus visibles.
- Dans le même ordre d'idée, j'ai également changé les couleurs. Les rendant plus vives. Marquant ainsi plus fort les actions, notamment les boutons. De plus, j'ai utilisé des couleurs d'accentuations et des couleurs secondaires pour les éléments secondaires (comme les fonds des différentes vues), permettant de donner un meilleur effet à l'interface, notamment en mode sombre.
Remplacement des pictogrammes
En plus des boutons, textes, listes, etc. composants l'interface, il faut compter sur les pictogrammes. Ceux-ci sont utilisés pour symboliser une action (comme un bouton) ou une information (dans une liste par exemple). Mon application en utilise plusieurs : bouton pour ouvrir le lecteur de QRCode, pour accéder aux réglages, etc. Jusqu'à maintenant, je devais toujours trouver des images sur Internet permettant de créer ces pictogrammes (notamment sur le site icones8). À nouveau, n'étant pas designer, créer des pictogrammes moi-même n'est pas évident. J'ai donc dû me contenter de ce que je trouvais sur le web lorsque je ne travaillais pas avec un designer dédier au projet. C'est le cas pour mes applications persos.
Mais depuis iOS 13 (2019), Apple met à disposition SF Symbols. Il s'agit d'une bibliothèque de pictogrammes qu'on peut utiliser facilement dans les applications (intégrés comme la police par défaut du système). Il est possible d'obtenir chaque pictogramme en plusieurs tailles et épaisseurs, et de facilement les intégrer dans son interface.
J'ai donc supprimé les pictogrammes au format image que j'avais pour les remplacer par ces pictogrammes plus "travaillés". Évidemment, toutes les actions ou informations ne peuvent pas être représentées par les pictogrammes proposés dans SF Symbols, mais une bonne partie a pu être convertie.
Pour créer une image à partir de SF Symbols, le code est simplement (ici en Objective-C) :[UIImage systemImageNamed:@"mappin.and.ellipse"]
Si vous souhaitez changer l'épaisseur du pictogramme, utilisez le code suivant :UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithWeight:UIImageSymbolWeightThin];
UIImage *img = [UIImage systemImageNamed:@"arrow.down" withConfiguration:config];
Cette utilisation de SF Symbols est très agréable car elle évite de devoir trouver (ou créer) des pictogrammes, générer plusieurs tailles d'image, et les importer dans l'application (alourdissant au passage le binaire final). Elle permet également d'avoir des interface assez standardisées avec des pictogrammes ayant le même aspect visuel (épaisseur, type de design). Et bien sûr, dans le cas des développeurs qui, comme moi, n'ont pas l'oeil d'un designer, cela permet un gain de temps notable !
Tests
Une fois tous ces éléments convertis et améliorés, l'application semble être prête pour sa mise à jour (enfin !). Néanmoins, seuls des tests permettent de s'assurer que son fonctionnement est toujours bon et que de nouveaux bugs n'ont pas été introduits. En 2018, je n'avais pas rédigé de tests unitaires ou fonctionnels de l'application. Par contre, j'en avais rédigés pour tester l'accès à l'API qui correspond en fait aux fonctionnalités principales de l'application. J'ai donc exécuté ces tests et tout était toujours opérationnel. Ce qui est logique car ces parties du code n'ont pas subi de changements.
J'ai ensuite fait des tests manuels de l'interface, notamment en mode sombre et sur plusieurs simulateurs (tailles d'écran).
Et pour finir, j'ai fait des tests qui sont difficiles à automatiser : J'ai utilisé l'application sur le terrain lors d'un déplacement en voiture. Notamment pour tester que le relevé des positions GPS se faisait bien, y compris en tâche de fond.
Une application comme celle-ci reste difficile à tester de manière automatique (tests fonctionnels ou unitaires) dans le mesure où son fonctionnement est spécifique aux déplacements, en tâche de fond et sur une longue durée.
Mise à jour sur App Store Connect
Mon application étant maintenant convertie, compatible avec les deux derniers OS et améliorée (UI), il ne restait plus qu'à la publier sur l'App Store. Pour cela, il faut soumettre sa mise à jour via App Store Connect, l'interface de gestion de ses applications pour l'App Store, et passer la validation des équipes d'Apple.
Qui dit application de 2018, dit expiration des provisioning profiles (valables un an). Ceux-ci permettent notamment de signer l'application et d'instruction pour l'installation. Renouveler les provisioning profiles n'est pas compliqué pour autant que vous ayez toutes les informations nécessaires (certificat de distribution, Bundle ID). Dans mon cas, j'ai eu quelques problèmes avec le provisioning profile lié à la partie Apple Watch, mais c'était dû à une fausse manipulation de ma part.
Après quelques essais, j'ai pu envoyer le nouveau binaire à Apple et j'ai attendu sa validation. Évidemment, une application demandant à l'utilisateur sa position GPS en continue, y compris en tâche de fond et de manière prolongée, suscite immédiatement les soupçons de l'équipe de validation ... Elle a donc été refusée, non pas à cause d'un problème technique, mais parce qu'ils voulaient savoir comment elle fonctionnait et quel était son but. Après quelques échanges et une vidéo de démonstration, la mise à jour a été acceptée.
Conclusion
Convertir une "vieille" application peut être douloureux et je le craignais en commençant ce travail. Dans mon cas, ça n'a pas été aussi pénible que ce que je m'attendais. Le fait que ce projet soit de taille modeste (peu de fonctionnalité et d'interfaces) a grandement aidé, bien sûr. De plus, l'utilisation d'éléments d'interface standards est essentiel et m'a fait gagner énormément de temps.
Cette replongée dans une application de 3 ans en arrière m'a permis également de l'améliorer sur plusieurs aspects. Et de voir les progrès que j'ai faits en développement iOS, car ce métier est en évolution constante (aussi bien l'aspect technologique que les compétences).
Et votre app ?
Néanmoins, cette opération peut être très chronophage pour une application composée d'éléments d'interface personnalisés ne faisant pas appel aux outils standards. Idem, bien sûr, suivant comment est réalisé son code logique métier, mais c'est plus difficile à généraliser dans ce cas.Ce problème n'arrivera pas à une entreprise dont le modèle d'affaire est basé sur son (ou ses) application. Mais je pense plutôt à des entreprises qui ont sorti une application à des fins marketings, mais ne l'ont pas tenue à jour. Il s'agit dans ce cas d'un produit secondaire qui n'a pas forcément un impact immense sur la stratégie de l'entreprise, il est donc laissé de côté "tant que ça marche".
Le problème survient lorsqu'il faut mettre à jour l'application : soit pour y changer une petite partie, soit parce que Apple "fait le ménage" dans les vieilles applications. Un changement mineur peut alors prendre des proportions immenses. Il s'agit pratiquement d'un nouveau projet à gérer pour les développeurs qui doivent revoir de fond en comble le code, l'interface et même certaines fonctionnalités de l'application qui pourraient ne plus marcher.
Dans mon entreprise, nous maintenons le code métier de nos librairies constamment, afin d'éviter ces changements abruptes forcés. Une mise à jour régulière a un coût, mais il est lissé sur plusieurs années (ou mois) tandis ce qu'une migration conséquente peut générer des coûts largement supérieurs et parfois faits dans l'urgence.
Si vous avez développé une application, savez-vous depuis quand elle n'a pas été mise à jour ? Savez-vous si les fonctions utilisées sont toujours d'actualité ou autorisées ? Savez-vous si elle fonctionnerait toujours actuellement ? Savez-vous si son interface utilise des composants standards ? Posez-vous ces questions et n'hésitez pas à consacrer du temps si nécessaire.