Vendredi après-midi, un correctif de production est prêt, mais le mécanisme de live update de votre application Capacitor a transformé le déploiement en un véritable jeu de devinettes. Un appareil signale le nouveau bundle, un autre conserve un ancien ensemble d'assets, et le rollback se comporte différemment selon la version arrivée en premier. L'updater semblait être une petite intégration quand vous l'avez installé. Le remplacer s'apparente davantage à la mise en place d'un différentiel : l'ancien assemblage doit être retiré proprement, le nouveau doit correspondre à sa base, et chaque mesure doit être reproductible.
Cette comparaison est importante car un système de mise à jour n'est pas qu'un simple bouton de téléchargement. Il gère les versions, reconstruit les bundles, applique les frontières entre natif et JavaScript, et décide de la marche à suivre lorsqu'un package est incomplet ou incompatible. La question pratique n'est pas seulement de savoir comment remplacer la livraison différentielle. C'est de savoir comment remplacer l'updater sans créer un second mode de défaillance pendant la migration.
Table des matières
- Reconnaître le besoin d'un nouvel updater
- Supprimer l'ancien mécanisme en toute sécurité
- Installer et configurer la nouvelle plateforme
- Ajuster le build et les pipelines CI
- Déploiement progressif et suivi des résultats
Reconnaître le besoin d'un nouvel updater
Le premier avertissement arrive souvent sous forme d’un mystère opérationnel. Une release passe les tests locaux, le serveur affiche un upload réussi, et le support reçoit quand même des signalements d’utilisateurs qui voient un écran obsolète. L’équipe d’ingénierie compare les identifiants de bundle, les versions de build natif, les affectations de canal et les logs des appareils, puis découvre que le système de mise à jour a accepté un paquet compilé par rapport à une base différente de celle stockée localement.
Cela ressemble à un différentiel avec une pignonnerie mal réglée. Les pièces peuvent sembler compatibles, mais l’ensemble produit du bruit sous charge. Dans une app Capacitor, ce bruit se manifeste par un état des assets incohérent, une extraction échouée, des tentatives sans fin ou un rollback qui ne restaure qu’une partie du bundle attendu.
Un diagnostic utile commence par les symptômes plutôt que par des suppositions :
- Incompatibilité de version : Vérifiez que la coquille native installée, le bundle téléchargé et les métadonnées de l’updater sont compatibles entre eux.
- Rollback imprécis : Testez si une mise à jour échouée restaure le bundle précédent complet ou laisse des fichiers obsolètes.
- Observabilité limitée : Vérifiez si vous pouvez identifier l’appareil concerné, la version du package, le canal, l’étape d’échec et le dernier démarrage réussi.
- Ciblage non maîtrisé : Vérifiez si des utilisateurs en production reçoivent des artefacts destinés à la bêta, au staging ou à un flux client spécifique.
- Livraison inefficace : Mesurez si le système envoie une archive complète alors que seuls quelques assets web ont changé. Le contexte de ce compromis de conception est abordé dans how delta updates reduce payload size.

