Teams, die zum ersten Mal Screenshots in App Store Connect hochladen, stoßen fast immer auf dieselbe Zahl: 14 Sprachen × 6 Screenshots × 3 Gerätegrößen – fast dreihundert Bilder. Klickt das Marketing-Team das manuell durch, ist locker ein ganzer Arbeitstag weg, und dabei vergisst man leicht, die Uhrzeit in der Statusleiste anzupassen. Solche repetitiven Aufgaben gehören auf eine Maschine mit macOS-GUI, die man im Batch laufen lässt – nicht auf das einzige MacBook im Team.
为什么放到云端 Mac mini 上跑
Screenshots lokal auf dem Notebook zu erzeugen hat zwei handfeste Nachteile: Erstens laufen schnell vier, fünf Simulatoren gleichzeitig, der Lüfter dreht hoch und der Bildschirm ist für alles andere blockiert. Zweitens läuft die lokale Umgebung meist nicht synchron mit dem Release-Branch – der Code, mit dem die Screenshots entstehen, weicht oft von der tatsächlich eingereichten Version ab. Verlagert man den gesamten Workflow auf einen dedizierten Cloud-Mac-mini-Knoten, ergeben sich klare Vorteile:
- Beliebig viele Simulatoren laufen lassen, ohne die eigene Entwicklungsmaschine zu belasten;
- Ein fester Branch und eine feste Xcode-Version nur für die Asset-Erstellung, komplett getrennt von der Build-Umgebung;
- Nach Abschluss des Jobs das Ergebnisverzeichnis einfach per SSH synchronisieren, statt vor der Maschine zu warten.
Screenshot-Automatisierung ist im Kern nichts anderes als „ein UI-Test, der dabei Screenshots macht". Voraussetzung ist also, dass die App per UI-Test zuverlässig bis zur Zielansicht navigiert werden kann – erzwungene Logins per Tracking oder Captcha-Sperren müssen vorher über einen Test-Umgebungsschalter deaktiviert werden.
用 fastlane snapshot 搭起流水线
Zunächst snapshot im Projekt initialisieren, das erzeugt SnapshotHelper.swift und Snapfile:
cd MyApp
fastlane snapshot init
Das Snapfile ist das Herzstück der Konfiguration: Sprachenliste, Geräteliste und Ausgabeverzeichnis werden hier fest hinterlegt, damit man nicht bei jedem Lauf Parameter von Hand übergeben muss:
devices([
"iPhone 16",
"iPhone 16 Pro Max",
"iPad Pro (12.9-inch)"
])
languages([
"zh-Hans", "zh-Hant", "en-US", "ja",
"ko", "de-DE", "fr-FR", "es-ES",
"pt-BR", "ru", "it", "id",
"th", "vi"
])
scheme("MyAppUITests")
output_directory("./screenshots")
clear_previous_screenshots(true)
override_status_bar(true)
concurrent_simulators(true)
Im UI-Test genügt ein einziger Aufruf der Screenshot-Funktion auf der Zielansicht, um die Mehrsprachigkeit muss man sich nicht kümmern – fastlane arbeitet das languages-Array automatisch nacheinander ab:
func testHomeScreenshot() {
let app = XCUIApplication()
app.launch()
snapshot("01Home")
}
多模拟器并发与资源边界
Mit concurrent_simulators(true) legt fastlane automatisch so viele Simulator-Instanzen an, wie Geräte konfiguriert sind. Dass es geht, heißt aber nicht, dass man es auch ausreizen sollte – der Arbeitsspeicher ist der eigentliche Flaschenhals. Zwei Konfigurationsstufen eines Cloud Mac mini als Beispiel:
| Modell | RAM | Empfohlene parallele Simulatoren | Referenzdauer für einen vollen Durchlauf (14 Sprachen × 3 Geräte) |
|---|---|---|---|
| Mini Basic (M4/16GB) | 16GB | 3–4 | ca. 55–70 Minuten |
| Mini Standard (M4/24GB) | 24GB | 5–6 | ca. 35–45 Minuten |
Überschreitet man die empfohlene Parallelität, swappt das System die Simulator-Prozesse unter Speicherdruck auf die Platte aus – die Screenshot-Jobs werden dadurch eher langsamer statt schneller, und einzelne Sprachen brechen ab und müssen erneut laufen. Der sichere Weg: Mit xcrun simctl list devices zunächst prüfen, wie viele Simulatoren bereits laufen, und bei Überschreitung des Schwellwerts in Batches aufteilen:
xcrun simctl list devices booted
fastlane snapshot --devices "iPhone 16" --languages "zh-Hans,ja,ko"
fastlane snapshot --devices "iPhone 16" --languages "en-US,de-DE,fr-FR"
命名规范与 frameit 加框
Nach einem Durchlauf liegen mehrere hundert Bilder vor, und eine chaotische Benennung ist die häufigste Fehlerquelle beim späteren Upload in App Store Connect. Empfehlenswert ist eine dreistufige Verzeichnisstruktur Sprachcode/Gerätename/Nummer-Seitenname.png, passend zum Standardverhalten des Snapfile – keine zusätzliche eigene Benennungsebene einführen.
Sollen die Screenshots mit Gerätrahmen dargestellt werden (üblich für Marketing-Seiten, nicht für die eigentliche App-Store-Produktseite), kommt frameit zum Einsatz:
fastlane frameit
Es liest die Metadaten der Screenshots, ordnet automatisch den passenden Rahmen für das jeweilige Gerät zu und schreibt das Ergebnis gesammelt in das Verzeichnis screenshots/framed – ein manuelles Ausrichten in Photoshop Bild für Bild entfällt.
常见坑与排查
- Statusleiste nicht vereinheitlicht: Fehlt
override_status_bar(true), zeigen die Screenshots unterschiedliche Uhrzeiten, Akkustände und Signalbalken – dem Review-Team fällt sofort auf, dass die Bilder einfach auf echten Geräten mitgeschnitten wurden. - Fehlende Systemschriften verzerren das Layout: Manche Sprachen (Thai, Arabisch) rendern auf älteren iOS-Simulator-Runtimes mit falscher Zeilenhöhe. Ein Update auf die mit dem neuesten Xcode gebündelte Simulator-Runtime löst das meist.
- Rückstände der Tastatursprache: Sind Eingabefelder Teil des UI-Tests, sollte man vor dem Testlauf die Tastatureinstellungen des Simulators zurücksetzen – sonst taucht in manchen Sprach-Screenshots noch das Eingabepanel der vorherigen Sprache auf.
- Simulator-Zustand nicht zurückgesetzt: Zwischen mehreren Testläufen empfiehlt sich
xcrun simctl erase all, um alle Simulatordaten zu löschen und zu verhindern, dass Login-Status oder Caches in die Screenshots der nächsten Sprache durchsickern.
CI 集成:定时增量出图
Nicht jedes Release erfordert einen vollständigen Neu-Durchlauf aller Assets – nur Seiten mit UI-Änderungen müssen neue Screenshots bekommen. Dazu läuft auf dem Cloud Mac mini ein geplanter Job, der über den Git-Diff die betroffenen Seiten ermittelt und nur die zugehörigen UI-Testfälle erneut ausführt:
git diff --name-only HEAD~1 HEAD | grep "Screens/" > changed_screens.txt
Über einen self-hosted Runner lässt sich diese Logik in GitHub Actions einbinden: Sobald ein PR in den Release-Branch gemerged wird, startet automatisch der inkrementelle Screenshot-Lauf, den man anschließend nach kurzer manueller Prüfung gesammelt hochlädt. Läuft die gesamte Pipeline auf einem dedizierten physischen Knoten, konkurriert sie nicht mit den Build-Jobs des restlichen Teams um Ressourcen – und es muss auch keine Entwicklungsmaschine extra dafür blockiert werden.
Häufig gestellte Fragen
Wie viele Simulatoren sollten parallel laufen?
Bei einem M4 mit 16GB RAM sind 3-4 Simulatoren gleichzeitig optimal; mehr führt zu Speicherdruck und macht den Gesamtlauf durch Warteschlangen sogar langsamer, zwei Durchgänge sind dann schneller.
Wie hält man die Statusleiste über alle Screenshots konsistent?
Mit override_status_bar true im Snapfile setzt fastlane Uhrzeit auf 9:41 und Akku auf voll automatisch, eine manuelle Nachbearbeitung entfällt komplett.
Brauchen Sie einen dedizierten Mac mini für Ihre Builds?
Physische Standorte in Singapur, Tokio, Seoul, Hongkong und US-West – Mietdauer ab einem Tag, VNC-/SSH-Zugangsdaten innerhalb von 10 Minuten.
Jetzt Mac mini mieten