Une archive de production réussit après la mise à niveau, mais le Flavor production refuse ensuite de se compiler.
La solution la plus sûre est de ne pas remplacer le nœud de production immédiatement : créez cette semaine un Mac distant isolé, mettez-y Flutter 3.47, conservez temporairement CocoaPods pour les plugins concernés, puis n’effectuez la bascule qu’après validation de la compilation réelle, de l’archive, de la signature et du retour arrière.
Cette procédure concerne les développeurs Flutter iOS qui maintiennent des plugins natifs, des Flavors ou des cibles Xcode personnalisées et doivent mesurer l’effet du changement de résolution des dépendances. Elle s’adresse également aux ingénieurs DevOps responsables d’un nœud de compilation distant, ainsi qu’aux équipes qui entretiennent une intégration Flutter add-to-app dans une application iOS existante.
Rappel de migration : au 21 août 2026, l’index officiel des versions Flutter classe Flutter 3.47 parmi les versions stables. Depuis Flutter 3.44, Swift Package Manager est l’intégration par défaut pour les dépendances natives iOS et macOS, avec une solution de repli CocoaPods pour les dépendances qui ne prennent pas encore SPM en charge. Vérifiez néanmoins les exigences Xcode et la compatibilité de chaque plugin au moment de l’opération.
Le calendrier de migration commence par la sauvegarde des preuves
La mise à niveau Flutter 3.47 pour iOS ne doit pas être traitée comme une simple modification de version dans un fichier de configuration. Une chaîne de compilation contient des résolutions de dépendances, des réglages de signature, des scripts, des caches et parfois plusieurs projets Xcode. Une migration réussie doit donc être comparable à l’état précédent.
Avant toute modification, créez une branche dédiée et archivez les éléments suivants :
- le fichier de version Flutter utilisé par le projet ;
pubspec.yamletpubspec.lock;Podfile,Podfile.locket les fichiers de configuration associés lorsqu’ils existent ;- le projet Xcode, les fichiers de packages générés et les Schemes partagés ;
- les réglages de chaque Flavor et de chaque cible personnalisée ;
- le dernier journal de compilation réussi ;
- le chemin de l’archive, son export et les informations de signature utilisées par la CI.
La référence officielle des versions doit être consultée avant l’ouverture de la branche de migration, car le statut stable et les notes d’évolution peuvent changer. L’index officiel des versions Flutter constitue la source à conserver dans le compte rendu de changement.
Le nœud de test doit être séparé du nœud qui publie actuellement l’application. Il peut s’agir d’un Mac local réservé, d’un Mac de laboratoire ou d’un Mac distant NodeMini, à condition que l’environnement soit recréé sans modifier le nœud de production.
La décision de cette semaine est simple :
- si une copie isolée du projet est disponible, commencez la migration sur cette copie ;
- si aucun Mac de secours n’est disponible, ne remplacez pas le nœud de publication : préparez d’abord un environnement temporaire ;
- si l’application doit être publiée avant la fin des tests, gardez l’ancien environnement et reportez la bascule.
Le projet standard doit être observé, pas réécrit manuellement
Un projet proche du modèle Flutter standard est le meilleur premier candidat, mais il ne doit pas servir de preuve pour les autres projets. La migration automatique peut modifier les références du projet Xcode, les scripts de préparation du framework ou la déclaration des paquets. Ces changements doivent être examinés dans le contrôle de version plutôt que recopiés à la main depuis un autre dépôt.
Après la mise à niveau dans l’environnement isolé, le flux minimal est le suivant :
flutter --version
flutter pub get
flutter clean
flutter build ios --config-only
La sortie de flutter --version doit être enregistrée avec le journal de migration. La commande de nettoyage ne constitue pas une preuve de réussite ; elle sert seulement à éliminer un cache qui pourrait masquer une dépendance manquante ou un ancien artefact.
Dans Xcode, observez particulièrement :
- l’apparition ou la modification des références Swift Package Manager ;
- le script de préparation du framework Flutter ;
- les liens entre le projet principal, les cibles et les paquets ;
- les Schemes partagés réellement utilisés par la CI ;
- les paramètres de recherche hérités d’une ancienne intégration.
Le guide Flutter destiné aux développeurs d’applications avec Swift Package Manager doit être rapproché du diff produit par le projet réel. Il ne faut pas supprimer automatiquement les fichiers CocoaPods simplement parce que SPM est devenu la voie par défaut.
Une validation utile comprend un lancement sur simulateur, une compilation pour appareil réel et une archive. Le simulateur vérifie rapidement la résolution du projet et le lien des frameworks, mais il ne valide pas la signature, certains appels natifs ni les conditions propres à un appareil.
Conservez une comparaison avant/après. Les fichiers générés doivent être soumis au contrôle de version uniquement lorsqu’ils font partie du mode de fonctionnement attendu par le projet ; inversement, un fichier nécessaire à la CI ne doit pas être ignoré uniquement parce qu’il est généré localement. Le bon périmètre dépend de la structure du dépôt et doit être démontré par une exécution depuis un clone propre.
Le scénario mixte garde une voie CocoaPods contrôlée
La présence persistante d’un Podfile ne signifie pas que la migration a échoué. Flutter prévoit une voie de repli pour les dépendances qui ne prennent pas encore Swift Package Manager en charge, ce que rappelle l’annonce officielle consacrée aux changements de Flutter 3.44 : l’évolution de l’intégration SPM dans Flutter.
Dans un projet contenant plusieurs plugins, établissez une fiche par dépendance native. Elle doit préciser :
- le plugin Flutter et sa version résolue ;
- son mode d’intégration actuel ;
- le paquet SPM ou la spécification CocoaPods utilisée ;
- le résultat de la résolution sur un clone propre ;
- le produit natif effectivement lié ;
- la version minimale d’iOS déclarée ;
- le résultat en Debug, en Release et lors de l’archive ;
- la possibilité de revenir à l’état précédent.
Le contrôle ne doit pas se limiter à une commande d’installation. Une dépendance peut être résolue, puis échouer au moment du lien, de l’archive ou de l’export signé. Les journaux Xcode doivent donc être conservés avec le résultat de la commande exécutée par la CI.
Trois choix sont raisonnables :
- continuer en double voie si le plugin CocoaPods compile, s’archive et se signe de manière reproductible, tandis que son équivalent SPM n’est pas encore validé ;
- remplacer le plugin si une alternative compatible est testée dans toutes les configurations livrables et si son comportement fonctionnel est équivalent ;
- suspendre la mise à niveau si une dépendance native bloque l’archive, modifie le produit final ou rend le retour arrière incertain.
Il est préférable de conserver une branche de restauration et une copie des fichiers de résolution plutôt que de supprimer la configuration historique dans le même changement. Le statut général de CocoaPods ne permet pas de déduire la compatibilité d’un plugin particulier ; les cas individuels doivent être vérifiés dans le dépôt et dans les journaux de compilation.
Les Flavors et les cibles personnalisées exigent une validation séparée
Un projet multi-configuration peut sembler sain lorsque seul le Scheme principal est exécuté. Cette réussite est insuffisante si staging, production, une cible de notification ou une extension partagent d’autres réglages de compilation.
Pour chaque Flavor livrable, vérifiez la correspondance entre :
- le Scheme ;
- le Build Configuration ;
- les variables d’environnement ;
- l’identifiant d’application ;
- les scripts de préparation ;
- les dépendances natives ;
- le profil et l’identité de signature ;
- le chemin de sortie attendu par la CI.
La séquence de contrôle doit être répétée pour chaque configuration, et non lancée une seule fois avec le Scheme par défaut :
flutter test
flutter build ios --release
La commande exacte d’archive et d’export dépend du projet, de ses scripts et du mode de signature retenu. Le journal doit toutefois prouver quatre éléments distincts : compilation propre, tests, archive et export. Les procédures Apple consacrées à la distribution d’une application avec Xcode et à la création d’un code signé pour la distribution servent de références pour distinguer l’archive de l’export final.
Pour une cible personnalisée, examinez également l’association aux paquets SPM générés. Une dépendance peut être disponible pour Runner mais absente d’une extension ou d’une cible secondaire. La preuve attendue n’est donc pas seulement « l’application démarre » : elle doit identifier la cible compilée, le Scheme employé, le chemin de l’artefact et le résultat de la signature.
Si production échoue alors que Debug fonctionne, revenez à la branche précédente et corrigez la configuration dans la branche de migration. Ne modifiez pas directement le nœud de publication pour contourner une erreur de cible : cette action détruit la comparaison et rend le diagnostic dépendant d’un état local difficile à reproduire.
L’intégration add-to-app doit rester distincte du projet Flutter standard
Dans une architecture add-to-app, Flutter n’est pas nécessairement le projet iOS principal. Le projet hôte peut déjà gérer ses propres paquets, ressources, Schemes et réglages de signature. Il est donc risqué d’appliquer les changements d’un projet Flutter autonome sans examiner la manière dont le module est incorporé.
Le contrôle commence par une cartographie de l’intégration :
- où le module Flutter est généré ;
- comment il est initialisé depuis une page native ;
- quelles ressources sont copiées ;
- quelles dépendances sont déclarées par le projet hôte ;
- quelles configurations utilisent le module ;
- quelles parties reposent encore sur Framework ou CocoaPods.
La documentation Flutter sur la maintenance d’un projet iOS add-to-app doit être utilisée pour comparer l’intégration réelle avec le modèle attendu. Une ancienne méthode ne doit pas être superposée à Swift Package Manager sans savoir quel projet possède effectivement la dépendance.
L’acceptation minimale comporte trois preuves :
- une page iOS native lance le module Flutter ;
- une construction Release complète produit l’artefact attendu ;
- l’ancienne intégration peut être restaurée depuis la branche sauvegardée.
Ajoutez un test des ressources, notamment lorsqu’un projet embarque des éléments audio, vidéo ou de design propres à l’application hôte. Une compilation réussie peut encore masquer une ressource absente au démarrage ou un chemin différent entre Debug et Release.
Le Mac distant devient un nœud CI seulement après l’acceptation technique
Un Mac distant est utile pour isoler une migration, mais l’accès à distance ajoute ses propres points de contrôle. Une commande qui réussit dans une session graphique peut échouer en SSH non interactif parce que le profil du shell, les variables, le trousseau ou les chemins de cache ne sont pas chargés.
Testez l’environnement avec une session SSH comparable à celle utilisée par le service d’intégration continue :
ssh utilisateur@hote-mac 'echo "$PATH"; flutter --version; xcodebuild -version'
Les versions affichées, le chemin de Flutter et l’outil Xcode doivent être consignés dans le rapport. Le script de CI ne doit pas dépendre d’une ouverture préalable de session graphique.
Contrôlez ensuite :
- l’accès aux certificats et profils de signature ;
- les variables nécessaires sans les écrire dans les journaux ;
- les droits sur les répertoires de cache ;
- la récupération des dépendances depuis un clone propre ;
- le comportement après redémarrage ;
- la conservation des journaux d’archive et d’export ;
- la possibilité de désactiver le nouveau nœud sans perturber la publication.
La gestion des certificats doit suivre une procédure explicite. Les recommandations Apple sur le partage des certificats de signature d’une équipe sont plus fiables qu’une copie manuelle de fichiers sensibles entre postes.
L’outil de décision sépare la migration acceptée du simple test réussi
La décision ne doit pas être prise à partir d’un unique code de sortie. Utilisez la liste conditionnelle suivante pendant la revue de migration et cochez chaque ligne avec un lien vers le journal ou l’artefact correspondant :
- [ ] Si une copie isolée du dépôt peut être reconstruite sans modifier la production, alors la migration Flutter 3.47 peut commencer ; sinon, conservez l’ancien nœud et préparez d’abord un environnement séparé.
- [ ] Si le projet standard compile avec SPM, mais qu’un plugin natif n’a pas encore été validé avec SPM, alors gardez CocoaPods pour ce plugin ; sinon, ne supprimez pas le
Podfileavant d’avoir documenté la nouvelle résolution. - [ ] Si chaque Flavor possède un Scheme, une configuration, une archive et un export validés, alors poursuivez vers la comparaison CI ; sinon, refusez la bascule, même si le Scheme
Runnerfonctionne. - [ ] Si une cible personnalisée ou une extension ne reçoit pas le même paquet natif que l’application principale, alors corrigez l’association de cible avant toute publication ; sinon, consignez la preuve dans le rapport.
- [ ] Si l’intégration add-to-app lance le module depuis une page native et produit une version Release, alors poursuivez la validation ; sinon, revenez à l’intégration précédente et n’empilez pas les deux méthodes.
- [ ] Si SSH non interactif retrouve les outils, les variables nécessaires et les identités de signature sans session graphique, alors le Mac distant peut être évalué comme nœud CI ; sinon, il reste un poste de test.
- [ ] Si compilation propre, compilation avec cache, archive, export signé et reprise après redémarrage réussissent sur le projet réel, alors planifiez une période de fonctionnement parallèle ; sinon, bloquez le remplacement du nœud de production.
- [ ] Si la branche précédente, les fichiers de résolution et l’ancien nœud peuvent être restaurés, alors une procédure de retour arrière existe ; sinon, la migration n’est pas réversible et doit être reportée.
Cette grille impose une règle importante : un succès en Debug ne vaut jamais une acceptation de production. Chaque décision doit être liée à une configuration précise, à un journal conservé et à un artefact que l’équipe peut retrouver.
La mise à niveau Flutter 3.47 se valide par scénario, pas par version seule
La bonne question n’est pas de savoir si Flutter 3.47 s’installe, mais si le projet qui doit être publié reste reproductible après la modification de ses dépendances natives. Un projet standard, un dépôt conservant CocoaPods, une application multi-Flavor, un module add-to-app et un nœud CI distant ne présentent pas le même risque.
Pour éviter une décision irréversible, gardez l’ancien nœud en service pendant la période de comparaison prévue par l’équipe, reproduisez les mêmes tâches sur l’environnement isolé et comparez les artefacts plutôt que les seuls codes de sortie. Une archive créée avec succès ne suffit pas si l’export, la signature ou le démarrage sur appareil échoue ensuite.
Si l’équipe ne possède pas de Mac disponible pour cette phase d’isolement, un Mac distant pour la compilation iOS peut servir d’environnement temporaire. L’objectif n’est pas de déplacer immédiatement toute la production, mais de répliquer la chaîne Flutter, d’exécuter la liste de migration sur un projet réel, puis de décider rationnellement si le nœud doit être conservé, étendu ou libéré.
Le nœud actuel ou un Mac distant pour la migration ?
Le nœud actuel reste préférable lorsqu’il est stable, documenté et déjà couvert par une restauration testée. En revanche, un poste local ou un Mac partagé présente souvent trois défauts opérationnels : son état peut dériver entre deux compilations, ses caches peuvent masquer une dépendance manquante et son accès n’est pas toujours disponible pour une validation continue. Un Mac distant NodeMini apporte un environnement accessible à distance et isolable pour cette phase, mais il ne dispense ni de verrouiller les versions ni de tester les certificats, les Flavors et le retour arrière.
La location est donc pertinente pour un cycle de migration, une capacité CI temporaire ou une équipe qui ne souhaite pas acheter un Mac uniquement pour reproduire une chaîne iOS. Pour une charge lourde permanente, un besoin d’interface physique ou une politique imposant une machine détenue sur site, l’achat d’un Mac dédié peut rester plus adapté. La décision doit découler des preuves d’acceptation, non de la seule disponibilité du matériel.
La recommandation finale est de réserver un cycle de publication à la validation parallèle, de maintenir CocoaPods lorsqu’un plugin l’exige réellement et de ne remplacer le nœud de production qu’après archivage, signature, export et restauration réussis. NodeMini permet alors de tester cette migration sur un Mac distant séparé, sans transformer une mise à niveau de dépendances en interruption de livraison.