Diagnostiquer avant de choisir un remplaçant
Ne considérez pas chaque échec de mise à jour comme la preuve que le mécanisme de mise à jour est défectueux. Un artefact de build défectueux, une règle de canal incorrecte, un secret de signature cassé ou un changement de compatibilité native peuvent produire le même symptôme visible. Capturez d'abord le chemin de l'échec, y compris l'identité du package, la version de base, l'état de l'appareil et si l'application s'est lancée correctement après l'application de la mise à jour.
Le remplacement devient justifié lorsque le mécanisme ne peut pas fournir de réponses fiables ni de récupération sécurisée. Si votre équipe ne peut pas prouver quels appareils ont reçu un bundle, ne peut pas invalider rapidement une release défectueuse, ou ne peut pas garantir qu'une version de base manquante bascule sur un package complet, corriger la configuration ne fera que repousser le prochain incident.
Le principe d’ingénierie est le même que pour un ensemble d’engrenages. Confirmez le composant défaillant avant de retirer le boîtier. Une migration complète de l’updater a un coût initial plus élevé, mais elle vous offre un protocole propre, des règles de version explicites et une limite de rollback testable, plutôt qu’un autre ajustement superposé à une installation incertaine.
Supprimer l'ancien mécanisme en toute sécurité
Considérez le retrait comme une procédure d’isolation contrôlée. L’objectif n’est pas de supprimer un package et d’espérer que le build suivant révélera ce qui reste. L’objectif est d’empêcher deux mécanismes de mise à jour de se disputer le même répertoire web, le même hook de démarrage, la même clé de configuration ou le même endpoint de livraison.
Commencez par geler la branche de migration et consigner le comportement actuel. Enregistrez la version active du plugin, la configuration native, les variables d’environnement, les commandes CI, les noms de canaux et l’emplacement où les bundles téléchargés sont stockés. Cet inventaire vous sera nécessaire pour distinguer les modifications intentionnelles des omissions accidentelles lors du premier build propre.
Établir une base propre
Créez une branche jetable ou une copie de travail, puis inspectez l’arborescence des dépendances et la configuration Capacitor. Identifiez le package de l’updater legacy par son nom de package réel plutôt que par une recherche générique sur « update ». Examinez package.json, les lockfiles, capacitor.config.ts, paramètres du projet iOS, ressources Android et code au démarrage qui appelle les méthodes download, sync, install ou rollback.
Supprimez la dépendance avec le gestionnaire de paquets utilisé par le dépôt. Par exemple, avec npm :
npm uninstall <legacy-updater-package>
npx cap sync
Utilisez la commande équivalente pour pnpm ou Yarn si c’est ce que le projet standardise. Le placeholder est volontaire. Un guide de migration ne devrait pas inventer un nom de package et encourager une commande destructive contre la mauvaise dépendance.
Recherchez ensuite dans le dépôt l’identifiant de l’ancien plugin, les appels API, les noms d’endpoints, les clés de configuration et les listeners d’événements. Supprimez les imports obsolètes et l’initialisation code de la couche application. Retirez aussi les wrappers morts. Laisser une abstraction locale qui appelle un updater supprimé rend le débogage ultérieur beaucoup plus difficile, car le build peut réussir alors que le comportement au démarrage échoue.
Nettoyer les résidus natifs
Ouvrez les projets iOS et Android après la suppression de la dépendance. Supprimez les références natives que le gestionnaire de paquets n’a pas nettoyées, y compris les pods ajoutés manuellement, les dépendances Gradle, les entrées du manifeste, les valeurs de ressources, les schémas d’URL, les déclarations de receivers et les hooks d’initialisation. Ne supprimez pas des fichiers simplement parce que leur nom semble lié. Vérifiez que chaque fichier appartient exclusivement à l’ancien mécanisme de mise à jour et qu’aucune configuration Capacitor partagée ne dépend de lui.
Lancez un rafraîchissement des dépendances natives et compilez les deux plateformes avant d’installer le remplacement. Cela permet de distinguer les échecs de nettoyage des échecs d’intégration. Un build natif propre ne prouve pas que la migration fonctionne, mais un build propre qui échoue prouve que l’ancien mécanisme n’a pas été entièrement neutralisé.
La même discipline s'applique aux scripts. Supprimez les anciens jobs d'upload, les variables d'endpoint, les étapes de signature, les commandes de copie d'artefacts et les notifications de release de votre CI. Vérifiez aussi bien les workflows de pull request que les workflows de production. Un job de preview oublié peut publier un package incompatible sur un canal qui semble inoffensif jusqu'à ce qu'un testeur le reçoive.
Règle pratique : Ne migrez jamais en modifiant l'ancien updater et en ajoutant le nouveau dans le même commit. Rendez la suppression observable, faites un build, et seulement ensuite introduisez le remplacement.
Avant de continuer, installez l'app nettoyée sur un appareil de test et vérifiez qu'elle ne tente plus de contacter l'ancien service. Effacez les données de l'app le cas échéant, inspectez les logs de démarrage et confirmez que l'app charge toujours normalement ses assets web embarqués dans le bundle. Cette base est votre échantillon témoin pour l'étape suivante. Pour une comparaison plus large des approches, consultez Les alternatives à CodePush pour Capacitor, Ionic et Cordova.
Installer et configurer la nouvelle plateforme
Un updater de remplacement doit entrer dans un projet comme un protocole explicite, et non comme une bibliothèque opaque. Définissez ce que contient un bundle, quelles versions natives peuvent l'appliquer, comment les canaux sont associés aux audiences, et ce que fait le client lorsque sa base stockée est indisponible. Si ces règles ne sont pas claires avant l'installation, la migration passera un test happy path tout en restant risquée en production.
Ajouter délibérément le client
Installez le nouveau package de l'updater avec le gestionnaire de paquets du dépôt, puis synchronisez les projets natifs :
npm install <new-updater-package>
npx cap sync
Utilisez le nom de package et les clés de configuration documentés par le fournisseur dans le projet réel. Gardez la modification de dépendance séparée des mises à jour Capacitor non liées, afin qu'un build natif qui échoue ait une cause restreinte.
Initialisez le module de mise à jour à un point prévisible du démarrage de l’application. Il doit connaître le build natif actuel, le canal actif, la version du bundle web local et la politique serveur pour la vérification des mises à jour. Évitez de disperser les appels de mise à jour sur plusieurs écrans. Un service unique doit gérer les vérifications, les téléchargements, la validation, les décisions d’installation et la remontée des erreurs.
Le client doit distinguer une mise à jour du bundle JavaScript d’une mise à jour de l’application native. Un bundle web ne peut pas ajouter un plugin natif, modifier les permissions de la plateforme ou supposer de manière sécurisée qu’un nouveau pont natif existe. Encodez la compatibilité dans les métadonnées de la release et faites en sorte que le module de mise à jour rejette les paquets en dehors de la plage native prise en charge.
Créez les canaux avant de publier
Mettez en place des flux distincts pour les tests internes, le staging et la production. Un canal est plus qu’un simple libellé. C’est une garde-fou qui détermine quel public peut recevoir un paquet et vous offre un environnement contrôlé pour valider le démarrage, la navigation, l’authentification, le comportement hors ligne et les appels au pont natif.
Définissez le chemin de promotion par écrit :
- Développement compile localement sans publication.
- Interne reçoit les artefacts signés pour les appareils d’ingénierie et de QA.
- Scénographie teste des services et une configuration de release proches de la production.
- la production n’accepte qu’un artefact ayant réussi les vérifications précédentes.
Gardez l’affectation du canal en dehors du bundle applicatif dans la mesure du possible, en privilégiant une configuration d’environnement gérée plutôt que des valeurs de test codées en dur. Un build de production qui pointe accidentellement vers un canal bêta est un échec du processus de release, pas une erreur de l’utilisateur.
Protégez le périmètre du bundle
Le service doit publier un bundle web complet et déterministe, même si l’optimisation du transport n’envoie ensuite que les fichiers modifiés. Générez l’artefact depuis un espace de travail propre, excluez les source maps et les fichiers de développement sauf si vous avez une raison précise de les livrer, et enregistrez une identité de contenu pour le package résultant.
Exigez une vérification d’intégrité avant l’installation. Le client doit valider les données téléchargées, reconstruire le répertoire attendu et y basculer de manière atomique. En cas d’échec de la vérification, conservez le bundle actuellement fonctionnel et signalez l’échec avec suffisamment de contexte pour le diagnostiquer.
Le modèl’OTA global, y compris le moment opportun pour les mises à jour et les limitations natives, est décrit dans comment effectuer des mises à jour OTA.

