Notes d’ingénierie MiniDebug

Automatiser l’export Unity iOS et la validation Xcode sur un Mac cloud

Automatiser l’export Unity iOS et la validation Xcode sur un Mac cloud

Un projet Unity peut parfaitement exporter un projet iOS en local, puis se bloquer sur un Mac cloud lors de l’importation des ressources, de la résolution des dépendances natives ou de l’édition de liens. Le principal problème n’est pas l’échec lui-même, mais le fait que toutes les étapes soient regroupées dans une seule commande : le journal indique seulement que la compilation a échoué, sans permettre de savoir s’il faut relancer Unity, vider le cache ou inspecter le projet Xcode. Une approche plus fiable consiste à scinder le pipeline en deux contrôles indépendants : générer d’abord un projet Xcode vérifiable, puis valider la compilation native sans effectuer de signature.

Définir les limites des entrées et des artefacts

Pour qu’un build soit reproductible, il faut au minimum figer quatre catégories d’entrées : la révision du dépôt, la version de l’éditeur Unity, le fichier de verrouillage des dépendances de paquets et la liste des scènes. Le script ne doit pas lire à la volée les paramètres de l’éditeur présents sur la machine d’un développeur, ni écraser le projet Xcode exporté lors de l’exécution précédente avant de poursuivre la compilation.

Il est recommandé d’utiliser un répertoire distinct pour chaque tâche :

Chemin Rôle Mise en cache
Source/ Projet Unity de la révision courante Non
Library/ Résultat de l’importation des ressources Sous conditions
Build/iOS/ Projet Xcode exporté pour cette exécution Non
.build/DerivedData/ Fichiers intermédiaires de la compilation native Sous conditions
Artifacts/ Journaux, résumés et résultats de validation Non

La clé de cache de Library doit inclure la version de Unity, la plateforme cible, ainsi que les empreintes de Packages/manifest.json et Packages/packages-lock.json. Toute modification de l’un de ces éléments doit déclencher une nouvelle importation. De même, DerivedData ne doit pas être réutilisé directement entre différentes versions de Xcode ou différentes configurations de projet.

Un cache ne peut accélérer que des entrées préalablement figées ; il ne remplace pas le verrouillage des versions. Un cache utilisé malgré des limites mal définies est généralement plus difficile à diagnostiquer qu’une reconstruction complète.

Exporter le projet Xcode en mode batch

Placez le point d’entrée de l’export dans Assets/Editor/IosExport.cs. La liste des scènes doit être générée à partir des éléments activés dans les paramètres de build, afin d’éviter de maintenir deux listes distinctes dans le script et dans l’interface de l’éditeur.

using System;
using System.Linq;
using UnityEditor;
using UnityEditor.Build.Reporting;

public static class IosExport
{
    public static void Run()
    {
        var scenes = EditorBuildSettings.scenes
            .Where(scene => scene.enabled)
            .Select(scene => scene.path)
            .ToArray();

        if (scenes.Length == 0)
            throw new InvalidOperationException("No enabled scenes.");

        var options = new BuildPlayerOptions
        {
            scenes = scenes,
            locationPathName = "Build/iOS",
            target = BuildTarget.iOS,
            options = BuildOptions.CleanBuildCache
        };

        var report = BuildPipeline.BuildPlayer(options);
        if (report.summary.result != BuildResult.Succeeded)
            throw new InvalidOperationException("Unity export failed.");
    }
}

Lors de l’exécution, indiquez explicitement le répertoire du projet, le chemin du journal et le nom de la méthode :

"$UNITY_EDITOR" \
  -batchmode \
  -nographics \
  -quit \
  -projectPath "$PWD" \
  -executeMethod IosExport.Run \
  -logFile "$PWD/Artifacts/unity-export.log"

Supprimez Build/iOS avant le démarrage de la tâche, mais ne supprimez pas systématiquement Library. À la fin, vérifiez simultanément le code de sortie, le fichier journal et la présence de Build/iOS/Unity-iPhone.xcodeproj. La seule présence du répertoire ne garantit pas la réussite de l’export : une tâche en échec peut également laisser un résultat partiel.

Séparer les dépendances natives de la validation de compilation

La réussite de l’export Unity indique seulement que le générateur a terminé son travail. Elle ne garantit pas que le code Objective-C et Swift, les artefacts IL2CPP et les bibliothèques natives puissent être compilés ensemble. Exécutez d’abord l’étape d’installation des dépendances natives prévue par le projet, puis déterminez s’il faut compiler le workspace ou le project. Lorsqu’un outil de dépendances a généré un fichier .xcworkspace, continuer à compiler le fichier .xcodeproj provoque souvent des erreurs de modules introuvables ou de bibliothèques manquantes lors de l’édition de liens.

