Jedes Unity-Studio hat dieses eine Build-Skript. Eine 400-zeilige Bash-Datei, die über zwei Jahre durch drei Entwicklerhände ging und kurz vor einem Meilenstein noch schnell editiert wurde. Niemand versteht wirklich, wofür jedes Flag da ist, aber alle haben Angst, es zu löschen. Multiplizieren Sie das über Plattformen (Windows, macOS, Android, iOS, WebGL) und Unity-Versionen hinweg, und Sie erhalten einen Wartungsaufwand, der still und leise 10-20 % jedes Sprints auffrisst.
Unity hat kürzlich ein vereinheitlichtes CLI eingeführt, das dieses Sammelsurium durch eine einzige Kommandozeilen-Schnittstelle ersetzt. Es verwaltet Unity-Editor-Installationen, führt Tests aus und erstellt Builds, alles über ein einziges Tool, das auf jedem CI-Provider funktioniert. Wenn Ihr Team seit Jahren eigene Skripte mit Klebeband zusammenbastelt, verändert das die Rechnung für die Build-Automatisierung grundlegend.
Das Problem: Warum Unity-CI/CD-Skripte außer Kontrolle geraten
Unity-Game-Builds unterscheiden sich in drei Punkten von typischer Software-CI/CD, die das Skripting zur Qual machen:
1. Mehrere Plattformen aus einem Projekt. Ein einziges Spiel benötigt unter Umständen Builds für Windows (64-Bit), macOS (Intel + Apple Silicon), Android (APK + AAB), iOS und WebGL. Jede Plattform hat ihren eigenen Build-Target-Enum, ihr eigenes Ausgabeformat und ihre eigenen Post-Processing-Eigenheiten (Code-Signing unter macOS, APK-Signing unter Android, Xcode-Projektgenerierung für iOS).
2. Unity-Version-Pinning. Verschiedene Branches benötigen oft unterschiedliche Unity-Versionen. Die Verwaltung der Installationen, die richtige Version herunterladen, die richtigen Module anwenden (Android Build Support, iOS Build Support, Linux Build Support), ist nicht trivial. Selbstgebaute Skripte neigen dazu, Pfade und Versionsnummern hart zu kodieren, die bei jeder Änderung brechen.
3. Layout-Tests sind verzahnt. Edit-Mode-Tests, Play-Mode-Tests und Integrationstests erfordern jeweils unterschiedliche Invocation-Flags. Studios enden oft mit separaten Testskripten für jede Kategorie, jedes mit eigener Fehlerbehandlung.
Ein hypothetisches mittelgroßes Studio könnte eine solche Skriptstruktur pflegen:
ci/
├── install_unity.sh # Editor herunterladen & konfigurieren
├── build_windows.bat # Windows-Standalone-Build
├── build_mac.sh # macOS-Build + Code-Signing
├── build_android.sh # Android APK + AAB
├── run_editmode_tests.sh # Unit- & Edit-Mode-Tests
├── run_playmode_tests.sh # Play-Mode-Integrationstests
├── deploy_itchio.sh # Upload zu itch.io
└── common_variables.env # Pfade, Versionsnummern, Signing-Keys
Sechs bis acht Dateien, die drei verschiedene Shell-Interpreter betreffen, gewartet von dem, der zuletzt an der CI gearbeitet hat. Wenn Unity seine API aktualisiert oder sich ein Plattform-Modul ändert, muss das Team jedes Skript durchsuchen.
Was Unity CLI tatsächlich leistet
Das neue Unity CLI konsolidiert die gesamte Oberfläche in einem einzigen Tool mit drei Kernfunktionen:
Installationsverwaltung. Unity-Version und benötigte Module angeben; das CLI holt und konfiguriert den Editor. Keine manuellen Downloads oder Versionsprüfungslogik in eigenen Skripten mehr.
Testausführung. Edit-Mode-Tests, Play-Mode-Tests oder beides mit einem einzigen Befehl ausführen. Das CLI übernimmt Test-Runner-Flags, Ausgabeformate und Exit-Codes, die CI-Systeme bereits nativ verstehen.
Build-Ausführung. Builds für jedes unterstützte Plattform-Target auslösen. Das CLI akzeptiert das Build-Target, den Ausgabepfad und relevante Optionen, ohne dass ein eigenes C#-Build-Skript nötig ist, es sei denn, Ihre Pipeline benötigt es wirklich.
Der entscheidende Designpunkt: Es ist provider-agnostisch. Dieselben CLI-Befehle funktionieren in GitHub Actions, GitLab CI, Jenkins, TeamCity, Bitbucket Pipelines oder im lokalen Terminal eines Entwicklers. Das bedeutet, Ihre Build-Logik lebt an einem Ort, nicht dupliziert über plattformspezifische YAML-Blöcke und Shell-Skripte.
Vorher und Nachher: Ein durchgerechnetes Beispiel
Schauen wir uns an, wie eine Multi-Plattform-CI-Pipeline mit und ohne Unity CLI aussieht. Die folgenden Beispiele sind hypothetisch, sie illustrieren das Muster, nicht die exakte CLI-Syntax, die sich noch ändern kann.
Vorher: Eigene Skripte
Ein typischer GitHub-Actions-Workflow, der eigene Skripte aufruft, könnte so aussehen:
# .github/workflows/build.yml, ALTER ANSATZ (hypothetisch)
name: Build All Platforms
on: push
jobs:
build-windows:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Unity
run: ./ci/install_unity.sh 2022.3.20f1 "Windows"
- name: Build
run: |
./ci/build_windows.sh \
--project-path . \
--output ./builds/windows/game.exe
- uses: actions/upload-artifact@v4
with:
name: windows-build
path: ./builds/windows/
build-android:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Unity
run: ./ci/install_unity.sh 2022.3.20f1 "Android"
- name: Build APK
run: |
./ci/build_android.sh \
--project-path . \
--keystore ${{ secrets.ANDROID_KEYSTORE }} \
--output ./builds/android/game.apk
- uses: actions/upload-artifact@v4
with:
name: android-build
path: ./builds/android/
Jeder Schritt hängt von einem eigenen Skript ab, das Unitys -batchmode -executeMethod-Aufruf kapselt. Wenn sich der Projektpfad ändert, brechen alle Skripte. Wenn Sie Windows 64-Bit als separates Target hinzufügen, brauchen Sie ein weiteres Skript.
Nachher: Unity CLI
Dieselbe Pipeline mit Unity CLI reduziert Installation, Tests und Builds auf weniger, klarere Schritte:
# .github/workflows/build.yml, UNITY-CLI-ANSATZ (hypothetische Syntax)
name: Build All Platforms
on: push
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Unity 2022.3
run: unity-cli install 2022.3.20f1 --modules Android,Windows
- name: Run Edit Mode Tests
run: unity-cli test --mode EditMode --output test-results.xml
- uses: actions/upload-artifact@v4
with:
name: test-results
path: test-results.xml
build-windows:
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4
- name: Install Unity 2022.3
run: unity-cli install 2022.3.20f1 --modules Windows
- name: Build Windows
run: unity-cli build --target StandaloneWindows64 --output ./builds/windows/
- uses: actions/upload-artifact@v4
with:
name: windows-build
path: ./builds/windows/
build-android:
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4
- name: Install Unity 2022.3
run: unity-cli install 2022.3.20f1 --modules Android
- name: Build Android
run: unity-cli build --target Android --output ./builds/android/
- uses: actions/upload-artifact@v4
with:
name: android-build
path: ./builds/android/
Die Unterschiede sind strukturell, nicht kosmetisch:
- Keine plattformspezifischen Shell-Skripte. Die Build-Logik wird deklarativ in der Pipeline-Konfiguration ausgedrückt.
- Zentralisierte Versionsverwaltung. Die Unity-Version zu ändern bedeutet, einen String in jedem Job zu editieren, nicht die Jagd nach hartkodierten Pfaden in Shell-Skripten.
- Standardisierte Testintegration. Testergebnisse erscheinen als strukturierte Ausgabe, die CI-Provider nativ parsen können, keine Wrapper-Skripte, um Unitys Log-Ausgabe in JUnit-XML zu konvertieren.
Anpassung an GitLab CI
Dasselbe Prinzip gilt für alle Provider. So könnte die Pipeline in der .gitlab-ci.yml aussehen:
# .gitlab-ci.yml, UNITY-CLI-ANSATZ (hypothetische Syntax)
stages:
- test
- build
variables:
UNITY_VERSION: "2022.3.20f1"
unit-tests:
stage: test
image: unityci/editor:ubuntu-2022.3.20f1-linux-il2cpp
script:
- unity-cli install $UNITY_VERSION --modules Linux
- unity-cli test --mode EditMode --output test-results.xml
artifacts:
reports:
junit: test-results.xml
build-windows:
stage: build
script:
- unity-cli install $UNITY_VERSION --modules Windows
- unity-cli build --target StandaloneWindows64 --output ./builds/windows/
artifacts:
paths:
- ./builds/windows/
build-android:
stage: build
script:
- unity-cli install $UNITY_VERSION --modules Android
- unity-cli build --target Android --output ./builds/android/
artifacts:
paths:
- ./builds/android/
Das Muster ist dasselbe: Deklarieren Sie, was Sie brauchen, und lassen Sie das CLI das Wie übernehmen. Ob Ihre CI auf GitLab-Shared-Runnern oder selbst gehosteten Maschinen auf einer eigenen Game-Backend-Infrastruktur läuft, die Befehle ändern sich nicht.
Was das für Live-Game-Services bedeutet
Für Studios, die Live-Spiele mit häufigen Content-Updates betreiben, ist CI/CD kein einmaliges Setup, es ist ein laufender operativer Kostenfaktor. Jede neue Plattform, jedes Unity-Upgrade, jede SDK-Integration, die die Build-Pipeline berührt, schafft einen potenziellen Fehlerpunkt.
Betrachten Sie ein Live-Service-Spiel, das wöchentliche Content-Updates über drei Plattformen (Windows, Android, iOS) ausliefert. Vor Unity CLI könnte eine hypothetische Pipeline erfordern:
- 3 plattformspezifische Build-Skripte (~150 Zeilen pro Skript)
- 1 Shell-Skript für die Unity-Versionsinstallation (~120 Zeilen)
- 1 Test-Runner-Wrapper (~80 Zeilen)
- Gemeinsame Konfiguration verteilt über
.env-Dateien und CI-Provider-Variablen
Das sind rund 650 Zeilen eigener Skripte, nur um drei Builds zu erzeugen. Wenn ein Entwickler ein Build-Skript ändert und um 2 Uhr morgens vor einem Content-Drop die Android-Pipeline bricht, liegt die Ursache meist in plattformspezifischer Logik begraben, die nur eine Person versteht.
Unity CLI verschiebt diese Komplexität in ein gewartetes Tool. Ihre CI-Konfiguration wird zur Spezifikation (was zu bauen ist) statt zur Implementierung (wie der Unity-Editor im Batch-Modus aufzurufen ist). Letzteres ist genau die Art von Code, die verrottet, er funktioniert, bis er es nicht mehr tut, und wenn er bricht, weiß niemand warum.
Best Practices für die Einführung von Unity CLI in Ihrer Pipeline
1. Beginnen Sie mit Testautomatisierung, nicht mit Builds. Richten Sie zuerst Edit-Mode- und Play-Mode-Tests ein. Tests geben Ihnen eine schnelle Feedback-Schleife, um zu validieren, dass die CLI-Integration funktioniert, und Sie gewinnen nebenbei bessere Testabdeckung. Builds sind das wertvollere Ziel, aber Tests sind der sicherere Ausgangspunkt.
2. Pinnen Sie Ihre Unity-Version explizit in der CI-Konfiguration. Auch wenn das CLI die Installationen verwaltet, sollte Ihre CI-Konfiguration die Version als Variable deklarieren (wie UNITY_VERSION im GitLab-Beispiel oben). Beim Upgrade ändern Sie sie an einer Stelle, und die gesamte Pipeline zieht gemeinsam um.
3. Halten Sie Build-Targets als Parameter, nicht als hartkodierte Werte. Nutzen Sie Matrix-Builds (GitHub Actions) oder parallele Jobs (GitLab CI), die von einer Target-Liste gesteuert werden. Eine neue Plattform, sagen wir Linux, hinzuzufügen, sollte bedeuten, einen Eintrag in der Matrix zu ergänzen, nicht ein neues Skript zu schreiben.
4. Fügen Sie nach jedem CLI-ausgelösten Build eine Build-Verifikation hinzu. Prüfen Sie, ob das Ausgabe-Artefakt existiert und eine plausible Dateigröße hat. Ein Build-Output von null Bytes bedeutet, dass der CLI-Befehl upstream stillschweigend fehlgeschlagen ist. Fangen Sie das sofort ab, nicht erst wenn QA meldet, dass der Build fehlt.
5. Cachen Sie die Unity-Installation in der CI. Das Herunterladen und Installieren von Unity mit allen Plattform-Modulen kann 10-15 Minuten dauern. Nutzen Sie den Cache-Mechanismus Ihres CI-Providers, um den installierten Editor zwischen den Läufen zu speichern. Ein Cache-Hit reduziert diesen Schritt auf unter eine Minute.
Wo ProjectMakers ins Spiel kommt
Die Einführung von Unity-CI/CD-Automatisierung ist eine dieser Aufgaben, die im Prinzip einfach und in der Praxis fummelig ist, besonders wenn Ihr Projekt eigene Build-Schritte, plattformspezifische Player oder von früheren Teammitgliedern geerbte Skripte hat. Studios, die sich lieber auf Game-Content als auf Pipeline-Infrastruktur konzentrieren, holen oft einen Game-Development-Partner an Bord, der die Pipeline einmalig aufsetzt, dokumentiert und migriert, und dann ein System übergibt, das das interne Team selbstständig warten kann.
Ob Ihr Team das intern oder mit externer Hilfe umsetzt, die Richtung ist klar: Eigene Shell-Skripte, die Unitys Batch-Modus umwickeln, werden zu Legacy-Tooling. Wenn Sie ein bestehendes Projekt mit mehreren Build-Targets und einer CI/CD-Pipeline haben, der niemand so recht vertraut, versuchen Sie als nächstes Experiment, das Build-Skript einer Plattform durch das neue CLI zu ersetzen. Beginnen Sie mit der Plattform, die am häufigsten bricht, Sie werden schnell wissen, ob das CLI Ihre Anforderungen abdeckt.
Quelle: CICD Made Easier with Unity CLI