Stockez la configuration dans le gestionnaire de secrets de la plateforme ou dans des variables CI protégées, pas dans le dépôt. Séparez l’accès en lecture pour les jobs de build des permissions administratives pouvant supprimer des releases ou modifier le ciblage de production. Le module de mise à jour doit également exposer un repli sur le package complet. Si l’appareil ne dispose pas de la version de base requise, le système ne doit pas tenter d’appliquer un patch non ancré.
Ajuster le build et les pipelines CI
La publication manuelle est acceptable pour une expérimentation, mais dangereuse comme système de release. Un pipeline fiable transforme une révision de code en un artefact connu, effectue des vérifications sur cet artefact, le signe, le publie sur le canal prévu et enregistre le résultat. La même entrée doit produire la même décision de release, que le job s'exécute sur le poste d'un développeur ou sur un runner hébergé.
Générez l'artefact dans un environnement propre
Commencez par une séquence reproductible. Installez les dépendances verrouillées, lancez le linting et les tests, compilez la couche web et générez la sortie Capacitor à partir des fichiers obtenus. Ne calculez pas de différentiel par rapport au répertoire de travail d'un développeur. Comparez deux bundles immuables et versionnés produits par la CI.
Un pipeline concret sépare les responsabilités :
- Validation : Exécutez les tests unitaires, le type checking, le linting et un build web de production avant tout upload.
- Compatibilité : Confirmez que les capacités natives requises par le bundle correspondent aux builds de l'application cible.
- Packaging : Créez une archive déterministe ou un manifeste de fichiers et excluez les fichiers temporaires.
- Signature : Signez la release avec des identifiants protégés détenus par l'environnement CI.
- Publication : Envoyez l'artefact vers le canal sélectionné par la branche, le tag ou l'approbation de la release.
- Vérification : Interrogez le service de livraison et confirmez que la version publiée, le checksum et le canal concordent.