set -euo pipefail

cd Build/iOS
rm -rf ../../.build/DerivedData

if [ -d "Unity-iPhone.xcworkspace" ]; then
  xcodebuild \
    -workspace Unity-iPhone.xcworkspace \
    -scheme Unity-iPhone \
    -configuration Release \
    -sdk iphoneos \
    -derivedDataPath ../../.build/DerivedData \
    CODE_SIGNING_ALLOWED=NO \
    build
else
  xcodebuild \
    -project Unity-iPhone.xcodeproj \
    -scheme Unity-iPhone \
    -configuration Release \
    -sdk iphoneos \
    -derivedDataPath ../../.build/DerivedData \
    CODE_SIGNING_ALLOWED=NO \
    build
fi

L’objectif est ici de valider la compilation et l’édition de liens, et non de produire un paquet installable destiné à la distribution. La signature doit être réservée à une étape ultérieure et contrôlée, afin que les tâches ordinaires de validation des commits n’accèdent pas inutilement à des éléments sensibles.

Prévoir l’invalidation du cache plutôt que la deviner

Dans les projets Unity, une erreur fréquente consiste à utiliser uniquement le nom de la branche comme clé de cache. Deux commits situés sur la même branche ne produisent pas nécessairement les mêmes résultats d’importation. Commencez par calculer une empreinte des entrées :

{
  printf '%s
' "$UNITY_VERSION"
  printf '%s
' "$XCODE_VERSION"
  shasum -a 256 Packages/manifest.json
  shasum -a 256 Packages/packages-lock.json
  find Assets -name '*.asmdef' -o -name '*.rsp' | sort | xargs shasum -a 256
} | shasum -a 256 | awk '{print $1}' > Artifacts/cache-key.txt

Ne pas mettre en cache l’intégralité du répertoire de travail

Mettre en cache une archive de l’ensemble du projet y mélange d’anciens exports, des paramètres temporaires et des fichiers qui ont depuis été supprimés. Library et DerivedData doivent être gérés séparément, et l’empreinte des entrées doit toujours être vérifiée après restauration. En cas d’écarts de compilation inexpliqués, conservez d’abord les journaux de l’échec, puis relancez une fois avec un cache vide. Si cette exécution réussit, le problème doit être classé comme une erreur de délimitation du cache, et non conduire directement à modifier le code métier.

Archiver le minimum de preuves nécessaire à l’analyse

Après un build réussi, ne conservez pas uniquement un marqueur de succès. Archivez au minimum le journal Unity complet, la sortie de Xcode, le hash du commit, les versions des outils, la clé de cache et un résumé du projet exporté. Ce résumé peut contenir le scheme, la configuration et les paramètres de build, mais doit exclure les identifiants, les jetons et les chemins privés propres à la machine.

Les échecs courants peuvent être rapidement orientés selon l’étape concernée :

Enfin, définissez « export réussi » et « compilation native réussie » comme deux états indépendants. Si le premier échoue, il est inutile d’exécuter Xcode ; si le second échoue, il n’est pas nécessaire de réimporter sans cesse toutes les ressources. Le pipeline devient ainsi plus facile à relancer, ses journaux sont plus courts et les responsabilités de chaque étape sont mieux délimitées.

Questions fréquentes

Pourquoi ne pas produire directement le paquet final depuis Unity ?

La séparation distingue les erreurs de scripts et d’import Unity des problèmes de dépendances, de compilation et d’édition de liens. Une compilation sans signature valide aussi le projet avant l’utilisation d’identifiants contrôlés.

Peut-on partager le dossier Library entre plusieurs projets ?

Ce n’est pas recommandé. La clé de cache doit inclure la version de Unity, les fichiers de verrouillage des dépendances et la plateforme cible ; toute différence impose de régénérer Library.

Quand faut-il compiler le fichier xcworkspace ?

Utilisez xcworkspace lorsque la préparation des dépendances natives en crée un. En son absence seulement, utilisez xcodeproj, avec une détection exécutée après l’installation des dépendances.

Mac physique dédié

Placez votre prochaine compilation iOS sur MiniDebug M4.

M4, 16 Go de RAM et SSD de 256 Go inclus. Location à la journée, à la semaine, au mois ou au trimestre, avec cinq nœuds au choix : Singapour, Tokyo, Séoul, Hong Kong et côte Est des États-Unis. La disponibilité réelle est indiquée en temps réel dans la console.

Choisir un nœud et commander