<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>store d'application mobile - Tag - Jordan Chapuy - Blog d'un développeur passionné ❤️</title><link>https://jordanchapuy.com/tags/store-dapplication-mobile/</link><description>store d'application mobile - Tag - Jordan Chapuy - Blog d'un développeur passionné ❤️</description><generator>Hugo -- gohugo.io</generator><language>fr</language><lastBuildDate>Fri, 08 Nov 2024 11:38:00 +0100</lastBuildDate><atom:link href="https://jordanchapuy.com/tags/store-dapplication-mobile/" rel="self" type="application/rss+xml"/><item><title>Mettre à jour une application mobile sans passer par les stores - #7 Les ressources</title><link>https://jordanchapuy.com/posts/2024/11/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-7-ressources/</link><pubDate>Fri, 08 Nov 2024 11:38:00 +0100</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2024/11/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-7-ressources/</guid><description><![CDATA[<p>Des <a href="https://jordanchapuy.com/posts/2023/09/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-2-remote-config-feature-flag" rel="">Feature Flag</a> aux <a href="https://jordanchapuy.com/posts/2024/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-6-over-the-air-update-ota" rel="">mise à jour par OTA</a>, on est monté crescendo dans les possibilités de modification d&rsquo;une app mobile à distance. Aujourd&rsquo;hui, revenons sur quelque chose de plus simple. Tellement simple que l&rsquo;on va enfoncer des portes ouvertes.</p>
<p>J&rsquo;y ai pensé sur la fin, ça m&rsquo;a sauté aux yeux : <strong>les ressources</strong>. Toutes ces petites choses dont l&rsquo;application peut avoir besoin comme des illustrations, des cartes, des documents pdf, des sons, des vidéos, etc.</p>
<p>On peut les embarquer directement au sein de l&rsquo;application. Elles sont donc téléchargées en même temps que l’utilisateur installe l’application - c’est un package, tout est inclus dans la boîte.</p>
<p>Il y a plusieurs avantages pour l&rsquo;utilisateur. Il a tout, tout de suite. Dès le premier lancement. Aucun besoin de charger (et donc de faire patienter), les ressources s&rsquo;affichent immédiatement. C&rsquo;est également disponible pour une utilisation hors-ligne.</p>
<p>Mais de l&rsquo;autre côté, cela implique que la ressource ne peut pas changer. Il faudra déployer une mise à jour que l&rsquo;utilisateur devra installer. Le poids de l&rsquo;app peut vite s&rsquo;alourdir. Même si c&rsquo;est moins le cas aujourd&rsquo;hui, avec toujours plus de stockage et de data internet dans les forfaits, certains utilisateurs restent regardant sur le poids affiché dans la fiche du store.</p>
<p>Sans surprise, on a des solutions pour modifier les ressources - on est tout de même sur une série &ldquo;sans passer par les stores&rdquo;. Il <em>suffit</em> de les exposer sur un serveur, de les rendre téléchargeables. Selon nos besoins, on a d&rsquo;ailleurs plusieurs options :</p>
<ul>
<li><strong>Ne rien embarquer dans l&rsquo;application, tout est en ligne</strong>. L&rsquo;application sera légère à l&rsquo;installation, au détriment de chargements à prévoir au premier lancement / aux premières utilisations. Point d&rsquo;attention, l&rsquo;app n&rsquo;aura aucune de ces ressources à son premier lancement si l&rsquo;utilisateur n&rsquo;a pas de réseau. Il sera limité.</li>
<li><strong>Embarquer ET avoir les ressources en ligne</strong>. On mixe les avantages. Les ressources seront disponibles tout de suite, et l&rsquo;utilisateur aura accès à des versions plus récentes lorsqu&rsquo;elles changeront.</li>
<li>On peut créer une mécanique pour <strong>ne télécharger que les nouvelles versions</strong> de ressources, en envoyant au serveur la date du dernier téléchargement ou un numéro de version. Le serveur répondrait alors soit avec une nouvelle ressource, soit que rien n&rsquo;a changé (réponse légère).</li>
<li>On peut ajouter une notion de <strong>fraîcheur</strong>, un délai pendant lequel l&rsquo;application va considérer qu&rsquo;elle n&rsquo;a pas besoin de faire une requête vers le serveur pour (peut-être) récupérer une nouvelle version de la ressource.</li>
</ul>
<p>Tous ces choix peuvent être appliqués différemment selon les ressources. On aura par exemple envie d&rsquo;embarquer de base la carte des métros qui est utilisée par la majorité de nos utilisateurs, mais pas celles des bus de nuit, qui sera en téléchargement optionnel.</p>
<p>On décide en fonction de plusieurs critères. Quand est-ce que c&rsquo;est utilisé (dès le début vs dans un écran lointain), à quelle fréquence (chaque utilisation de l&rsquo;app vs peut-être une fois de temps en temps), combien d&rsquo;utilisateurs sont concernés (tous vs seulement un petit segment).</p>
<p>Terminons par un autre enfoncement de porte ouverte. Une porte encore plus grande. C&rsquo;est bientôt le week-end, on peut se faire plaisir. <strong>Les données, ce sont aussi des ressources</strong>.</p>
<p>Des mentions légales par exemple, ou un référentiel JSON. Hop, sur un serveur ! Et le changement devient possible sans mise à jour de l&rsquo;application. Le référentiel peut être exposé statiquement par le serveur ou devenir un endpoint. Idem pour les mentions, qui pourraient même se transformer en une page HTML chargée dans une webview.</p>
<p>Et ce titre qui change souvent ? Pourquoi pas un peu de <a href="https://jordanchapuy.com/posts/2023/09/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-2-remote-config-feature-flag" rel="">Remote config</a>. La boucle est bouclée.</p>
<p>Bon week-end :)</p>
<hr>
<blockquote>
<p>Série d&rsquo;articles <strong>Mettre à jour une application mobile sans passer par les stores</strong> :</p>
<ul>
<li><a href="https://jordanchapuy.com/posts/2023/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-1-pourquoi" rel="">#1 Pourquoi</a></li>
<li><a href="https://jordanchapuy.com/posts/2023/09/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-2-remote-config-feature-flag" rel="">#2 Remote config, Feature Flag &amp; co</a></li>
<li><a href="https://jordanchapuy.com/posts/2023/12/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-3-backend-for-frontend-bff" rel="">#3 Backend for Frontend (BFF)</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/01/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-4-server-driven-ui" rel="">#4 Server-Driven UI</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/07/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-5-interpreteur-de-code" rel="">#5 Interpréteur de code</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-6-over-the-air-update-ota" rel="">#6 Over-the-air update (OTA)</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/11/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-7-ressources" rel="">#7 Les ressources</a></li>
<li>#8 En résumé, mes options</li>
</ul>
<p>Hors-série :</p>
<ul>
<li>Accélérer le temps de review App Store d&rsquo;une application iOS</li>
<li>Forcer la mise à jour d&rsquo;une application mobile</li>
</ul>
</blockquote>
]]></description></item><item><title>Mettre à jour une application mobile sans passer par les stores - #6 Over-the-air update (OTA)</title><link>https://jordanchapuy.com/posts/2024/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-6-over-the-air-update-ota/</link><pubDate>Wed, 07 Aug 2024 16:10:00 +0100</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2024/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-6-over-the-air-update-ota/</guid><description><![CDATA[<p>Nous y sommes enfin, la solution ultime pour mettre à jour notre application mobile sans passer par les stores. Une mise à jour complète. Pas juste un élément, pas besoin de prévoir un <a href="https://jordanchapuy.com/posts/2023/09/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-2-remote-config-feature-flag" rel="">flag</a> ou une quelconque configuration, non, on change quasiment tout ! Et sans besoin de l&rsquo;aval d&rsquo;Apple et Google. Ni même d&rsquo;une action des utilisateurs. Mais quelle est donc cette magie noire ?</p>
<h1 id="over-the-air-update">Over-the-air update</h1>
<p>Derrière l&rsquo;acronyme OTA se cache un mécanisme pour <strong>déployer une mise à jour directement sur les appareils</strong> des utilisateurs. Pour comprendre la différence avec une mise à jour classique, rappelons les étapes de ce processus (simplifié).</p>
<ul>
<li>L&rsquo;équipe développe une nouvelle version.</li>
<li>Le build est envoyé sur l&rsquo;App Store / le Google Play.</li>
<li>Apple / Google prend le temps d&rsquo;effectuer quelques vérifications.</li>
<li>La nouvelle version est disponible sur l&rsquo;App Store / le Google Play.</li>
<li>Via le store, l&rsquo;utilisateur installe la nouvelle version&hellip;
<ul>
<li>Manuellement : quand l&rsquo;utilisateur aura décidé de le faire.</li>
<li>Automatiquement : quand le système aura décidé du &ldquo;moment idéal&rdquo; (Wifi, en charge, niveau de batterie).</li>
</ul>
</li>
</ul>
<p>On note qu&rsquo;il y a deux étapes qui peuvent prendre du temps et qui ne sont pas sous notre contrôle : la vérification par les stores et l&rsquo;installation par les utilisateurs. Regardons maintenant comment se déroule une mise à jour OTA.</p>
<ul>
<li>L&rsquo;équipe développe une nouvelle version.</li>
<li>Le build est envoyé sur le serveur OTA.</li>
<li>L&rsquo;application détecte et télécharge la mise à jour.</li>
<li>L&rsquo;application se lance avec la nouvelle version.</li>
</ul>
<p>Il n&rsquo;y a plus d&rsquo;action extérieure. C&rsquo;est l&rsquo;application qui <strong>se met à jour elle-même</strong>, sans intervention des stores ou de l&rsquo;utilisateur. Le temps nécessaire pour que les utilisateurs disposent de la nouvelle version peut être fortement <strong>réduit</strong> par rapport à une mise à jour classique.</p>
<p><em>Note : le moment exact où l&rsquo;application se lancera avec la nouvelle version dépendra de la solution utilisée. Par exemple au prochain lancement de l&rsquo;application, ou une mise à jour forcée en pleine utilisation.</em></p>
<h2 id="comment-est-ce-possible-">Comment est-ce possible ?</h2>
<p>L&rsquo;<em>Over-the-air update</em> est devenu faisable avec des technologies <strong>cross-plateform</strong> comme Flutter et React Native. Eh oui, autant le dire tout de suite au risque d&rsquo;en décevoir quelques-uns, ce n&rsquo;est actuellement pas possible de le faire sur une application native Android ou iOS.</p>
<p>Dans une application native, l&rsquo;ensemble du code est <em>figé</em> lorsque l&rsquo;on génère un exécutable, une version. On ne peut pas apporter de modification sur ce code, à moins de générer un nouvel exécutable et de l&rsquo;installer. D&rsquo;ailleurs, ce code est écrit dans un langage prévu par la plateforme. Par exemple Swift pour iOS et Kotlin pour Android. Il est <em>naturellement compris</em> par la plateforme - il n&rsquo;y a pas besoin de le <em>traduire</em>.</p>
<p>Flutter et React Native fonctionnent différemment. On utilise les langages Dart et Javascript - il y a donc besoin de <em>traduire</em> pour que l&rsquo;éco-système natif puisse comprendre les instructions. C&rsquo;est le rôle des <strong>machines virtuelles</strong> qui sont embarquées avec ces technologies cross-plateform, une couche supplémentaire qui a la capacité d&rsquo;exécuter ces langages et de discuter avec la plateforme native.</p>
<p>C&rsquo;est grâce à cette différence que l&rsquo;OTA est possible. Vu qu&rsquo;il est possible d&rsquo;interpréter du code au <strong>runtime</strong>, il suffit de récupérer du <strong>code distant</strong> (sur un serveur) qui serait utilisé à la place du code local (embarqué dans l&rsquo;application). Bien entendu, c&rsquo;est plus complexe que cela - les créateurs de Shorebird ont par exemple dû modifier le moteur de Flutter.</p>
<p>Et justement, en parlant de <strong>solutions</strong>, en voici trois disponibles :</p>
<ul>
<li><a href="https://docs.shorebird.dev/" target="_blank" rel="noopener noreffer">Shorebird</a> pour Flutter.</li>
<li><a href="https://docs.expo.dev/eas-update/introduction/" target="_blank" rel="noopener noreffer">EAS Update</a> pour React Native, par Expo.</li>
<li><a href="https://learn.microsoft.com/en-us/appcenter/distribution/codepush/" target="_blank" rel="noopener noreffer">CodePush</a> pour React Native, par Microsoft.</li>
</ul>
<h2 id="tout-ou-presque">Tout, ou presque</h2>
<p>L&rsquo;<em>Over-the-air update</em> apporte une énorme flexibilité puisqu&rsquo;il est possible de quasiment tout changer, sans même avoir eu à prévoir que nos composants soient configurables à distance. On peut changer du code métier, des composants graphiques, des dépendances, des images. La plupart du temps, c&rsquo;est tout ce qu&rsquo;il nous faut, pas besoin de plus.</p>
<p>Il faut tout de même être conscient des limitations. Certains morceaux de notre application ne peuvent pas changer. C&rsquo;est par exemple le cas du code <strong>natif</strong>. Souvenons-nous, ce code est figé, il n&rsquo;est pas interprété par la machine virtuelle qui fait tourner la technologie cross-plateform. Il ne peut être changé à distance.</p>
<h2 id="cas-dusage">Cas d&rsquo;usage</h2>
<p>L&rsquo;utilisation la plus évidente, et qui apporte aussi le plus de valeur, est <strong>la correction d&rsquo;un problème critique</strong> en production. Il y a un crash au lancement ? Le tunnel d&rsquo;achat ne fonctionne plus ? Impossible pour les utilisateurs de se connecter ? On pourrait imaginer tout ce qui est vital pour l&rsquo;application, et l&rsquo;entreprise qui est derrière.</p>
<p>Avec une mise à jour OTA, on a la capacité de <strong>réagir très vite</strong>. On pousse un correctif, voire on rollback vers une version antérieure qui n&rsquo;avait pas de problème, tout simplement. Comme je le disais dans mon article autour de <a href="https://jordanchapuy.com/posts/2023/08/cynefin-x-user-story-et-si-on-adaptait-le-flow-a-la-complexite/" rel="">Cynefin pour adapter nos réponses en fonction de la complexité</a>, on a besoin d’agir maintenant. On prendra le temps d&rsquo;apporter une meilleure réponse plus tard.</p>
<p>En dehors de la gestion de crise, on peut imaginer des cas pour tester en production. Afin de voir l&rsquo;usage d&rsquo;une nouvelle fonctionnalité. Ou de s&rsquo;assurer qu&rsquo;il n&rsquo;y a aucun problème avec cette nouvelle version - on pourra rollback rapidement (voire automatiquement) s&rsquo;il y a un souci. À surveiller si les solutions proposent de faire un déploiement progressif, ou de la segmentation. Ces cas d&rsquo;usages seront davantage intéressant.</p>
<p>Une équipe qui voudrait s&rsquo;approcher du déploiement continu pourrait être intéressée par des mises à jour OTA. Elle pourrait envoyer une nouvelle version toutes les heures en production par exemple.</p>
<h2 id="coût">Coût</h2>
<p>Abordons maintenant la question du coût (argent et temps) d&rsquo;un tel système. Je vais commencer par le coût en entrée, c&rsquo;est-à-dire, l&rsquo;investissement que l&rsquo;on doit faire la toute première fois pour mettre en place de la mise à jour OTA sur notre application. Bonne nouvelle, le coût est très faible. On <strong>configure facilement et rapidement de l&rsquo;OTA</strong> sur une application, y compris une déjà existante.</p>
<p>Côté Flutter, tout se passera par l&rsquo;outil en ligne de commande que l&rsquo;on doit installer et un petit fichier de configuration. Aucune modification à apporter au projet. Côté React Native, Expo est devenu le framework de référence, il est donc très probable qu&rsquo;il soit utilisé sur le projet. Si c&rsquo;est le cas, utiliser EAS Update reviendra également à une simple configuration. Sinon, il faut migrer le projet vers Expo mais là aussi c&rsquo;est assez simple (et Expo propose d&rsquo;ailleurs un outil de migration automatique).</p>
<p>Vient ensuite le coût du service. Shorebird et Expo ont tout deux <strong>un tier gratuit</strong>, qui permet de tester la solution, et qui est suffisant lorsque l&rsquo;on a une <strong>petite application</strong> ou que c&rsquo;est pour un usage interne. Avec une plus grande base d&rsquo;utilisateurs, on doit passer sur <strong>des plans payant mensuellement</strong>. Et le prix change en fonction du nombre de mise à jour OTA installée dans le mois.</p>
<p>À noter que Expo propose un tier &ldquo;on-demand&rdquo; où l&rsquo;<strong>on paie uniquement en fonction de l&rsquo;usage réel</strong> - un plan qui est donc gratuit chaque mois où l&rsquo;on ne fait aucune mise à jour. Je trouve cela très intéressant pour s&rsquo;ajouter un filet de sécurité sans coût, et de pouvoir le déclencher au moment où il apportera une réelle valeur. Il existe également la possibilité de self-host le service EAS Update.</p>
<p>Le coût est cependant à <strong>relativiser</strong>. Il ne faut pas le regarder seul, il faut le contextualiser avec la nature de l&rsquo;application et les pertes possible d&rsquo;un mal fonctionnement. Si je m&rsquo;appelle Uber et que mon app ne fonctionne plus, chaque heure compte. Chaque minute même. Les utilisateurs qui ont besoin d&rsquo;un VTC ne vont pas attendre que ça se répare, que ça soit déployé sur les store, qu&rsquo;ils l&rsquo;installent, etc. Ils en ont besoin maintenant, et ils vont aller voir ailleurs. La course est donc perdue, l&rsquo;argent entrant aussi.</p>
<p>Je ne connais pas le chiffre d&rsquo;affaires d&rsquo;Uber par heure, mais j&rsquo;imagine qu&rsquo;il est très élevé, et que si on le compare au coût du service, c&rsquo;est très négligeable. C&rsquo;est cela que je veux dire par relativiser. Dans l&rsquo;absolu, le coût de faire une mise à jour par OTA à 200.000 utilisateurs peut paraître élevé, mais mis face au manque à gagner de plusieurs heures voire journées, on obtient un regard différent. Le potentiel chiffre que l&rsquo;on peut sauver est bien supérieur au coût du service.</p>
<h2 id="et-cest-autorisé-">Et c&rsquo;est autorisé ?</h2>
<p>En voilà une bonne question. Une solution qui s&rsquo;apparente à de la magie noire est sûrement interdite par Apple et Google. Eh bien non, il y a un cadre dans lequel on peut faire des mises à jour par OTA. Les solutions comme Shorebird et EAS Update ont été <strong>construites pour respecter les règles</strong> de l&rsquo;App Store et du Google Play.</p>
<p>Il est en effet autorisé de télécharger du code s&rsquo;il est exécuté dans une machine virtuelle ou par un interpréteur. Ajouter ces solutions à notre application n&rsquo;ajoute donc pas de risque de se faire rejeter une soumission.</p>
<p>La contrainte principale sera sur le contenu de la mise à jour : elle ne doit pas être <strong>déceptive</strong> pour l&rsquo;utilisateur. En d&rsquo;autres termes, l&rsquo;application doit continuer de faire ce qui est affiché sur sa page store et doit éviter de changer radicalement.</p>
<blockquote>
<p>[Google Play] An app distributed via Google Play may not modify, replace, or update itself
using any method other than Google Play&rsquo;s update mechanism. Likewise, an app
may not download executable code (such as dex, JAR, .so files) from a
source other than Google Play. <em>This restriction does not apply to code
that runs in a virtual machine or an interpreter</em> where either provides
indirect access to Android APIs (such as JavaScript in a webview or
browser).</p>
</blockquote>
<blockquote>
<p>[App Store] 3.2.2
&hellip; interpreted code may be downloaded to an Application but only so long as such code:
(a) does not change the primary purpose of the Application by providing features or functionality that are inconsistent
with the intended and advertised purpose of the Application as submitted to the App Store,
(b) does not create a store or storefront for other code or applications, and
(c) does not bypass signing, sandbox, or other security features of the OS.</p>
</blockquote>
<p>La mise à jour par OTA est donc une réelle carte à considérer pour se donner davantage d&rsquo;options et mieux <strong>s&rsquo;adapter aux imprévus</strong>.</p>
<hr>
<blockquote>
<p>Série d&rsquo;articles <strong>Mettre à jour une application mobile sans passer par les stores</strong> :</p>
<ul>
<li><a href="https://jordanchapuy.com/posts/2023/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-1-pourquoi" rel="">#1 Pourquoi</a></li>
<li><a href="https://jordanchapuy.com/posts/2023/09/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-2-remote-config-feature-flag" rel="">#2 Remote config, Feature Flag &amp; co</a></li>
<li><a href="https://jordanchapuy.com/posts/2023/12/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-3-backend-for-frontend-bff" rel="">#3 Backend for Frontend (BFF)</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/01/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-4-server-driven-ui" rel="">#4 Server-Driven UI</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/07/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-5-interpreteur-de-code" rel="">#5 Interpréteur de code</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-6-over-the-air-update-ota" rel="">#6 Over-the-air update (OTA)</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/11/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-7-ressources" rel="">#7 Les ressources</a></li>
<li>#8 En résumé, mes options</li>
</ul>
<p>Hors-série :</p>
<ul>
<li>Accélérer le temps de review App Store d&rsquo;une application iOS</li>
<li>Forcer la mise à jour d&rsquo;une application mobile</li>
</ul>
</blockquote>
]]></description></item><item><title>Mettre à jour une application mobile sans passer par les stores - #5 Interpréteur de code</title><link>https://jordanchapuy.com/posts/2024/07/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-5-interpreteur-de-code/</link><pubDate>Wed, 31 Jul 2024 14:50:00 +0100</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2024/07/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-5-interpreteur-de-code/</guid><description><![CDATA[<p>Reprenons le chemin de la modification à distance. Cette fois-ci, plutôt que d&rsquo;envoyer des données plus ou moins enrichies comme on a pu le voir avec des solutions de <a href="https://jordanchapuy.com/posts/2023/09/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-2-remote-config-feature-flag" rel="">Feature Flag</a> ou de <a href="https://jordanchapuy.com/posts/2024/01/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-4-server-driven-ui" rel="">Server-Driven UI</a>, regardons comment envoyer directement des algorithmes et même du code. Après tout, on peut tout envoyer via notre serveur, tant que notre application sait l&rsquo;interpréter.</p>
<h1 id="interpréteur-de-code">Interpréteur de code</h1>
<p>L&rsquo;idée serait d&rsquo;avoir une brique logicielle au sein de l&rsquo;application qui transforme quelque chose de très basique comme du texte en une suite d&rsquo;instructions à exécuter. Ce pourrait même être directement du code. Un tel système apporterait beaucoup de flexibilité, car il permettrait de modifier plus profondément le comportement de l&rsquo;application.</p>
<p>On pourrait par exemple modifier un algorithme, un calcul complexe. On pourrait complètement modifier l&rsquo;apparence d&rsquo;un composant. Voire même définir un tunnel d&rsquo;écrans et de fonctionnalités. J&rsquo;imagine par exemple une utilité pour explorer et tester, une sorte d&rsquo;A/B testing boosté. 99% de l&rsquo;application serait &ldquo;stable&rdquo; (le code est figé, livré à chaque mise à jour, ne change pas), et il y a ce nouveau tunnel, qu&rsquo;on veut tester, et modifier souvent. Puis, dès que l&rsquo;on a des réponses à nos questions, on enlève ce côté dynamique pour l&rsquo;embarquer pleinement dans une mise à jour.</p>
<p>J&rsquo;explore à voix haute, tout ceci est hypothétique : aujourd&rsquo;hui, je n&rsquo;ai pas travaillé avec un tel système. Pour autant, je trouve intéressant d&rsquo;en parler, de voir les possibilités, et ce qui existe.</p>
<p>Et justement, lors de mes recherches, j&rsquo;ai trouvé plusieurs dépendances que l&rsquo;on peut ajouter à notre projet.</p>
<ul>
<li>Côté Swift, il y a <a href="https://github.com/tevelee/Eval" target="_blank" rel="noopener noreffer">Eval</a>.</li>
<li>Pour Kotlin, <a href="https://github.com/s1monw1/KtsRunner" target="_blank" rel="noopener noreffer">KtsRunner</a>.</li>
<li>En Dart, <a href="https://pub.dev/packages/dart_eval" target="_blank" rel="noopener noreffer">dart_eval</a>.</li>
<li>Pour Flutter spécifiquement, <a href="https://pub.dev/packages/flutter_eval" target="_blank" rel="noopener noreffer">flutter_eval</a> et <a href="https://pub.dev/packages/rfw" target="_blank" rel="noopener noreffer">Remote Flutter Widgets</a> dont j&rsquo;ai vu le nom passer plusieurs fois dans ma timeline Twitter.</li>
<li>Du côté de React Native, javascript propose <code>eval()</code> et le constructeur <code>new Function()</code>.</li>
<li>On peut aussi imaginer se créer un meta-langage.</li>
</ul>
<p>Selon le langage et le framework, on a accès à davantage de possibilités. <code>flutter_eval</code> et <code>dart_eval</code> permettent par exemple d&rsquo;envoyer une classe entière en Dart ou un widget, et quasiment comme si on l&rsquo;avait écrit directement dans le code du projet. C&rsquo;est puissant et ça nous apporte beaucoup de flexibilité. À l&rsquo;opposé, en Swift, <code>Eval</code> propose plutôt d&rsquo;interpréter des expressions simples, et de faire du <em>template</em>.</p>
<h1 id="points-dattention">Points d&rsquo;attention</h1>
<p>La grande flexibilité que peut apporter un tel mécanisme vient aussi avec des problématiques qu&rsquo;il faut avoir en tête.</p>
<ul>
<li>Il y a le coût à considérer. Créer un interpréteur ou en intégrer un demandera un certain effort. Il faudra également le tester et confirmer le degré de confiance qu&rsquo;on peut lui accorder.</li>
<li>Il faut déterminer les limitations. Envoyer des expressions n&rsquo;offre pas les mêmes possibilités que d&rsquo;envoyer toute une classe complexe.</li>
<li>Et, élément très important, la sécurité. On ajoute une surface potentielle d&rsquo;attaque. Il est très facile d&rsquo;intercepter une requête HTTP et de changer la réponse. Il ne faudrait pas qu&rsquo;un attaquant s&rsquo;en serve pour injecter du code qui lui permettra de réaliser des actions non autorisées dans l&rsquo;application.</li>
</ul>
<p>Au final, au vu de ces points, je me demande si ce type de mécanisme ne serait pas à restreindre aux équipes internes pour effectuer des changements et des tests rapidement, ou à destination d&rsquo;employés via un store d&rsquo;entreprise / des appareils appartenant à une même flotte.  Mais dans ces cadres, la barrière des stores (Apple et Google) est absente, puisqu&rsquo;on peut déployer et forcer les mises à jour plus facilement via des stores privés.</p>
<p>Ou peut-être qu&rsquo;il faudrait restreindre à des éléments graphiques, qui ne contiennent pas de logique métier.</p>
<p>Je serais très curieux d&rsquo;avoir des retours d&rsquo;expérience pour compléter ma vision. Actuellement, je resterais sceptique : je vois peu d&rsquo;usage justifié au regard des problématiques qui s&rsquo;ajoutent et des autres options que l&rsquo;on a à disposition pour modifier une application à distance.</p>
<hr>
<blockquote>
<p>Série d&rsquo;articles <strong>Mettre à jour une application mobile sans passer par les stores</strong> :</p>
<ul>
<li><a href="https://jordanchapuy.com/posts/2023/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-1-pourquoi" rel="">#1 Pourquoi</a></li>
<li><a href="https://jordanchapuy.com/posts/2023/09/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-2-remote-config-feature-flag" rel="">#2 Remote config, Feature Flag &amp; co</a></li>
<li><a href="https://jordanchapuy.com/posts/2023/12/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-3-backend-for-frontend-bff" rel="">#3 Backend for Frontend (BFF)</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/01/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-4-server-driven-ui" rel="">#4 Server-Driven UI</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/07/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-5-interpreteur-de-code" rel="">#5 Interpréteur de code</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-6-over-the-air-update-ota" rel="">#6 Over-the-air update (OTA)</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/11/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-7-ressources" rel="">#7 Les ressources</a></li>
<li>#8 En résumé, mes options</li>
</ul>
<p>Hors-série :</p>
<ul>
<li>Accélérer le temps de review App Store d&rsquo;une application iOS</li>
<li>Forcer la mise à jour d&rsquo;une application mobile</li>
</ul>
</blockquote>
]]></description></item><item><title>Une introduction à la distribution d’applications iOS</title><link>https://jordanchapuy.com/posts/2024/02/une-introduction-a-la-distribution-applications-ios-certificate-provisioning-profile-ad-hoc-code-signing/</link><pubDate>Mon, 12 Feb 2024 14:00:00 +0100</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2024/02/une-introduction-a-la-distribution-applications-ios-certificate-provisioning-profile-ad-hoc-code-signing/</guid><description><![CDATA[<p><em>Certificate</em>, <em>Provisioning Profile</em>, <em>Ad-Hoc</em>, <em>Distribution</em>, <em>Code signing</em>, &hellip; Bienvenue dans le monde complexe de la distribution d’applications iOS. C’est un sujet qui peut dérouter, et malheureusement, on s’y confronte dès lors que l’on veut distribuer une application.</p>
<p>Peu importe le framework utilisé (<em>&ldquo;je fais du natif iOS&rdquo;, &ldquo;je fais du cross-plateforme Flutter, React Native&rdquo;</em>), et quelque soit le type de poste (<em>&ldquo;j&rsquo;archive avec mon macbook&rdquo;, &ldquo;c&rsquo;est le runner de ma CI qui archive&rdquo;</em>), on n&rsquo;y échappe pas.</p>
<p>Cette mécanique imposée par Apple n&rsquo;a pas son équivalent côté Android ou sur le web. Pas étonnant que ça provoque quelques maux de têtes au premier contact. Ça arrive même à des développeurs iOS plus expérimentés. Mais comme tout, ça s&rsquo;apprend.</p>
<p>Une fois que l&rsquo;on a compris les rouages, on est beaucoup plus à l&rsquo;aise pour résoudre les problèmes qui gravitent autour de la distribution d&rsquo;applications iOS. Et c&rsquo;est là que j&rsquo;interviens aujourd&rsquo;hui. Je vais vulgariser certains concepts de base pour, je l&rsquo;espère, permettre de mieux comprendre les problèmes qui surviennent et trouver plus facilement des solutions.</p>
<p>Je démarre en douceur, en grattant un peu la surface, ce qui est visible par tous. On plongera en profondeur et avec un peu plus de technique ensuite. Ça va bien se passer.</p>
<h1 id="les-canaux-de-distribution">Les canaux de distribution</h1>
<p>Regardons tout d&rsquo;abord les différentes possibilités à notre disposition pour utiliser une application iOS que l&rsquo;on développe soi-même, et les spécificités de chacune d&rsquo;elles.</p>
<ul>
<li><strong>Simulateur</strong></li>
</ul>
<p>Depuis mon poste, je peux installer l&rsquo;application en cours de développement sur un simulateur et l&rsquo;utiliser comme bon me semble. C&rsquo;est ce qu&rsquo;un développeur fait en continu. C&rsquo;est rapide, on peut debugger.</p>
<ul>
<li><strong>Appareil</strong></li>
</ul>
<p>Depuis mon poste, je peux installer l&rsquo;application en cours de développement sur un appareil relié à ma machine (câble ou WiFi). C&rsquo;est ce qu&rsquo;un développeur va faire également pour tester l&rsquo;application sur un vrai appareil. On peut également debugger. L&rsquo;application expire au bout d&rsquo;un temps.</p>
<ul>
<li><strong>Store de bêta alternatif</strong></li>
</ul>
<p>Je peux distribuer une version bêta de mon application sur des stores comme Firebase Distribution, Appaloosa, App Center. C&rsquo;est ce que l&rsquo;on utilise souvent pour déployer en continu les incréments réalisés, pour que l&rsquo;équipe interne puisse installer les différentes versions de l&rsquo;application sur leurs téléphones.</p>
<p>Il faut enregistrer l&rsquo;UUID de chaque appareil (maximum 100) et inviter l&rsquo;utilisateur sur ce store alternatif. L&rsquo;application expire au bout d&rsquo;un temps.</p>
<ul>
<li><strong>TestFlight (interne)</strong></li>
</ul>
<p>Je peux distribuer une version bêta de mon application sur TestFlight en mode &ldquo;tests internes&rdquo;. C&rsquo;est une alternative intéressante aux stores bêta alternatifs car avec TestFlight, on ne s&rsquo;embête pas à enregistrer des appareils.</p>
<p>Il faut seulement inviter les utilisateurs sur TestFlight, avec un maximum de 100 personnes. L&rsquo;application expire au bout de 90 jours.</p>
<ul>
<li><strong>TestFlight (externe)</strong></li>
</ul>
<p>Je peux distribuer une version bêta de mon application sur TestFlight en mode &ldquo;tests externes&rdquo;. C&rsquo;est LA solution pour faire des tests à grandes échelles avec des utilisateurs externes. Il suffit de les inviter ou de leur donner un lien pour qu&rsquo;ils rejoignent le test.</p>
<p>On peut monter jusqu&rsquo;à 10.000 personnes. Apple effectue une revue de l&rsquo;app à chaque nouvelle version. Petit avantage intéressant, on peut passer une version directement en prod (App Store) si on est satisfait.</p>
<ul>
<li><strong>App Store</strong></li>
</ul>
<p>Je peux distribuer l&rsquo;application finale sur l&rsquo;App Store. Tous les utilisateurs y auront accès, sans contrainte, limite ou enregistrement à effectuer. C&rsquo;est la prod ! C&rsquo;est par l&rsquo;App Store que les utilisateurs classiques découvrent et installent toutes leurs applications.</p>
<ul>
<li><strong>Store de prod interne</strong></li>
</ul>
<p>Je peux distribuer l&rsquo;application finale sur un store interne à mon entreprise. C&rsquo;est l&rsquo;option que l&rsquo;on va choisir si on veut déployer une application réservée à ses salariés - elle doit rester privée, on veut contrôler qui peut l&rsquo;installer.</p>
<p>Un exemple : les vendeurs d&rsquo;une grande enseigne qui auraient une application spéciale sur leurs iPads pour gérer les stocks du magasin et la caisse. On ne veut pas la voir sur l&rsquo;App Store. L&rsquo;application expire au bout d&rsquo;un temps.</p>
<ul>
<li><strong>Store de prod alternatif</strong></li>
</ul>
<p>Je peux distribuer l&rsquo;application finale sur un store alternatif. J&rsquo;en parlais dans <a href="https://jordanchapuy.com/posts/2024/02/actualites-news-applications-mobiles-ios-android-flutter-apple-google" rel="">le récap des news autour des applications mobile</a>, Apple va permettre la création d&rsquo;autres stores pour installer des applications de production. Je ne m&rsquo;étalerais pas plus sur ce sujet ici, c&rsquo;est encore trop récent, je n&rsquo;ai pas toutes les informations.</p>
<p><em>J’ajoute une précision. Quand je dis “l’application expire au bout d’un temps”, c’est à cause des <code>Provisionning Profiles</code> ou d’une limite spécifique au canal de distribution. On peut obtenir une application qui “n’expire jamais” si on pousse des nouvelles versions avant les dates limites.</em></p>
<h1 id="les-types-de-distribution-selon-apple">Les types de distribution selon Apple</h1>
<p>Descendons d&rsquo;un cran en profondeur, je vais commencer à utiliser des termes techniques d&rsquo;Apple. On a vu qu&rsquo;il y avait beaucoup de possibilités pour installer une application iOS, mais Apple les regroupe selon 4 types de distribution. Ces termes seront utiles pour créer les bons <code>Provisionning Profiles</code>.</p>
<ul>
<li>
<p><strong>Development</strong>. On installe l&rsquo;application directement sur un appareil, et celui-ci doit être relié à un Mac.</p>
</li>
<li>
<p><strong>Ad-Hoc</strong>. On archive l&rsquo;application (on crée un binaire) afin de le distribuer sur des stores de bêta alternatifs (Firebase, Appaloosa, App Center, &hellip;).</p>
</li>
<li>
<p><strong>App Store Connect</strong>. On archive l&rsquo;application afin de la distribuer sur les stores officiels d&rsquo;Apple (App Store et Test Flight).</p>
</li>
<li>
<p><strong>In-House</strong>. On archive l&rsquo;application afin de la distribuer sur un store de production interne.</p>
</li>
</ul>
<p>J&rsquo;en profite pour également introduire la notion de <code>Certificate</code>. On va se pencher sur les deux types qui sont intéressants dans notre cas.</p>
<ul>
<li>
<p><strong>Development</strong>. C&rsquo;est utile lorsque l&rsquo;on veut signer l&rsquo;application pour l&rsquo;installer directement sur un appareil.</p>
</li>
<li>
<p><strong>Distribution</strong>. C&rsquo;est utile dès lors que l&rsquo;on veut signer l&rsquo;application pour la distribuer, peu importe comment (Ad-Hoc, App Store, In-House) et où (store de bêta, App Store, TestFlight, store interne, &hellip;).</p>
</li>
</ul>
<p><em>À noter qu&rsquo;il existe ces mêmes types pré-fixés par &ldquo;iOS&rdquo; ou &ldquo;Mac&rdquo;. C&rsquo;est la même chose, sauf qu&rsquo;ils contraignent à leurs plateformes.</em></p>
<h1 id="les-ingrédients">Les ingrédients</h1>
<p>Maintenant, entrons dans le vif du sujet, allons dans la profondeur. La <a href="https://developer.apple.com/account/resources" target="_blank" rel="noopener noreffer">page ressources</a> du compte développeur regroupe tous les éléments nécessaires pour distribuer une application. On y retrouve ceux qui sont existants, expirés, et on peut en créer de nouveaux.</p>
<p>Tous ces éléments sont créés sur notre compte développeur, ce qui a deux conséquences. Ils peuvent servir à toutes les applications sous la propriété de ce compte - cool. Les limites de création concernent l&rsquo;ensemble du compte, ce n&rsquo;est pas par application - pas cool.</p>
<ul>
<li><strong>Devices</strong></li>
</ul>
<p>C&rsquo;est la liste des appareils enregistrés sur notre compte développeur. Il est nécessaire d&rsquo;ajouter ici l&rsquo;UUID d&rsquo;un appareil sur lequel on souhaite installer l&rsquo;application en direct ou distribuer sur un store de bêta (donc des distributions de type <code>Development</code> et <code>Ad-Hoc</code>).</p>
<p>La limite est de 100 appareils (pour tout le compte !). Je n&rsquo;ai qu&rsquo;une seule occasion par an de supprimer des appareils : le mois précédant la date anniversaire de la souscription au <code>Apple Developer Program</code>. Apple nous le rappelle quand on approche de cette période.</p>
<ul>
<li><strong>Identifiers</strong></li>
</ul>
<p>Chaque application possède un identifiant unique sous la forme <code>com.example.app</code> qu&rsquo;il faut enregistrer dans cette section. On y associe également des <em>Capabilities</em> - des autorisations d&rsquo;utiliser certains services (Push Notifications, HomeKit, Siri, &hellip;).</p>
<p>Pour une même application, on peut être amené à créer plusieurs <code>Identifiers</code>. Par exemple pour différencier des environnements (<code>com.example.app</code> et <code>com.example.app.staging</code>). L&rsquo;intérêt sera de pouvoir installer les deux applications sur un même téléphone.</p>
<ul>
<li><strong>Certificates</strong></li>
</ul>
<p>Dès que l&rsquo;on veut installer une application sur un appareil ou la distribuer, il faut signer l&rsquo;archive (le binaire) de l&rsquo;application. C&rsquo;est là qu&rsquo;entre en jeu le certificat. Il indique que cette application provient de notre compte.</p>
<p>En général, chaque développeur crée son certificat de type <code>Development</code>, afin de pouvoir installer l&rsquo;application en cours de développement sur son appareil. Et il faut au moins générer un certificat de type <code>Distribution</code> pour déployer l&rsquo;application sur des stores.</p>
<p>Un certificat est lié au compte développeur, et non à une application - un seul certificat de <code>Distribution</code> peut donc signer toutes nos applications. D&rsquo;ailleurs, on est limité à un maximum de 3 certificats de type <code>Distribution</code>. Il sera intéressant d’en générer un second lorsque l’on s’approche de la date d’expiration du premier. Ou parce que l’on veut le donner à une équipe externe et pouvoir le révoquer facilement sans nous impacter.</p>
<p>Attention, on ne peut télécharger le certificat contenant la clé privée de signature qu&rsquo;au moment de sa création. La machine qui signe les applications doit avoir le certificat avec la clé privée dans son keychain.</p>
<p>Un certificat expire au bout d&rsquo;un an. Une application ne se lancera pas si le certificat associé est expiré ou invalide. Il faudra distribuer une nouvelle version avec tous les éléments valides. L’App Store n’est pas concerné par ce problème.</p>
<ul>
<li><strong>Provisioning Profiles</strong></li>
</ul>
<p>Un profil est la glu qui lie tous les éléments. On associe un <code>Identifier</code>, un <code>Certificate</code>, un type de distribution et on sélectionne des <code>devices</code>. Le profil permettra d&rsquo;indiquer à l&rsquo;appareil si l&rsquo;application peut être installée et à quels services elle a accès.</p>
<p>On en crée autant qu&rsquo;il y a d&rsquo;applications, de type de distribution (<code>Development</code>, <code>Ad-Hoc</code>, &hellip;) et d&rsquo;environnement (si on a plusieurs <code>Identifiers</code>). On se retrouve rapidement à en avoir une grande quantité.</p>
<p>Un profil expire au bout d&rsquo;un an, et devient invalide si le certificat auquel il est associé expire. La machine qui compile l&rsquo;application doit avoir les bons profils installés.</p>
<p>Une application ne se lancera pas si le profil associé est expiré ou invalide. Il faudra distribuer une nouvelle version avec tous les éléments valides. L’App Store n’est pas concerné par ce problème.</p>
<ul>
<li><strong>API Keys</strong></li>
</ul>
<p>Bonus. La clé d&rsquo;API permet de s&rsquo;identifier auprès d&rsquo;Apple pour utiliser des services de l&rsquo;App Store Connect. Ce sera utile pour les runners d&rsquo;une CI lorsqu&rsquo;une commande interagit avec le compte développeur (ex: récupérer un <code>profile</code>) ou avec l&rsquo;App Store (ex: soumettre une application).</p>
<p>La génération des clés d&rsquo;API se fera sur l&rsquo;<a href="https://appstoreconnect.apple.com/" target="_blank" rel="noopener noreffer">App Store Connect</a>, onglet <em>Users and Access</em>, et non depuis le compte développeur.</p>
<h1 id="la-mayonnaise">La mayonnaise</h1>
<p>On a tous les ingrédients nécessaires pour faire monter une belle mayonnaise, il n&rsquo;y a plus qu&rsquo;à les assembler. Je vais illustrer avec plusieurs scénarios qui peuvent arriver tout le long d&rsquo;une année.</p>
<ul>
<li><strong>On commence une nouvelle application</strong></li>
</ul>
<p>On enregistre un <code>Identifier</code> pour notre application et on ajoute les différents appareils de l&rsquo;équipe dans <code>Devices</code>. Chaque développeur génère son <code>Certificate (Development)</code> puis on crée un <code>Provisioning Profile (Development)</code> (associant les appareils de l&rsquo;équipe et les certificats des développeurs).</p>
<p>Pour pouvoir déployer les incréments sur un store de bêta, on génère un <code>Certificate (Distribution)</code> puis un <code>Provisioning Profile (Ad-Hoc)</code> en cochant bien tous les appareils de l&rsquo;équipe.</p>
<p>Pour pouvoir déployer sur TestFlight et sur l&rsquo;App Store, je vais créer un <code>Provisioning Profile (App Store)</code>. On a déjà le bon certificat.</p>
<ul>
<li><strong>Un certificat expiré</strong></li>
</ul>
<p>On génère un nouveau <code>Certificate</code> du même type puis modifie tous les <code>Provisioning Profiles</code> qui étaient associés à l&rsquo;ancien certificat pour sélectionner le nouveau.</p>
<ul>
<li><strong>Un profil a expiré ou est invalide</strong></li>
</ul>
<p>On modifie le <code>Provisioning Profile</code> pour le re-créer. Pas besoin de le supprimer, on peut cliquer sur &ldquo;Edit&rdquo; et le sauvegarder à nouveau.</p>
<ul>
<li><strong>Il faut ajouter un nouvel appareil</strong></li>
</ul>
<p>On ajoute l&rsquo;appareil dans la liste des <code>Devices</code> puis on modifie les <code>Provisioning Profiles</code> pour cocher l&rsquo;appareil nouvellement ajouté. Attention, cet appareil ne pourra installer que les prochains builds de l&rsquo;application (qui seront archivées et signés avec ce nouveau profil).</p>
<ul>
<li><strong>On veut distinguer un nouvel environnement</strong></li>
</ul>
<p>On suit quasiment les mêmes étapes que la création d&rsquo;un nouveau projet avec le nouvel <code>Identifier</code> que l&rsquo;on va créer. Il n&rsquo;y a pas besoin de générer de <code>Certificates</code> ni de saisir des <code>Devices</code>.</p>
<ul>
<li><strong>Un nouveau développeur rejoint l&rsquo;équipe</strong></li>
</ul>
<p>Il va ajouter son appareil dans les <code>Devices</code>, générer son <code>Certificate (Development)</code> puis modifier le <code>Provisioning Profile (Development)</code> pour y cocher son certificat et son appareil. Il modifiera aussi le <code>Provisioning Profile (Ad-Hoc)</code> pour cocher son appareil.</p>
<p><em>Remarques : À chaque création ou modification, on pensera à installer la clé privée des certificats et les profils sur les machines qui en auront besoin. Certaines étapes peuvent être automatisées par des outils tels que Fastlane et Codemagic, ou par Xcode.</em></p>
<h1 id="les-comptes-et-programmes-apple">Les comptes et programmes Apple</h1>
<p>Je termine cette épopée en remontant à la surface. Respirons, c&rsquo;est presque terminé. Il ne nous reste plus qu&rsquo;à jeter un coup d&rsquo;oeil sur les types de compte qui existent et ce qu&rsquo;ils permettent.</p>
<ul>
<li><strong>Compte développeur</strong></li>
</ul>
<p>On s&rsquo;enregistre en créant/utilisant une Apple ID. C&rsquo;est gratuit et accessible à tous. On a accès aux outils comme Xcode et les simulateurs. On peut installer l&rsquo;application sur un appareil relié à notre poste. On ne fait que du développement, aucune distribution possible. On ne peut pas créer de <code>Certificate</code>, de <code>Profile</code> ou autre.</p>
<ul>
<li><strong>Apple Developer Program</strong></li>
</ul>
<p>On souscrit au programme pour 99$ par an, en tant qu&rsquo;individu ou entreprise. Notre compte développeur aura accès à la distribution <code>Ad-Hoc</code> et <code>App Store</code>. On aura aussi accès à l&rsquo;App Store Connect. C&rsquo;est le programme auquel on souscrit dans une immense majorité des cas. On peut tout faire sauf déployer sur un store interne.</p>
<ul>
<li><strong>Apple Developer Enterprise Program</strong></li>
</ul>
<p>On souscrit au programme pour 299$ par an en tant que grande entreprise. Notre compte développeur aura accès à la distribution <code>In-House</code> - c&rsquo;est seulement pour déployer sur un store interne. L&rsquo;accès à ce programme est contraint par plusieurs conditions et nécessite une vérification d&rsquo;Apple. On doit avoir un réel besoin auquel le programme classique ne peut répondre.</p>
<h1 id="quelques-ressources">Quelques ressources</h1>
<p>Petit cadeau de fin, j&rsquo;ai fouillé les internets d&rsquo;Apple pour faire remonter des liens utiles. Les voici :</p>
<ul>
<li><a href="https://developer.apple.com/account" target="_blank" rel="noopener noreffer">Developer account</a></li>
<li><a href="https://developer.apple.com/account/resources" target="_blank" rel="noopener noreffer">Developer account - Resources</a></li>
<li><a href="https://help.apple.com/xcode/mac/current/#/dev5a825a1ca" target="_blank" rel="noopener noreffer">Run an app on a device</a></li>
<li><a href="https://help.apple.com/xcode/mac/current/#/devac02c5ab8" target="_blank" rel="noopener noreffer">Distribution overview</a></li>
<li><a href="https://developer.apple.com/testflight/" target="_blank" rel="noopener noreffer">TestFlight</a></li>
<li><a href="https://appstoreconnect.apple.com/" target="_blank" rel="noopener noreffer">App Store Connect</a></li>
<li><a href="https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api" target="_blank" rel="noopener noreffer">Creating API Keys for App Store Connect API</a></li>
<li><a href="https://developer.apple.com/programs/" target="_blank" rel="noopener noreffer">Apple Developer Program</a></li>
<li><a href="https://developer.apple.com/programs/enterprise/" target="_blank" rel="noopener noreffer">Apple Developer Enterprise Program</a></li>
</ul>
]]></description></item><item><title>Mettre à jour une application mobile sans passer par les stores - #4 Server-Driven UI</title><link>https://jordanchapuy.com/posts/2024/01/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-4-server-driven-ui/</link><pubDate>Thu, 04 Jan 2024 18:20:00 +0100</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2024/01/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-4-server-driven-ui/</guid><description><![CDATA[<p>Et si on poussait le concept de <a href="https://jordanchapuy.com/posts/2023/12/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-3-backend-for-frontend-bff" rel="">Backend for Frontend</a> encore plus loin, à l’extrême ? Un peu à l&rsquo;image de l&rsquo;Extreme Programming qui pousse des pratiques dans leurs retranchements. Qu’est-ce que ça pourrait donner pour notre histoire de backend et de front mobile ? Pourrait-on déporter jusqu&rsquo;à l&rsquo;UI de l&rsquo;application ?</p>
<p>De base, notre backend stocke des données, communique avec d&rsquo;autres services et applique de nombreuses règles métiers. Notre application, elle, va envoyer une requête pour récupérer des informations, les traiter, appliquer d&rsquo;autres règles, puis construire un rendu visuel avec divers composants UI (j&rsquo;ai une bannière, ensuite un carrousel avec trois images, puis une liste d&rsquo;articles).</p>
<p>On a vu qu&rsquo;on pouvait ajouter des traitements spécifiques au mobile en ayant un <a href="https://jordanchapuy.com/posts/2023/12/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-3-backend-for-frontend-bff" rel="">Back for Frontend</a>. Ça nous aide en déportant certaines règles côté backend, en agrégeant des données de plusieurs sources, en facilitant certains changements. Reste encore à construire le rendu visuel côté application.</p>
<p>On en arrive au cran d&rsquo;après. Bienvenue dans le <strong>Server-Driven UI</strong>.</p>
<h1 id="je-te-dis-comment-afficher">Je te dis comment afficher</h1>
<p>Avec du Server-Driven UI (aussi appelé Server-Driven Rendering, Backend-Driven UI, &hellip;), il y a un backend qui va à la fois <strong>retourner des données ET indiquer comment les présenter</strong>. Une partie de la construction de l&rsquo;interface graphique (du front mobile) est déportée côté backend.</p>
<p>Qu&rsquo;est-ce que ça veut dire, construire l&rsquo;interface ? Eh bien, le backend indique les <strong>composants</strong> à afficher (une bannière, un carrousel, une liste d&rsquo;éléments, une image, &hellip;) directement renseignés avec les <strong>données associées</strong>. De fait, la <strong>composition</strong> de l&rsquo;écran est aussi gérée (j&rsquo;ai d&rsquo;abord la bannière, ensuite le carrousel, &hellip;). Et il pourrait aussi <strong>configurer</strong> les composants (le texte de la carte est bleu, la police de 16pt, &hellip;), les <strong>actions</strong> lorsque l&rsquo;on tape sur un élément.</p>
<p>La réponse à une requête sera beaucoup plus riche. Un exemple au format JSON :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="s2">&#34;Accueil&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;content&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;carousel&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;content&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;image&#34;</span><span class="p">:</span> <span class="s2">&#34;https://monserveur.com/img/001.jpg&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;Arthur&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;color&#34;</span><span class="p">:</span> <span class="s2">&#34;#FFFFFF&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="p">},</span>
</span></span><span class="line"><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;image&#34;</span><span class="p">:</span> <span class="s2">&#34;https://monserveur.com/img/002.jpg&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;Perceval&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;color&#34;</span><span class="p">:</span> <span class="s2">&#34;#FFFFFF&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="p">},</span>
</span></span><span class="line"><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;image&#34;</span><span class="p">:</span> <span class="s2">&#34;https://monserveur.com/img/003.jpg&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;Lancelot&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;color&#34;</span><span class="p">:</span> <span class="s2">&#34;#FFFFFF&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;identifier&#34;</span><span class="p">:</span> <span class="s2">&#34;list&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;content&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="s2">&#34;Les personnages&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;En découvrir plus sur les personnages&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;details&#34;</span><span class="p">:</span> <span class="s2">&#34;88026897-3fcb-4de8-af77-9aeb76d1e8a1&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="p">},</span>
</span></span><span class="line"><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="s2">&#34;Les secrets de tournage&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;Mystère et magie !&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;details&#34;</span><span class="p">:</span> <span class="s2">&#34;1da6005c-1f57-4c95-bb1a-6fb3b3a1bde7&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>On obtient donc un nouveau moyen de mettre à jour une application mobile sans passer par les stores. On peut <strong>contrôler la construction de l&rsquo;affichage à distance</strong>. <a href="https://jordanchapuy.com/posts/2023/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-1-pourquoi" rel="">Ça nous intéresse</a> car ça nous ouvre des portes pour expérimenter, pour changer plus vite.</p>
<p>Tout cela implique <strong>un développement côté serveur et côté application</strong>.</p>
<ul>
<li>Côté serveur. Il y a une brique / un service / un backend qui construit cette réponse plus complexe. Qui doit avoir cette logique de présentation des données.</li>
<li>Côté application mobile. Il faut créer chaque composant et il faut une brique qui interprète la réponse du serveur pour la traduire dans les composants correspondants.</li>
</ul>
<p>Et vu que c&rsquo;est à notre portée, on peut aller <strong>aussi loin que nécessaire</strong> pour répondre à notre besoin. On peut avoir une présentation plutôt simple. Le serveur indiquerait seulement des composants à afficher avec leurs données. Ou au contraire, on peut pousser la configuration en détaillant des tailles de texte, des couleurs, des alignements, etc.</p>
<p>On a également le choix d&rsquo;appliquer ce concept dans les parties de l&rsquo;application qui nous intéressent. On peut avoir du Server-Driven UI <strong>uniquement sur une sous-partie de l&rsquo;application</strong>. Ce n&rsquo;est pas structurant au point de nécessiter d&rsquo;en avoir partout. Mais on peut le faire, s&rsquo;il y a le besoin. On adapte !</p>
<h2 id="quelques-cas---exemples">Quelques cas - exemples</h2>
<p>Pour illustrer et donner de l&rsquo;inspiration, voici des cas qui existent en production sur des applications grand public.</p>
<p><strong>Une campagne de satisfaction</strong>. Sous la forme d&rsquo;un simple formulaire, avec une suite de questions et plusieurs formats de réponses (choix multiple, choix unique, champs de texte libre). La complexité technique et fonctionnelle est faible. Il ne s&rsquo;agit que de donner des questions et d&rsquo;indiquer sous quelle forme on peut y répondre. Il y a un besoin de déclencher une campagne à n&rsquo;importe quel moment et de moduler le contenu.</p>
<p><strong>Un quizz</strong>. On est dans le même ordre d&rsquo;idées, c&rsquo;est au final une sorte de formulaire mais présenté sous une autre forme. Ici, le besoin est d&rsquo;avoir un parcours de questions qui change régulièrement, sans pour autant faire de mise à jour.</p>
<p><strong>Un onboarding</strong>. On entre dans un parcours bien plus complexe et lourd. C&rsquo;est une succession d&rsquo;écrans avec de nombreuses possibilités comme des formulaires, des listes, des présentation de CGU, de l&rsquo;upload de fichier, de la visualisation d&rsquo;images, etc. Les formulaires sont complexes, contiennent des règles de validation, possèdent plusieurs formes (champs libres, choix multiple, champs numéro de téléphone, &hellip;). On peut ajouter des boutons et des popups d&rsquo;aide / assistance.  Bref, un parcours complètement modulable car il y a un fort besoin de changement. À l&rsquo;autre bout, un back-office existe pour configurer tout cela.</p>
<p><strong>Une page d&rsquo;accueil</strong>. Pas de parcours mais une composition de page qui nécessite d&rsquo;être très modulable. Un jour une simple liste, un autre jour une mise en avant avec une bannière et un el suivi de la liste. Parfois des raccourcis, des cartes d&rsquo;action rapide. D&rsquo;autres fois des rappels. Et demain, un peu de tout ça en même temps. D&rsquo;ailleurs, on expérimente facilement ce qui marche le mieux en changeant à distance l&rsquo;interface.</p>
<p><strong>Un fil de contenu</strong>. Dès lors que le contenu est très dynamique, sa présentation l&rsquo;est aussi. On a besoin d&rsquo;adapter les formats.</p>
<h2 id="bénéfices">Bénéfices</h2>
<p>Outre la gestion de l&rsquo;affichage déporté sur un serveur, on peut espérer obtenir d&rsquo;autres avantages grâce au Server-Driven UI.</p>
<p>Déjà, et c&rsquo;est ce qui nous intéressait le plus par rapport à notre histoire, à <a href="https://jordanchapuy.com/posts/2023/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-1-pourquoi" rel="">cette série d&rsquo;articles</a>, on peut changer de nouveaux éléments de notre application mobile sans devoir passer par les stores : l&rsquo;interface graphique.</p>
<p>Et on est plutôt ravi de cette possibilité. On va pouvoir <strong>changer à distance</strong> plus profondément l&rsquo;application, on va pouvoir apporter des changements et des corrections plus rapidement aux utilisateurs. On aura plus de contrôle.</p>
<p>On facilite également l&rsquo;<strong>expérimentation</strong>, l&rsquo;A/B Testing. Pas besoin de <a href="https://jordanchapuy.com/posts/2023/09/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-2-remote-config-feature-flag" rel="">Feature Flag</a>, c&rsquo;est un serveur qui génère la composition de l&rsquo;écran. C&rsquo;est déjà de la configuration à distance. On peut donc dès maintenant expérimenter.</p>
<p>Si plusieurs plateformes consomment notre serveur, on gagne une unification des interfaces. Le serveur devient <strong>une source de vérité unique</strong>, les applications clientes ne feront qu&rsquo;appliquer la présentation reçue. On a plus facilement une cohérence entre différentes plateformes. Le changement de l&rsquo;affichage ne se fera qu&rsquo;à un seul endroit.</p>
<h2 id="points-dattention">Points d&rsquo;attention</h2>
<p>Comme d&rsquo;habitude, rien n&rsquo;est magique ou parfait. Le Server-Driven UI ne fait pas exception.</p>
<p>Je commence par enfoncer une porte ouverte. Si on veut que notre serveur retourne un nouveau composant, ou une nouvelle configuration par exemple, il faut le code de notre application puisse l&rsquo;<strong>interpréter</strong>. Il faut donc soumettre une mise à jour de l&rsquo;application pour gérer ces nouveaux cas. Comme si on ajoutait une nouvelle <a href="https://jordanchapuy.com/posts/2023/09/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-2-remote-config-feature-flag" rel="">Feature Flag</a>.</p>
<p>Je continue avec une autre porte voisine, les versions. Il faut garder en tête que dans la nature, il y a possiblement une grande variété de versions de notre application. Eh oui, pour rappel, <a href="https://jordanchapuy.com/posts/2023/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-1-pourquoi" rel="">rien n&rsquo;oblige un utilisateur à mettre à jour une application mobile</a>. Il la fera peut-être rapidement, ou dans une semaine, ou jamais.</p>
<p>On a donc une problématique de <strong>rétrocompatibilité</strong>. Admettons qu&rsquo;on ajoute un nouveau composant et qu&rsquo;on ait une nouvelle version de l&rsquo;application qui le gère, comment ça se passe pour les anciennes applications ? On peut versionner nos composants. On peut créer un mécanisme de mise à jour forcée. On peut ignorer. On a plusieurs options, mais il faut y penser.</p>
<p>Le Server-Driven UI, c&rsquo;est également une <strong>couche supplémentaire</strong> dans notre système. Ça vient avec son lot de complexité, de besoin de maintenance, de debug, etc. Et ça requiert un <strong>investissement à l&rsquo;entrée</strong>. Il y a un coût de développement plus élevé au début pour mettre en place les différentes briques et composants pour que tout fonctionne.</p>
<p>Je pense aussi à la <strong>sécurité</strong>. La surface d&rsquo;attaque de l&rsquo;application est augmentée puisqu&rsquo;elle se base davantage sur des <strong>instructions extérieures</strong>. Il est facile de modifier à la volée une réponse HTTP. Par exemple, si le serveur indique des intentions de navigation ou d&rsquo;action, l&rsquo;application devrait peut-être vérifier que l&rsquo;utilisateur a bien le droit de le faire.</p>
<h2 id="pour-se-lancer">Pour se lancer</h2>
<p>Le sujet du Server-Driven UI étant vaste et complexe, on peut chercher à en apprendre plus en s&rsquo;inspirant de retours d&rsquo;expériences de grands noms qui en font ou qui en ont fait de manière poussée : AirBnb, Instagram, Lyft, Reddit, Square.</p>
<p>On peut aussi regarder du côté de frameworks qui existent déjà. En faisant une rapide recherche, je tombe sur <a href="https://github.com/divkit/divkit" target="_blank" rel="noopener noreffer">DivKit</a> et <a href="https://github.com/ZupIT/beagle" target="_blank" rel="noopener noreffer">beagle</a> qui proposent des solutions à la fois côté serveur et côté client iOS, Android, web. J&rsquo;avais également repéré <a href="https://pub.dev/packages/rfw" target="_blank" rel="noopener noreffer">rfw (Remote Flutter Widget)</a>, mais qui me semble d&rsquo;ailleurs plus proche d&rsquo;un interpréteur de code. On le verra peut-être dans l&rsquo;épisode suivant !</p>
<hr>
<blockquote>
<p>Série d&rsquo;articles <strong>Mettre à jour une application mobile sans passer par les stores</strong> :</p>
<ul>
<li><a href="https://jordanchapuy.com/posts/2023/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-1-pourquoi" rel="">#1 Pourquoi</a></li>
<li><a href="https://jordanchapuy.com/posts/2023/09/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-2-remote-config-feature-flag" rel="">#2 Remote config, Feature F &amp; co</a></li>
<li><a href="https://jordanchapuy.com/posts/2023/12/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-3-backend-for-frontend-bff" rel="">#3 Backend for Frontend (BFF)</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/01/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-4-server-driven-ui" rel="">#4 Server-Driven UI</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/07/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-5-interpreteur-de-code" rel="">#5 Interpréteur de code</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-6-over-the-air-update-ota" rel="">#6 Over-the-air update (OTA)</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/11/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-7-ressources" rel="">#7 Les ressources</a></li>
<li>#8 En résumé, mes options</li>
</ul>
<p>Hors-série :</p>
<ul>
<li>Accélérer le temps de review App Store d&rsquo;une application iOS</li>
<li>Forcer la mise à jour d&rsquo;une application mobile</li>
</ul>
</blockquote>
]]></description></item><item><title>Mettre à jour une application mobile sans passer par les stores - #3 Backend for Frontend (BFF)</title><link>https://jordanchapuy.com/posts/2023/12/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-3-backend-for-frontend-bff/</link><pubDate>Fri, 22 Dec 2023 19:05:00 +0100</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2023/12/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-3-backend-for-frontend-bff/</guid><description><![CDATA[<p>De nos jours, il est rare de trouver une application qui ne communique pas du tout avec l&rsquo;extérieur. <strong>La majorité des applications</strong> que l&rsquo;on utilise <strong>font des requêtes vers un ou plusieurs serveurs</strong> - pour demander des données, les afficher dynamiquement, et pour en envoyer.</p>
<p>J&rsquo;ai fait le test avec mon téléphone, j&rsquo;ai eu du mal à trouver une application qui ne faisait aucune requête (en tout cas en apparence, je n&rsquo;en suis même pas sûr à 100%). J&rsquo;ai la calculatrice qui vit sa vie dans son coin.</p>
<p>Pourquoi je raconte ça ? Parce que ces applications font très probablement des requêtes <strong>vers un serveur qui leur appartient</strong>. En d&rsquo;autres termes, l&rsquo;équipe, le département, ou l&rsquo;entreprise qui gère le développement de l&rsquo;application est également responsable du serveur.</p>
<p>Dans l&rsquo;épisode précédent, on a vu qu&rsquo;<a href="https://jordanchapuy.com/posts/2023/09/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-2-remote-config-feature-flag" rel="">une configuration à distance permettait de changer le comportement d&rsquo;une application mobile</a>. Et que la configuration à distance, ce pouvait être simplement un fichier JSON ou une API qui exposait quelques valeurs.</p>
<p>De là à faire le rapprochement entre les données envoyées par nos serveurs et la possibilité de changer le comportement d&rsquo;une application mobile à distance, il n&rsquo;y a vraiment qu&rsquo;un petit pas. Alors faisons-le !</p>
<h1 id="vers-une-api-spécialisée">Vers une API spécialisée</h1>
<p>En général, ce qu&rsquo;on retrouve souvent, c&rsquo;est un backend qui tends vers de l&rsquo;envoi de données brutes aux fronts. Et qui s&rsquo;approche plus ou moins du REST. Pour alimenter une page, le front mobile devra effectuer une ou plusieurs requêtes puis traiter les données, appliquer un peu de logique.</p>
<p>Imaginons une page agenda sur notre application. On a envie de mettre en valeur les événements qui ont lieu aujourd&rsquo;hui, dans de jolis encarts avec un maximum d&rsquo;informations, ainsi que les 3 prochains événements. Pour le reste, on les groupe par semaine glissante et juste le titre nous suffira.</p>
<p>Notre backend nous propose une route qui retourne 100 événements, à partir du début de la semaine. Côté front mobile, on va devoir trier par date, filtrer les événements passés, mettre de côté les événements du jour et également les 3 prochains pour la mise en valeur, puis ensuite faire des groupes par semaine glissante.</p>
<p>Beaucoup de logique métier qui se retrouve côté client (l&rsquo;application). Si on décide de changer, disons par exemple la sélection des événements qui sont mis en valeur, <strong>il faut modifier l&rsquo;application et donc redéployer</strong>, ce qui implique de <a href="https://jordanchapuy.com/posts/2023/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-1-pourquoi" rel="">traverser tout le process de soumission sur les stores que l&rsquo;on aimerait éviter</a>.</p>
<p>Sans parler des données qui transitent sur le réseau : on a besoin que du titre pour une grande partie des événements. On augmente au passage la charge serveur pour rien. Bonne nouvelle, on a dit qu&rsquo;on est responsable du serveur - on peut décider d&rsquo;y <strong>déporter certaines logiques</strong>.</p>
<p>Le backend pourrait :</p>
<ul>
<li>Trier dans l’ordre adapté,</li>
<li>Ne renvoyer que les futurs événements.</li>
<li>Porter la mise en valeur en envoyant deux listes distinctes, et indiquer juste le titre pour les événements lointains.</li>
<li>Grouper par semaine glissante.</li>
<li>Aller plus loin en portant la logique de présentation. “Afficher une carte avec un titre, une description, une date pour cet événement mis en valeur, afficher un simple titre pour cet événement, etc”. On commencerait alors à parler de <a href="https://jordanchapuy.com/posts/2024/01/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-4-server-driven-ui" rel="">Server-Driven UI</a>.</li>
</ul>
<p>En fonction de ce que l&rsquo;on déporte sur le backend, on pourra <strong>modifier le comportement de l&rsquo;application à distance</strong> en déployant une nouvelle version du backend plutôt que de l&rsquo;application. Et c&rsquo;est souvent bien plus rapide.</p>
<p>Notre API, qui était généraliste, devient spécialisée pour un front.</p>
<h2 id="le-cas-graphql">Le cas GraphQL</h2>
<p>Un petit aparté sur GraphQL. Je le mettrais bien dans le panier <em>API généraliste</em> pour notre histoire. Oui, ça apporte une certaine flexibilité au front qui consomme l&rsquo;API, il peut sélectionner ce qu&rsquo;il veut, mais à la fin, <strong>c&rsquo;est toujours le front qui construit les requêtes</strong>. On veut finalement filtrer les événements passés ? Eh bien il faut redéployer l&rsquo;application.</p>
<p>Certes, c&rsquo;est une modification très simple puisque c&rsquo;est peut-être seulement un paramètre dans la requête GraphQL à ajouter ou modifier, mais cette modification est à faire côté client (notre application). Elle impliquera une soumission de la version sur les stores.</p>
<p>On n&rsquo;est pas dans la spécialisation de notre API, elle ne porte pas de la logique supplémentaire dédiée au front.</p>
<h1 id="backend-for-frontend">Backend for Frontend</h1>
<p>Avoir une API spécialisée, ça peut nous embêter dans certains cas. Si j&rsquo;ai plusieurs fronts par exemple : un site web et une application mobile. Il y a parfois une logique différente entre les deux. Le web est une autre plateforme, l&rsquo;interface est très différente. Pour l&rsquo;agenda, je veux tout afficher sous la forme d&rsquo;un calendrier mensuel.</p>
<p>On comprend donc l&rsquo;intérêt d&rsquo;avoir une API généraliste qui essaye de faire plaisir à tout le monde. Pour autant, on perçoit aussi les avantages d&rsquo;avoir une API spécialisée. C&rsquo;est là qu&rsquo;intervient le principe de Backend for Frontend : on peut avoir les deux !</p>
<p>Un Backend For Frontend, souvent connu avec l&rsquo;acronyme BFF, est une couche intermédiaire entre un backend et un frontend. Concrètement, <strong>c&rsquo;est un backend supplémentaire qui va traiter des données spécifiquement pour un type de front</strong> (une application mobile par exemple).</p>
<p>Notre front mobile va effectuer toutes ses requêtes en passant par le Back for Front, et uniquement ce dernier. <strong>C&rsquo;est le Back for Front qui appellera le backend pour obtenir les données nécessaires</strong>. Il pourra ensuite appliquer de la <strong>logique dédiée</strong> avant de renvoyer les données à l&rsquo;application mobile. Le site web aurait de son côté son propre Back for Front.</p>
<p>Vu que le Back for Front devient le point d&rsquo;entrée unique du front, il peut servir d&rsquo;<strong>agrégateur</strong>. Peut-être que pour notre agenda, on avait besoin de la liste des événements futurs et également des événements où l&rsquo;on est inscrit. Plutôt que de faire deux requêtes, le front n&rsquo;en fera qu&rsquo;une seule vers le BFF.</p>
<p>Avec cette mécanique, on voit rapidement plusieurs avantages :</p>
<ul>
<li>On sépare les logiques spécialisées. Il y a un BFF mobile, un BFF web, etc.</li>
<li>On sépare la partie spécialisée de la partie généraliste. Il y a un backend qui ne subit pas les caprices du front.</li>
<li>Un développeur mobile peut plus aisément sortir de son éco-système et effectuer des changements sur le BFF.</li>
<li>On peut regrouper plusieurs ressources en une seule route, et réfléchir en termes de page, d&rsquo;écran.</li>
<li>On cache la complexité au front. Il n&rsquo;y a pas à savoir s&rsquo;il y a plusieurs services ou même s&rsquo;il y a un partenaire externe.</li>
</ul>
<p>Et notamment, ce qui nous intéresse particulièrement dans cette série d&rsquo;articles, <strong>on déporte de la logique client (app mobile) sur un serveur distant (notre BFF)</strong>. On peut donc modifier du comportement sans passer par les stores ! On aime :)</p>
<p>C’est tout de même une décision à peser dans l’équipe. Qui dit couche supplémentaire, dit une <strong>maintenance supplémentaire</strong>. Il y a une nouvelle brique qui doit évoluer et être déployée. Déléguer davantage au Back for Front augmente au passage les possibilités d’erreurs sur l’application - elle est plus permissive. On songera à monitorer plus en profondeur ce qu’il se passe dans l’application.</p>
<hr>
<blockquote>
<p>Série d&rsquo;articles <strong>Mettre à jour une application mobile sans passer par les stores</strong> :</p>
<ul>
<li><a href="https://jordanchapuy.com/posts/2023/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-1-pourquoi" rel="">#1 Pourquoi</a></li>
<li><a href="https://jordanchapuy.com/posts/2023/09/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-2-remote-config-feature-flag" rel="">#2 Remote config, Feature Flag &amp; co</a></li>
<li><a href="https://jordanchapuy.com/posts/2023/12/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-3-backend-for-frontend-bff" rel="">#3 Backend for Frontend (BFF)</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/01/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-4-server-driven-ui" rel="">#4 Server-Driven UI</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/07/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-5-interpreteur-de-code" rel="">#5 Interpréteur de code</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-6-over-the-air-update-ota" rel="">#6 Over-the-air update (OTA)</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/11/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-7-ressources" rel="">#7 Les ressources</a></li>
<li>#8 En résumé, mes options</li>
</ul>
<p>Hors-série :</p>
<ul>
<li>Accélérer le temps de review App Store d&rsquo;une application iOS</li>
<li>Forcer la mise à jour d&rsquo;une application mobile</li>
</ul>
</blockquote>
]]></description></item><item><title>Mettre à jour une application mobile sans passer par les stores - #2 Remote config, Feature Flag &amp; co</title><link>https://jordanchapuy.com/posts/2023/09/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-2-remote-config-feature-flag/</link><pubDate>Wed, 13 Sep 2023 09:25:00 +0200</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2023/09/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-2-remote-config-feature-flag/</guid><description><![CDATA[<p>Et s&rsquo;il suffisait de passer à <code>non</code> un paramètre pour désactiver une fonctionnalité qui pose problème en prod ? Ou de changer un <code>chiffre</code> pour modifier le nombre d&rsquo;éléments de la page d&rsquo;accueil d&rsquo;une application mobile ? Sans avoir à modifier du code et sans passer par la case déploiement bien entendu, parce qu&rsquo;on a envie d&rsquo;agir rapidement. On pourrait simplement changer des valeurs sur une interface web par exemple.</p>
<p>Eh bien, c&rsquo;est ce qui se cache derrière des concepts comme le Remote Config et le Feature Flagging. Ce sont des techniques de développement qui permettent de <strong>modifier des éléments d’une application sans avoir à déployer une nouvelle version</strong>. Les répercussions arrivent <strong>très peu de temps</strong> après (quelques minutes) et ne nécessitent <strong>aucune intervention de l’utilisateur</strong>. On peut changer le comportement d&rsquo;une fonctionnalité, un algorithme, et même l&rsquo;interface graphique.</p>
<p>On peut utiliser ces techniques sur un site web, une application mobile, un backend. Partout ! Le principe de base est très simple. D&rsquo;un côté, il y a une configuration distante (sur un serveur par exemple). C&rsquo;est un ensemble de paramètres avec des valeurs que l&rsquo;application pourra interpréter - <code>Activer le partage ? NON</code> - et ça peut être un simple fichier JSON :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&#34;feature_share_enabled&#34;</span><span class="p">:</span> <span class="kc">false</span> 
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>D&rsquo;un autre côté, il y a une application qui récupère cette configuration régulièrement depuis le serveur et qui contient du code utilisant les différents paramètres reçus pour adapter son comportement. Par exemple, le nombre d’éléments de ma page d’accueil n’est pas un chiffre fixe dans mon code, mais correspond à celui indiqué dans ma configuration à distance.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-swift" data-lang="swift"><span class="line"><span class="cl"><span class="kd">let</span> <span class="nv">numberOfElements</span> <span class="p">=</span> <span class="n">remoteConfig</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s">&#34;home_number_of_elements&#34;</span><span class="p">)</span> 
</span></span></code></pre></div><p>La récupération peut se faire par pull - c’est l’application qui demande régulièrement la configuration - ou par push - c’est le serveur qui indique à l’application qu’il y a un changement. Ou même un mélange des deux, le push permettant d’avoir une bonne réactivité s’il y a un changement critique.</p>
<p>J&rsquo;insiste sur un point important. Du code doit être au préalable <strong>ajouté dans l&rsquo;application en production</strong> pour réagir <strong>à chaque nouveau paramètre</strong> que l&rsquo;on veut ajouter à la configuration. En d&rsquo;autres termes, si je veux désactiver le partage, je dois écrire du code qui conditionne l&rsquo;affichage ou non de mes boutons de partage. Et je dois aussi déployer cette version en production. Ce n&rsquo;est pas magique, il faut prévoir ce travail.</p>
<p>Une fois que j&rsquo;ai rendu configurable mes fonctionnalités, je n&rsquo;ai qu&rsquo;à modifier des valeurs dans ma configuration distante pour affecter mon application sans avoir ni à modifier son code ni à la déployer ! On décorrèle le déploiement du code de celui de la feature, ce qui nous ouvre de multiples possibilités.</p>
<h1 id="cas-dutilisations">Cas d&rsquo;utilisations</h1>
<p>Sans chercher à faire une liste précise et exhaustive, je vais parcourir plusieurs exemples afin de donner de la variété dans les cas d&rsquo;utilisations - c&rsquo;est bien plus qu&rsquo;un <em>bouton on/off</em>.</p>
<ul>
<li>
<p><strong>Désactiver une fonctionnalité</strong>. J&rsquo;ai soudainement un problème en production. La dernière fonctionnalité provoque un crash, une forte charge sur le serveur, se comporte anormalement. Ou un SDK tierce - qui se souvient du SDK de Facebook il y a quelques années ? Il a provoqué le crash au lancement d&rsquo;innombrables apps, y compris les géants comme Spotify ou TikTok. Je peux réagir très vite en désactivant la fonctionnalité puis en analysant le pourquoi ensuite (<a href="https://jordanchapuy.com/posts/2023/08/cynefin-x-user-story-et-si-on-adaptait-le-flow-a-la-complexite" rel="">Cynefin : on est dans le chaos, on cherche à agir tout de suite</a>). On se met un <strong>filet de sécurité</strong>, un <strong>kill switch</strong>, on peut <strong>rollback</strong>. Ou peut-être qu&rsquo;il n&rsquo;y a aucun problème et que la fonctionnalité est simplement éphémère - on l&rsquo;arrête sans nécessité de mise à jour.</p>
</li>
<li>
<p><strong>Activer une fonctionnalité</strong>. J&rsquo;ai le besoin inverse, activer plus tard une fonctionnalité. Peut-être qu&rsquo;il faut attendre que la version de l&rsquo;application soit assez déployée pour activer la fonctionnalité. Ou une date, un événement. Peut-être parce que le backend n&rsquo;a pas encore terminé tout le travail requis. Ou parce qu&rsquo;on veut <strong>intégrer et déployer continuellement (CI/CD)</strong> - on cache la fonctionnalité tant que le travail est inachevé.</p>
</li>
<li>
<p><strong>Modifier l&rsquo;expérience utilisateur</strong>. De manière plus générale, on peut modifier l&rsquo;expérience utilisateur sous différents aspects. Ce n&rsquo;est pas uniquement binaire &ldquo;activé ou désactivé&rdquo;. Je peux modifier l&rsquo;agencement d&rsquo;une page, un nombre d&rsquo;éléments. Je peux créer une mécanique pour forcer la mise à jour de l&rsquo;application (on indique un numéro de version minimal, et l&rsquo;application aurait un écran incitant à mettre à jour au lancement).</p>
</li>
<li>
<p><strong>Déployer progressivement une fonctionnalité</strong>. Apple et Google proposent tous les deux du déploiement progressif sur leurs stores. Ici, on pourrait très bien le faire au niveau d&rsquo;une fonctionnalité. Je pourrais déployer ce nouveau tunnel à 10% des utilisateurs, et j&rsquo;observe ce qu&rsquo;il se passe. J&rsquo;augmente le pourcentage quand et comme je le souhaite (ce que ne permet pas la solution sur l&rsquo;App Store). On fait du <strong>Canary Release</strong>. Et je peux même réduire à 0% si j&rsquo;ai un gros problème. Plus personne n&rsquo;y aura accès. Un avantage par rapport aux déploiements progressifs via les stores : stopper le déploiement ne fait qu&rsquo;empêcher de nouvelles installations, ceux qui ont déjà installé garderont la fonctionnalité active.</p>
</li>
<li>
<p><strong>Expérimenter des variantes</strong>. J&rsquo;ai envie de tester en production un affichage différent, un autre parcours, un placement, une couleur. Peut-être même deux solutions pour améliorer un problème. On va faire vivre ces deux variantes dans la nature en même temps et observer laquelle obtient le meilleur résultat. On fait de l&rsquo;<strong>A/B Testing</strong>.</p>
</li>
<li>
<p><strong>Bêta-tester</strong>. Je peux créer un groupe de bêta-testeurs ou d&rsquo;early adopters pour donner accès en avance à des fonctionnalités. Ou je pourrais même avoir un opt-in dans l&rsquo;application. Et j&rsquo;active ou désactive plus largement dans le futur.</p>
</li>
</ul>
<p>J&rsquo;en profite pour rebondir sur cette dernière phrase. On peut <em>combiner</em> des cas d&rsquo;utilisations. Parce que j&rsquo;ai rendu configurable cette fonctionnalité, je peux commencer à l&rsquo;ouvrir à mon groupe de bêta-tester, puis ouvrir à 10% de tous mes utilisateurs, puis désactiver la fonctionnalité quand un problème se présente. Et toujours sans avoir à déployer une nouvelle version.</p>
<h1 id="je-veux-ça-">Je veux ça !</h1>
<p>Okkkayyyy je commence à être convaincu par l&rsquo;idée, j&rsquo;ai envie de l&rsquo;intégrer sur mon projet, dans mon équipe. Quelle solution prendre ?</p>
<p>Première étape, j&rsquo;opterais pour une autre question : <strong>quels sont mes besoins</strong> ? Plutôt que de foncer sur un outil parce qu&rsquo;il a l&rsquo;air cool ou parce qu&rsquo;untel a dit qu&rsquo;on a raté notre vie si on ne l&rsquo;utilise pas, je préfère regarder mon contexte et mes besoins pour répondre de manière adaptée.</p>
<p>Ici, on peut se demander si on veut une configuration qui expose simplement des valeurs, ou si on veut pouvoir introduire des variantes pour faire de l&rsquo;A/B Testing, du déploiement progressif, etc. Qui va modifier la configuration ? Un fichier versionné sous git pourrait suffire, mais une interface web serait plus adaptée si on veut que toute l&rsquo;équipe puisse apporter des changements. Quel contrôle veut-on sur les données ? Une solution hébergée chez nous ou un SaaS clé en main ? Et le feature flagging au final, est-ce ce qui répond le mieux à notre besoin ?</p>
<p>À partir de ces réflexions, je peux aller dans plusieurs directions.</p>
<ul>
<li>Je peux <strong>créer moi-même une solution</strong>. La mécanique de base est simple. Notre backend qui expose un fichier JSON ou une route avec la configuration et un appel HTTP classique côté app pourrait suffire. Un peu de gestion de cache. On a un contrôle total, c&rsquo;est hébergé chez nous. Puis peut-être qu&rsquo;on ajoute une interface web, de la variance, etc. Ce sont des ajouts qui prendront un peu plus de temps et qui pourraient diriger vers une solution open-source ou SaaS pour éviter de réinventer la roue.</li>
<li>Je peux <strong>héberger une solution open-source</strong> chez moi. J&rsquo;ai rapidement accès à de multiples fonctionnalités et en même temps, je garde un assez bon contrôle. Je gère juste que ça tourne bien sur mes serveurs. <a href="https://github.com/Unleash/unleash" target="_blank" rel="noopener noreffer">Unleash</a> et <a href="https://github.com/featurehub-io/featurehub" target="_blank" rel="noopener noreffer">Featurehub</a> sont deux possibilités.</li>
<li>Je peux utiliser une <strong>solution propriétaire dans le cloud</strong>. Je ne veux rien gérer, je délègue tout. Je peux très rapidement mettre en place une configuration à distance pour mon projet, mais j&rsquo;ai moins de contrôle. <a href="https://firebase.google.com/docs/remote-config" target="_blank" rel="noopener noreffer">Firebase Remote Config</a> a démocratisé la technique pour les applications mobiles, et est très souvent utilisé. C&rsquo;est Google derrière et aux USA, à avoir en tête pour les données :). <a href="https://www.optimizely.com/" target="_blank" rel="noopener noreffer">Optimizely</a> et <a href="https://configcat.com/" target="_blank" rel="noopener noreffer">ConfigCat</a> sont deux alternatives intéressantes ; la dernière proposant une option pour un cloud privée.</li>
</ul>
<h1 id="conclusion">Conclusion</h1>
<p>J&rsquo;aime bien les techniques de Feature Flag et Remote Config parce qu&rsquo;elles sont simples et qu&rsquo;elles apportent une réelle flexibilité en <strong>séparant le déploiement du code et de la fonctionnalité</strong>. On peut réagir à certains imprévus, on peut expérimenter en production, on peut modifier l&rsquo;expérience utilisateur.</p>
<p>Vous avez pu voir que plusieurs autres pratiques et concepts gravitent autour des Feature Flags. L&rsquo;A/B Testing, le kill switch, le Canary Release, par exemple. C&rsquo;est aussi une brique que l&rsquo;on peut retrouver quand on se plonge dans l&rsquo;intégration continue (CI), le déploiement continu (CD), le trunk-based development - la configuration permettant d&rsquo;intégrer et de livrer très régulièrement en cachant le travail non terminé.</p>
<p>Pour autant, les Feature Flags ne sont ni magiques ni parfaites. Il faut prendre soin d&rsquo;en mettre aux endroits adaptés. Il faut <strong>une hygiène dans l&rsquo;équipe</strong> pour les maintenir, les supprimer, éviter les chevauchements.</p>
<p>Elles permettent d&rsquo;expérimenter en production, mais elles ne remplacent pas des entretiens et ateliers avec des utilisateurs, de la discovery, etc. C&rsquo;est complémentaire.</p>
<p>Elles permettent d&rsquo;ajouter un filet de sécurité. Elles ne remplacent pas une attention à la qualité de code, au design applicatif, aux tests, etc. Ajouter -&gt; il est supplémentaire.</p>
<p>Et au fait, on dit Feature Flag, Feature Toggle, ou Feature Flip ? C&rsquo;est la même chose. J&rsquo;ai une préférence pour Feature Flag qui est moins binaire.</p>
<hr>
<blockquote>
<p>Série d&rsquo;articles <strong>Mettre à jour une application mobile sans passer par les stores</strong> :</p>
<ul>
<li><a href="https://jordanchapuy.com/posts/2023/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-1-pourquoi" rel="">#1 Pourquoi</a></li>
<li><a href="https://jordanchapuy.com/posts/2023/09/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-2-remote-config-feature-flag" rel="">#2 Remote config, Feature Flag &amp; co</a></li>
<li><a href="https://jordanchapuy.com/posts/2023/12/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-3-backend-for-frontend-bff" rel="">#3 Backend for Frontend (BFF)</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/01/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-4-server-driven-ui" rel="">#4 Server-Driven UI</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/07/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-5-interpreteur-de-code" rel="">#5 Interpréteur de code</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-6-over-the-air-update-ota" rel="">#6 Over-the-air update (OTA)</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/11/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-7-ressources" rel="">#7 Les ressources</a></li>
<li>#8 En résumé, mes options</li>
</ul>
<p>Hors-série :</p>
<ul>
<li>Accélérer le temps de review App Store d&rsquo;une application iOS</li>
<li>Forcer la mise à jour d&rsquo;une application mobile</li>
</ul>
</blockquote>
]]></description></item><item><title>Mettre à jour une application mobile sans passer par les stores - #1 Pourquoi</title><link>https://jordanchapuy.com/posts/2023/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-1-pourquoi/</link><pubDate>Mon, 14 Aug 2023 18:00:00 +0200</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2023/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-1-pourquoi/</guid><description><![CDATA[<p>Le monde est changeant et incertain, et les applications mobiles ne sont pas épargnées. On a un besoin de <strong>s’adapter rapidement</strong>. Parce qu’on veut expérimenter en production, pour réagir à une nouvelle fonctionnalité provoque des crashs, pour intégrer continuellement, ou parce qu’on s’est planté sur une hypothèse.</p>
<p>On a cependant <strong>deux barrières de taille</strong> au changement rapide dans le développement mobile : les stores (App Store et Google Play), et les utilisateurs.</p>
<p>Pour un site web ou un backend, on peut avoir la totale maîtrise du déploiement. Si on veut mettre en ligne la toute dernière version, on peut le faire en quelques secondes - c’est notre serveur, on décide de ce qu’il exécute. Les utilisateurs y auront accès tout de suite et n’auront d’ailleurs pas le choix - derrière l’url de notre site web, il y a toujours notre dernière version.</p>
<p>Pour une application mobile, je disais qu’on a deux barrières. D’abord, <strong>les stores</strong>.</p>
<p>C&rsquo;est notre première halte sur la route du déploiement. Ici, on ne maîtrise pas. On est chez Apple et chez Google. Il y a une <strong>étape de vérification</strong> de l’application que l’on soumet. Le temps d’analyse est variable et dépend d’eux, et <strong>ils peuvent refuser</strong> comme bon leur semble. Côté Apple, c’est d&rsquo;ailleurs un sport national - les règles sont plus strictes et l&rsquo;application peut soudainement être refusée pour un élément qui est en prod depuis plusieurs versions.</p>
<p>Une fois que l’application est acceptée et déployée sur les stores, on ne peut pas encore crier victoire - c’est au tour des <strong>utilisateurs</strong> d’installer l’application.</p>
<p>Seconde halte pour le déploiement donc, et on ne maîtrise toujours pas. <strong>Les utilisateurs vont mettre à jour quand ça leur chante</strong> : le jour même, le lendemain, 2 semaines après, 6 mois, jamais. Les utilisateurs ne sont d’ailleurs pas spécialement notifiés qu’une nouvelle version est disponible. Ils doivent aller sur les stores eux-mêmes.</p>
<p>Et ceux qui activent les mises à jour automatique ? Elles ne sont pas instantanées pour autant. Le système décide de lancer le téléchargement lorsque certaines conditions sont réunies (connexion à un réseau Wi-Fi, batterie en charge, heure de la journée, utilisation du téléphone).</p>
<p>Ce qui veut dire que si ma nouvelle fonctionnalité provoque un crash en production, il faut passer par toutes ces étapes pour corriger le problème. Un processus long, et sans garanti. Les utilisateurs auront peut-être désinstallé l&rsquo;application avant que ce ne soit réglé et livré.</p>
<p>Face à ce risque, certaines équipes vont entrer dans ce que je trouve être <strong>un cercle vicieux</strong> : on a peur de faire des erreurs parce que le changement sera long, donc on s&rsquo;ajoute du contrôle et des process, ce qui allonge le temps avant de livrer, donc on a encore plus peur, on contrôle davantage, on allonge d&rsquo;autant le délai, etc. Au final, cette équipe va se <strong>figer</strong>, les livraisons deviendront <strong>douloureuses</strong> et les problèmes se multiplieront.</p>
<p>D&rsquo;autres équipes vont plutôt <strong>se diriger vers des pratiques vertueuses</strong>. Elles vont par exemple chercher à <strong>intégrer et déployer en continu</strong> (CI/CD) chaque changement. J&rsquo;entends bien plus souvent ces sujets dans le monde du web, et surtout du backend. Cependant, sur mobile, il existe aussi des techniques pour s&rsquo;approcher des principes de CI et CD malgré les deux barrières que sont les stores et les utilisateurs.</p>
<p>On peut effectuer des changements sur une application mobile en prod sans pour autant devoir déployer une nouvelle version sur les stores. Et ça tombe bien, j’avais envie de faire un petit tour d’horizon pour faire découvrir quelques possibilités avec cette série d&rsquo;articles.</p>
<blockquote>
<p><strong>Mettre à jour une application mobile sans passer par les stores</strong> :</p>
<ul>
<li><a href="https://jordanchapuy.com/posts/2023/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-1-pourquoi" rel="">#1 Pourquoi</a></li>
<li><a href="https://jordanchapuy.com/posts/2023/09/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-2-remote-config-feature-flag" rel="">#2 Remote config, Feature Flag &amp; co</a></li>
<li><a href="https://jordanchapuy.com/posts/2023/12/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-3-backend-for-frontend-bff" rel="">#3 Backend for Frontend (BFF)</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/01/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-4-server-driven-ui" rel="">#4 Server-Driven UI</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/07/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-5-interpreteur-de-code" rel="">#5 Interpréteur de code</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-6-over-the-air-update-ota" rel="">#6 Over-the-air update (OTA)</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/11/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-7-ressources" rel="">#7 Les ressources</a></li>
<li>#8 En résumé, mes options</li>
</ul>
<p>Hors-série :</p>
<ul>
<li>Accélérer le temps de review App Store d&rsquo;une application iOS</li>
<li>Forcer la mise à jour d&rsquo;une application mobile</li>
</ul>
</blockquote>
]]></description></item></channel></rss>