Rendez l'identité de version sans ambiguïté
Utilisez un identifiant de release qui relie la révision source, la compatibilité native et le bundle publié. Ne vous fiez pas à un libellé mutable comme « latest » lors du diagnostic. L'updater doit remonter la version exacte installée et la version candidate exacte, tandis que le système de release doit conserver un historique suffisant pour effectuer un rollback ou republier délibérément.
Un manifeste utile enregistre :
| Champ | Pourquoi c'est important |
|---|---|
| Version du bundle | Identifie les assets web installés et candidats |
| Compatibilité native | Empêche un bundle web de compter sur un bridge code indisponible |
| Canal | Définit l'audience cible |
| Version de base | Ancre la reconstruction différentielle |
| Valeur d'intégrité | Détecte la corruption ou l'altération |
| Statut de la release | Prend en charge la promotion, la pause et le rollback |
La version de base est particulièrement importante pour la livraison différentielle. La RFC 3229 décrit le modèle général : un client identifie sa représentation stockée, demande un algorithme de différence et reçoit une réponse représentant le changement plutôt que la ressource complète. L'équivalent côté applicatif doit calculer un patch uniquement si la base connue de l'appareil est valide, et envoyer le bundle complet sinon.
Sécurisez le chemin de publication
Considérez le runner CI comme une machine de release privilégiée. Restreignez qui peut déclencher une publication en production, gardez les matériaux de signature hors des logs, faites tourner les identifiants via les contrôles de secrets de la plateforme et empêchez les pull requests non fiables d’accéder aux secrets de release. Le guide de bonnes pratiques CI/CD de DevArmor fournit un contexte utile pour durcir les permissions, les secrets et les limites du pipeline.
Ajoutez une étape de publication en dry-run ou en staging avant la production. Testez l’artifact téléchargé sur un simulateur ou un appareil propre, puis vérifiez le premier lancement, le relancement, le téléchargement interrompu, la signature rejetée et le comportement de rollback. Gardez le job de release idempotent autant que possible. Relancer un job en échec ne doit pas créer une collection ambiguë de packages avec des identifiants qui se chevauchent.
Pour un modèle d’implémentation concret, utilisez le Capacitor guide de configuration de pipeline CI/CD. L’objectif n’est pas seulement d’automatiser les uploads. C’est de rendre chaque release auditable, du commit source à l’état de l’appareil.
Déploiement progressif et suivi des résultats
Le déploiement progressif est le moment où la conception de l’updater est mise à l’épreuve sous charge. Dès le premier jour, un package qui semblait propre en staging rencontre des appareils avec des bases plus anciennes, des téléchargements interrompus, un stockage faible et des versions d’app que votre matrice QA n’a pas couvertes. Considérez le ciblage par pourcentage comme un réglage, mais le véritable mécanisme de sécurité est la capacité d’arrêter la promotion et de ramener les utilisateurs vers un bundle connu bon. Déployez comme vous installeriez un nouveau train de différentiel : commencez par un contrôle d’ajustement contrôlé, écoutez les anomalies, puis n’approfondissez que lorsque l’engrènement est prouvé stable.
Observez tout le parcours de mise à jour
Surveillez tout le chemin, pas seulement le transfert. Les appareils peuvent télécharger chaque octet et échouer tout de même à la vérification de signature, à l’extraction, à l’activation ou au premier lancement après le swap. Journalisez chaque étape avec la version du bundle, la version native de l’app, le canal, la plateforme, un identifiant d’appareil respectueux de la vie privée et une catégorie d’erreur sur laquelle l’équipe peut agir.
Les signaux minimaux doivent répondre à quelques questions opérationnelles :
- L’appareil a-t-il découvert le candidat ?
- A-t-il reçu le bundle complet ou un patch différentiel ?
- La validation d’intégrité a-t-elle réussi ?
- L’activation a-t-elle été complétée ?
- L’app s’est-elle lancée avec succès ensuite ?
- Le client est-il resté sain lors de sa session normale suivante ?
Cette piste d’événements fournit à chaque équipe ce dont elle a besoin. Le support a besoin d’une chronologie par appareil pour expliquer ce qui s’est passé sur un téléphone. Les responsables de release ont besoin des tendances d’adoption, d’échec et de rollback sur toute la flotte. Un modèle pratique pour suivre le succès des mises à jour OTA dans les apps Capacitor correspond parfaitement à ces étapes et facilite grandement la conception du dashboard.

