Build iOS Kotlin 2.4.10 : déployer un CI Mac distant en 2026
Ce guide s’adresse aux équipes qui développent Kotlin Multiplatform depuis Windows ou Linux, mais doivent produire et signer une application iOS. Il définit la frontière entre le poste principal et le Mac distant, puis détaille les contrôles pour les Framework, les tests, l’Archive, les secrets, les caches et la reprise après incident.
Sommaire
- À qui s’adresse cette méthode
- La frontière entre poste de développement et nœud Apple
- Les Framework Kotlin doivent être validés par architecture et par usage
- L’intégration Xcode doit rester non interactive
- Les tests doivent être séparés par responsabilité
- Archive et signature : rendre chaque étape observable
- Caches, concurrence et reprise après incident
- Le choix du Mac distant face à votre solution actuelle
La documentation de Kotlin distingue les cibles iOS pour appareil et simulateur, notamment iosArm64 et iosSimulatorArm64 (référence officielle sur les cibles natives). La décision est donc immédiate : gardez le code partagé et les contrôles Gradle sur Windows ou Linux, mais confiez les Framework iOS, les simulateurs, les tests Xcode et l’Archive finale à un véritable Mac équipé de Xcode. En cette semaine du 27 août 2026, votre première action doit être de faire passer un dépôt fraîchement cloné sur ce nœud, sans réglage manuel.
À qui s’adresse cette méthode
Ce guide est destiné aux développeurs qui travaillent principalement sous Windows ou Linux et livrent une application Kotlin Multiplatform pour iOS. Il concerne aussi les ingénieurs DevOps qui veulent relier Kotlin/Native à un pipeline Xcode, ainsi que les responsables de plateforme qui administrent les identifiants de signature, les caches et un Mac distant partagé.
Attention : Kotlin 2.4.10 est la version stable retenue pour cette procédure au 14 juillet 2026, tandis que Kotlin 2.4.20-RC reste une version préliminaire. Ne validez donc pas le comportement de cette dernière comme une capacité garantie de Kotlin 2.4.10 ; contrôlez la version réellement résolue par votre dépôt avant chaque campagne de validation.
La frontière entre poste de développement et nœud Apple
Un poste Windows ou Linux peut parfaitement héberger l’édition du code commun, les revues, les contrôles statiques et une grande partie des tâches Gradle qui ne produisent pas de binaire Apple. En revanche, le nœud Mac doit prendre en charge ce qui dépend directement de la chaîne Apple : intégration dans Xcode, lancement du simulateur, tests propres à l’application iOS, signature, création de l’Archive et export destiné à la distribution.
Le fait d’utiliser un Mac distant ne signifie pas qu’il faut y déplacer tout le projet de développement. La séparation réduit les ambiguïtés et facilite le diagnostic :
| Élément | Poste Windows ou Linux | Mac distant de CI | Preuve attendue |
|---|---|---|---|
| Code commun et configuration Gradle | Modification, revue et validation | Lecture depuis le dépôt | Clone propre et état reproductible |
| Dépendances Kotlin et contrôles partagés | Résolution et vérifications générales | Résolution nécessaire au build Apple | Journal Gradle conservé |
| Framework ou XCFramework iOS | Non considéré comme définitif | Génération par Kotlin/Native | Fichiers, architectures et somme de contrôle |
| Projet Xcode | Édition possible, mais non suffisante | Compilation, tests et Archive | Journal de build et fichier xcresult |
| Certificats et profils | Aucun secret de distribution requis | Stockage contrôlé hors dépôt | Vérification sans secret dans les logs |
| Produit final | Téléchargement ou publication du résultat | Archive et export | Archive inspectée et retour arrière possible |
Le test le plus utile n’est pas de vérifier qu’un développeur peut ouvrir Xcode avec une session graphique. Il consiste à supprimer le répertoire de travail, cloner le dépôt avec l’utilisateur du runner, injecter uniquement les secrets prévus, puis atteindre la phase de build Apple sans cliquer dans une boîte de dialogue. Si une variable locale, un chemin absolu ou une autorisation interactive est indispensable, le nœud n’est pas encore autonome.
Cette approche est également importante pour un nœud Mac destiné au développement à distance : l’accès SSH sert à administrer et observer la machine, mais ne doit pas masquer les dépendances du pipeline.
Les Framework Kotlin doivent être validés par architecture et par usage
Pour un projet Kotlin Multiplatform, le succès d’une tâche Gradle sur une seule cible ne prouve pas que le livrable iOS est distribuable. Une application exécutée sur un appareil et une application lancée dans un simulateur ne consomment pas nécessairement le même binaire. Les cibles iosArm64 et iosSimulatorArm64 doivent donc être déclarées selon les environnements réellement pris en charge par votre projet, conformément à la documentation officielle de génération des binaires natifs.
Sans Mac local, pouvez-vous construire une application iOS Kotlin Multiplatform ?
Oui, si le dépôt peut être cloné sur un Mac équipé de Xcode et si le pipeline y exécute la partie Apple. Windows ou Linux reste adapté au développement partagé, mais ne remplace pas le système macOS nécessaire à la compilation, aux tests Xcode et à la signature. La réponse pratique est donc « oui avec un nœud Apple distant », et non « oui avec un simple serveur Linux ».
Pour une intégration directe, le Framework est généralement produit pour être consommé par le projet Xcode du même dépôt. Cette solution réduit le nombre de livrables, mais rend le lien entre une tâche Gradle et le projet Apple particulièrement sensible aux chemins et à l’ordre d’exécution. Un Framework indépendant peut convenir lorsque l’application iOS et le module partagé suivent des cycles de développement distincts. Le XCFramework, lui, est plus adapté à une distribution regroupant les variantes nécessaires, à condition de vérifier son contenu plutôt que de se fier à son seul nom.
| Mode d’intégration | Quand le choisir | Risque principal en CI | Contrôle à ajouter |
|---|---|---|---|
| Intégration directe | Dépôt unifié et livraison coordonnée | Chemin local ou tâche Gradle implicite | Dépendance explicite entre build Kotlin et Xcode |
| CocoaPods | Projet déjà structuré autour de ce gestionnaire | Installation différente entre postes | Résolution depuis un environnement propre |
| XCFramework versionné | Distribution à plusieurs consommateurs | Mauvaise architecture ou artefact périmé | Inspection du contenu et somme de contrôle |
| Dépendance binaire distante | Équipes et cycles séparés | Décalage entre code et binaire | Version immuable et test d’import Xcode |
La vue officielle de l’intégration Kotlin Multiplatform avec iOS doit servir de référence pour choisir le raccordement. Dans le pipeline, faites apparaître explicitement le nom du module, le répertoire de sortie et la tâche Gradle appelée. Évitez les scripts qui supposent que l’utilisateur courant possède déjà un Framework dans un dossier de travail.
L’acceptation doit réunir plusieurs preuves :
- la tâche Gradle de génération se termine sans intervention ;
- le Framework ou le XCFramework contient les variantes attendues ;
- le projet Xcode importe réellement le module ;
- une modification du code partagé change le produit généré ;
- le même commit produit un résultat comparable dans un répertoire neuf.
Comment générer et contrôler un XCFramework Kotlin depuis un Mac distant ?
Définissez les cibles dans le projet, lancez la tâche de production prévue par votre configuration, puis inspectez le répertoire obtenu avec les outils disponibles sur macOS. Ne validez pas seulement le code retour Gradle : contrôlez les architectures présentes, l’import du module dans Xcode et la correspondance entre le commit du dépôt et l’artefact. Si votre distribution passe par Swift Package Manager, comparez votre configuration à la documentation Kotlin sur l’export SPM.
L’intégration Xcode doit rester non interactive
Le projet Xcode est souvent le point où les configurations locales deviennent visibles : Build Phases modifiées à la main, Scheme absent du dépôt, fichier de configuration ignoré, chemin vers un Framework propre au poste d’un développeur ou tâche Gradle lancée uniquement depuis l’interface graphique. Chacun de ces éléments peut fonctionner en développement et échouer sur le runner.
Examinez les relations suivantes avant de considérer le pipeline comme prêt :
- le Scheme utilisé par la ligne de commande est partagé et sélectionné sans action graphique ;
- les Build Phases appellent la tâche Kotlin prévue, avec un chemin calculé depuis le dépôt ;
- les fichiers de configuration requis sont versionnés ou générés à partir de variables documentées ;
- le mode de configuration, la destination et l’identifiant du projet sont transmis par le pipeline ;
- le répertoire de sortie est supprimé ou isolé entre deux exécutions.
Apple documente les paramètres transmis à l’outil de build dans sa référence des variables d’environnement Xcode. Utilisez cette documentation pour distinguer une variable officielle d’un contournement propre à votre shell. Le runner doit recevoir les paramètres par son environnement, et non par un fichier personnel présent uniquement dans votre session SSH.
Après avoir modifié un module partagé, refaites le parcours complet : génération du Framework, ouverture du projet Xcode, compilation et import d’une API modifiée. Ce test en boucle détecte mieux les artefacts obsolètes qu’une compilation répétée sans changement de source.
Les tests doivent être séparés par responsabilité
Les tests common, les tests Kotlin/Native et les tests Xcode ne répondent pas à la même question. Les premiers vérifient la logique partagée ; les seconds exposent les contraintes du backend natif ; les derniers contrôlent l’application dans son environnement Apple, avec ses ressources, ses dépendances et éventuellement son interface.
| Famille de test | Emplacement logique | Ce qu’un échec indique d’abord | Sortie à conserver |
|---|---|---|---|
| Tests communs | Poste principal ou étape Gradle | Logique partagée, sérialisation, règles métier | Rapport Gradle et journal du commit |
| Tests Kotlin/Native | Mac distant, cible Apple | Interopérabilité, mémoire ou compilation native | Rapport Kotlin/Native et sortie Gradle |
| Tests Xcode | Mac distant, destination Apple | Projet, runtime, ressources ou intégration | Journal Xcode et xcresult |
| Test de lancement simulateur | Mac distant avec session adaptée | Runtime, destination, architecture ou affichage | Logs du simulateur et résultat de test |
Quelles tâches iOS de Kotlin Multiplatform doivent être exécutées sous macOS ?
Toute tâche qui produit ou consomme un binaire Apple, qui s’appuie sur Xcode, qui lance un simulateur ou qui signe une application doit être placée sur le Mac. Les contrôles purement communs peuvent rester ailleurs, mais la frontière doit être écrite dans la définition du pipeline afin qu’un déplacement accidentel vers Linux soit impossible.
Un simulateur peut aussi dépendre d’une session graphique, d’un runtime installé et d’une destination précise. Ne promettez donc pas le débogage interactif sur chaque nœud partagé : un pipeline non interactif est plus robuste, tandis qu’une session distante VNC peut être réservée à l’analyse ponctuelle. Pour l’exécution en ligne de commande, suivez les principes Apple de construction et lancement d’une application avec Xcode.
Un simple code retour ne suffit pas. Archivez le journal lisible, le paquet xcresult, la destination effectivement sélectionnée et la référence du commit. Vous pourrez ainsi distinguer une erreur de code commun, une incompatibilité native, une configuration Xcode incomplète ou un simulateur indisponible.
Archive et signature : rendre chaque étape observable
Un pipeline iOS fiable sépare la résolution des dépendances, la génération Kotlin, la compilation Xcode, l’Archive et l’export. Chaque étape doit avoir une entrée déclarée, un répertoire de sortie connu et une condition d’arrêt explicite.
| Étape | Entrées | Produit | Arrêt immédiat si |
|---|---|---|---|
| Résolution | Commit, fichiers de dépendances, variables non secrètes | Dépendances résolues et journal | Version ou dépôt non déterministe |
| Framework | Module partagé et cibles Apple | Framework ou XCFramework | Architecture ou import absent |
| Build Xcode | Projet, Scheme, configuration | Application compilée | Avertissement bloquant ou ressource manquante |
| Archive | Application, équipe et signature | Archive inspectable | Signature invalide ou profil absent |
| Export | Archive et méthode de distribution | Paquet destiné à la suite du processus | Produit non vérifiable ou manifeste incohérent |
Comment intégrer un projet Kotlin Multiplatform dans une CI iOS avec archivage automatique ?
Commencez par rendre le Scheme partageable, puis appelez depuis le runner la tâche Gradle qui produit le Framework. Enchaînez avec la commande Xcode d’Archive et l’export dans un répertoire isolé. Le pipeline doit publier les logs, l’Archive et les métadonnées de build, tout en échouant avant la publication si la signature ou la vérification du produit ne passe pas. Les principes de flux Apple pour la création d’une Archive destinée à la distribution fournissent le cadre de contrôle.
Les certificats, profils, comptes de signature et clés privées ne doivent jamais être commis dans le dépôt ni imprimés dans les logs ordinaires. Utilisez un gestionnaire de secrets du système CI, limitez leur exposition au job Apple et séparez les identifiants de publication des comptes utilisés pour le développement quotidien. La procédure Apple de distribution vers des appareils enregistrés rappelle que la destination de distribution influence les prérequis de signature.
Avant la mise en service, supprimez toute action nécessitant un clic. Le critère n’est pas seulement qu’une Archive puisse être obtenue, mais qu’un job lancé par un compte de service puisse la produire, la contrôler et s’arrêter proprement en cas d’erreur. Préparez également un chemin de retour : l’ancienne Archive validée doit rester identifiable, tandis que la nouvelle est publiée uniquement après vérification.
Caches, concurrence et reprise après incident
Un Mac partagé ne doit pas être traité comme un poste de développeur laissé allumé. Les caches Gradle, Kotlin/Native, Xcode Derived Data et dépendances peuvent accélérer les tâches, mais ils peuvent aussi masquer un défaut de configuration ou faire consommer à un projet l’artefact d’un autre.
Quels fichiers faut-il conserver en cache pour un nœud Kotlin iOS ?
Commencez par mesurer les téléchargements et les réutilisations de Gradle, des dépendances Kotlin/Native, des dépendances Apple et de Derived Data. Ne conservez ensuite que les caches dont le contenu est rattachable à une version de dépendance et à un projet. Le cache doit être un accélérateur supprimable, jamais une condition secrète de réussite.
Attribuez à chaque exécution un répertoire de travail propre ou un identifiant de job isolé. Cette règle concerne aussi les simulateurs, les ports d’accès, les fichiers temporaires et les ressources de signature. Deux projets ne doivent pas pouvoir modifier le même répertoire de Framework ni démarrer une destination portant le même état supposé.
Pour un runner GitHub Actions, un libellé explicite permet de router les tâches iOS vers le bon hôte ; la documentation GitHub sur les libellés des runners auto-hébergés décrit ce mécanisme. Utilisez un libellé indiquant la famille de système et les capacités réellement installées, sans déclarer une compatibilité que le nœud n’a pas été testé à fournir.
La validation opérationnelle doit couvrir les incidents ordinaires :
- interrompre la session SSH pendant un job long et vérifier que le job ne dépend pas du terminal ;
- redémarrer le Mac et contrôler le retour du runner ;
- envoyer un nouveau job après reconnexion ;
- relancer depuis un répertoire de travail vierge ;
- exécuter deux projets avec des répertoires et des ressources isolés ;
- vérifier que les secrets ne réapparaissent pas dans les journaux après un échec.
Votre score de préparation peut être qualitatif : acceptable si le clone propre, l’Archive, les tests et la reprise passent ; conditionnel si seul le chemin avec cache fonctionne ; à rejeter si une action manuelle, un chemin local ou un compte personnel est requis. Cette grille est plus utile qu’un temps de build isolé, car elle mesure la capacité du nœud à rester exploitable après une interruption.
Le choix du Mac distant face à votre solution actuelle
Si vous développez déjà sous Windows ou Linux, conserver cette machine comme poste principal est rationnel : elle reste pratique pour l’édition, les contrôles communs et la gestion du dépôt. En revanche, un serveur Linux seul ne fournit ni Xcode, ni les destinations Apple, ni le flux de signature requis. Une machine virtuelle macOS ou une installation non standard ajoute des contraintes de licence, de pilotes, de performances graphiques et de maintenance qui compliquent un nœud destiné à la publication.
Acheter un Mac dédié peut être préférable lorsque vous devez maintenir une charge stable sur une longue période, connecter des périphériques physiques ou garder un contrôle matériel complet. Pour une équipe qui doit d’abord valider Kotlin 2.4.10, tester une chaîne Xcode et absorber des pics de livraison, cette option immobilise toutefois un matériel supplémentaire, impose son administration locale et ne résout pas automatiquement l’isolation des jobs.
Dans ce cas précis, louer un Mac réel auprès de VPSMAC vous donne un point de sortie Apple séparé sans transformer votre poste Windows ou Linux en environnement hybride fragile. Vous pouvez commencer par un nœud Mac M4 pour vos essais de CI, exécuter le clone propre, le Framework, les tests et l’Archive, puis décider seulement après validation si ce nœud doit devenir permanent. Pour une équipe distribuée, le choix d’un nœud Mac M4 en Virginie ou d’un autre emplacement doit surtout suivre la latence d’administration et les contraintes de votre chaîne, plutôt qu’une promesse de performance non mesurée.
Si vous devez seulement disposer temporairement d’un environnement Apple pour qualifier une version, reproduire un échec ou établir un runner avant un investissement matériel, cette location est généralement plus cohérente qu’un serveur Linux complété de contournements. En revanche, si votre charge est permanente, fortement concurrente ou liée à des interfaces physiques, comparez le coût total et l’achat d’un Mac dédié avant de choisir.
Commencez cette semaine par un dépôt de test sans dépendance locale, imposez la génération du Framework sur le Mac distant, conservez les résultats Xcode et vérifiez la reprise après redémarrage. Une fois ces preuves réunies, vous disposerez d’un nœud CI mesurable, et non d’un simple accès distant qui fonctionne uniquement depuis la session d’un développeur.