Use rollback as a release feature
Définissez des conditions de rollback avant de publier. Parmi les bons déclencheurs : une hausse des échecs de lancement, des erreurs d'intégrité répétées, un nombre croissant d'appareils bloqués sur le candidat, ou un type de crash limité à une seule plateforme. Conservez sur l'appareil le dernier bundle connu comme fonctionnel et rendez le retour en arrière réversible sans attendre une publication sur les stores.
Le rollback exige aussi de conserver les preuves. Gardez les métadonnées et les logs du package en échec pour que l'équipe puisse reproduire le problème, identifier la plage de compatibilité concernée et décider s'il faut restaurer l'affectation précédente ou déployer un artefact corrigé. Un rollback qui fait disparaître le symptôme pour les utilisateurs mais efface les traces conduit généralement au même échec lors de la release suivante.
Le modèle de transport derrière la livraison différentielle existe depuis longtemps. L'encodage delta HTTP est devenu un standard web formel avec la RFC 3229, publiée par l'Internet Engineering Task Force en janvier 2002., et le Spécification RFC 3229 est encore utile pour une raison pratique. Un delta n'aide que si le client possède une version de base valide et que la reconstruction du résultat coûte moins cher que l'envoi de la ressource complète.
C’est pourquoi les updaters qui prennent en compte l’application fonctionnent généralement mieux que de s’appuyer sur le comportement delta HTTP générique. Le service connaît le bundle de base, le client peut vérifier la sortie reconstruite, et l’updater peut basculer vers un package complet quand le delta ne convient pas. Le choix d’ingénierie est de savoir si le protocole de livraison rend explicites la compatibilité, l’intégrité, le rollback et l’observabilité ; la réponse détermine si la livraison différentielle apporte un réel bénéfice.