Wenn dasselbe iOS-Projekt gleichzeitig mit Entwicklungs-, Staging- und Produktionsdiensten verbunden ist, besteht der gefährlichste Fehler meist nicht darin, dass die Kompilierung fehlschlägt, sondern dass erfolgreich ein Archiv für die falsche Umgebung erstellt wird. Gelangen eine Entwicklungsadresse, aktivierte Protokollierung oder interne Feature-Flags in das Release-Paket, kann die Pipeline trotzdem grün bleiben. Zuverlässiger ist es, öffentliche Konfigurationen in Ebenen zu verwalten, den Build-Einstiegspunkt fest vorzugeben und die Archivprüfung als festen Release-Schritt zu behandeln, statt darauf zu vertrauen, dass jemand in Xcode den richtigen Menüpunkt auswählt.
Grenze zwischen Konfiguration und Geheimnissen festlegen
xcconfig eignet sich für Build-Parameter, die zusammen mit dem Client öffentlich werden dürfen, etwa die API-Basis-URL, ein Bundle-ID-Suffix, die Protokollierungsstufe oder Standardwerte für Feature-Flags. Es ist kein Tresor für Geheimnisse. Jeder Wert, der in den Client-Build einfließt, kann später in Info.plist, Ressourcendateien, Compiler-Parametern oder der ausführbaren Datei auftauchen.
Die Entscheidungsregel ist einfach: Wenn Benutzer einen Wert auch nach Erhalt des Installationspakets nicht kennen dürfen, darf Xcode ihn nicht in die App einbauen.
Administrationsschlüssel für Server, Zugangsdaten für Signaturdienste und Token mit Schreibrechten gehören auf den Server oder in einen kontrollierten CI-Anmeldedatenspeicher. Der Client sollte ausschließlich kurzlebige, eingeschränkte und widerrufbare Autorisierungsergebnisse erhalten. Auch wenn die CI Geheimnisse über Umgebungsvariablen einschleust, ändert das nichts daran, dass sich das fertige Artefakt analysieren lässt.
Erstellen Sie zunächst eine Konfigurationsliste und vermerken Sie für jeden Eintrag, ob er öffentlich sein darf, aus welcher Quelle er stammt und wo er nach der Archivierung voraussichtlich zu finden ist. Das Team prüft diese Liste und nicht Dutzende über die Build Settings verstreute Werte.
Prüfbare xcconfig-Ebenen aufbauen
Es empfiehlt sich, gemeinsame Einstellungen, umgebungsspezifische Abweichungen und lokale Überschreibungen voneinander zu trennen:
Config/
Base.xcconfig
Development.xcconfig
Staging.xcconfig
Production.xcconfig
LocalOverrides.xcconfig.example
In Base.xcconfig stehen ausschließlich Werte, die für alle Umgebungen gelten. Jede umgebungsspezifische Datei bindet sie zunächst ein und überschreibt anschließend nur wenige abweichende Werte:
#include "Base.xcconfig"
APP_ENVIRONMENT = staging
API_BASE_URL = https:/$()/staging-api.invalid
ENABLE_VERBOSE_LOGGING = YES
PRODUCT_BUNDLE_IDENTIFIER = com.example.product.staging
Das $() verhindert hier, dass der doppelte Schrägstrich in der URL als Kommentar interpretiert wird. Die Beispieldomain ist lediglich ein nicht auflösbarer Dokumentationswert und muss in einem echten Projekt durch die eigene Dienstadresse ersetzt werden.
Lokale Überschreibungsdateien gehören nicht ins Repository. Mit einer optionalen Einbindung lässt sich die Hürde beim ersten Checkout senken:
#include? "LocalOverrides.xcconfig"
Lokale Überschreibungen dürfen jedoch nur der bequemeren Entwicklung dienen und keinesfalls zu einer impliziten Eingabe für offizielle Archive werden. Die Produktionskonfiguration muss sich auch ohne diese Datei vollständig auflösen lassen. Ordnen Sie die drei Configurations Development, Staging und Release jeweils der zugehörigen Datei zu und stellen Sie sicher, dass das in der CI verwendete Scheme als Shared markiert ist.
Build-Einstiegspunkt für die Kommandozeile festlegen
Archivierungsaufträge auf einem Cloud-Mac dürfen keinen Zustand übernehmen, den eine frühere Bedienung der grafischen Oberfläche hinterlassen hat. Workspace, Scheme, Configuration und Ausgabepfad müssen explizit angegeben werden:
set -euo pipefail
WORKSPACE="App.xcworkspace"
SCHEME="App"
CONFIGURATION="Release"
ARCHIVE_PATH="$PWD/build/App.xcarchive"
xcodebuild \
-workspace "$WORKSPACE" \
-scheme "$SCHEME" \
-configuration "$CONFIGURATION" \
-showBuildSettings > build-settings.txt
xcodebuild \
-workspace "$WORKSPACE" \
-scheme "$SCHEME" \
-configuration "$CONFIGURATION" \
-archivePath "$ARCHIVE_PATH" \
clean archive
Aufgelöste Einstellungen vor der Archivierung prüfen
Prüfen Sie nicht nur die Quelldateien, sondern die Einstellungen, die Xcode tatsächlich aufgelöst hat. Die entscheidenden Werte lassen sich aus build-settings.txt auslesen und für die Produktionsumgebung mit verbindlichen Assertions absichern:
grep -E "APP_ENVIRONMENT|API_BASE_URL|PRODUCT_BUNDLE_IDENTIFIER|ENABLE_VERBOSE_LOGGING" \
build-settings.txt
grep -q "APP_ENVIRONMENT = production" build-settings.txt
grep -q "ENABLE_VERBOSE_LOGGING = NO" build-settings.txt
Verwendet das Projekt mehrere Targets, muss jedes Target einzeln geprüft werden, da Erweiterungen, Test-Bundles und die Haupt-App unterschiedliche Base Configurations erben können. Das Skript sollte außerdem den aktuellen Git-Commit, die Xcode-Version und das verwendete Scheme ausgeben, damit sich der genaue Zustand bei Abweichungen rekonstruieren lässt.
Das tatsächlich ausgelieferte Archiv scannen
Korrekte Build Settings garantieren noch kein korrektes Artefakt. Run Scripts, generierter Code oder Schritte zum Kopieren von Ressourcen können weiterhin Testkonfigurationen in das Archiv einschleusen. Nach der Archivierung sollten mindestens die Property List der Haupt-App, eingebettete Ressourcen und Zeichenfolgen in der ausführbaren Datei geprüft werden.
APP_PATH="$(find build/App.xcarchive/Products/Applications -maxdepth 1 -name '*.app' -print -quit)"
test -n "$APP_PATH"
plutil -p "$APP_PATH/Info.plist"
if grep -RInaE "staging-api|debug-token|INTERNAL_ONLY" "$APP_PATH"; then
echo "forbidden marker found in archive" >&2
exit 1
fi
EXECUTABLE_NAME=$(/usr/libexec/PlistBuddy -c "Print :CFBundleExecutable" "$APP_PATH/Info.plist")
if strings "$APP_PATH/$EXECUTABLE_NAME" | grep -E "staging-api|debug-token|INTERNAL_ONLY"; then
echo "forbidden marker found in executable" >&2
exit 1
fi
Für den Scan sollten vom Team definierte Kennzeichnungen verwendet werden. Echte Geheimnisse dürfen nicht direkt in Skripte oder Protokolle geschrieben werden. Empfehlenswert sind zwei kurze Listen mit erlaubten und verbotenen Vorkommen, damit gewöhnliche Wörter keine Fehlalarme auslösen. In den Scan-Ergebnissen sollten nur Dateipfad und Regelname gespeichert werden, nicht der vollständige Inhalt eines sensiblen Treffers.
| Prüfobjekt | Zu prüfende Inhalte | Vorgehen bei Fehlern |
|---|---|---|
| Finale Build Settings | Umgebungsname, Bundle-ID, Protokollierungsschalter | Archivierung sofort stoppen |
| Info.plist | Dienstadresse, URL Scheme, Umgebungskennzeichnung | Export blockieren |
| Ressourcenverzeichnis der App | Debug-Konfiguration, Testdaten, temporäre Dateien | Quelle entfernen und neu bauen |
| Ausführbare Datei | Merkmale interner Adressen, Token-Kennzeichnungen | Erzeugungsschritt ermitteln und betroffene Zugangsdaten rotieren |
Häufige Abweichungen und Irrtümer vermeiden
Eine besonders häufige Ursache für Abweichungen ist ein Scheme, das lokal vorhanden, aber nicht geteilt ist. Fehlen die zugehörigen xcshareddata im Repository, kann die CI das Scheme möglicherweise nicht finden, oder ein Entwickler weicht vorübergehend auf einen anderen Einstiegspunkt aus. Ein weiteres Problem entsteht, wenn der Umgebungsname in Skriptverzweigungen festgelegt wird, ohne die Configuration als einzige maßgebliche Quelle zu verwenden. Mit der Zeit bilden sich dadurch zwei voneinander unabhängige Entscheidungslogiken.
Ein weiterer Irrtum besteht in der Annahme, eine Variable sei sicher, sobald sie verschleiert, aufgeteilt oder in eine Binärdatei geschrieben wurde. Langfristig gültige Geheimnisse lassen sich in einem Client nicht zuverlässig verbergen. Wird festgestellt, dass ein Geheimnis in ältere Archive gelangt ist, müssen zunächst die Zugangsdaten widerrufen oder rotiert und anschließend die Build-Konfiguration korrigiert werden. Nur die Zeichenfolge aus dem aktuellen Branch zu entfernen, beseitigt nicht das Risiko bereits ausgelieferter Versionen.
Wird dieser Ablauf auf festen physischen Nodes von MangoVM ausgeführt, sollte der Runner außerdem für jeden Auftrag ein sauberes Arbeitsverzeichnis verwenden. DerivedData, temporäre Konfigurationen und Exportverzeichnisse aus dem vorherigen Auftrag dürfen nicht wiederverwendet werden. Bereinigungen müssen auf den Workspace des aktuellen Auftrags beschränkt bleiben, damit parallel laufende Jobs sich nicht gegenseitig Dateien löschen.
Prüfungen als Merge- und Release-Gates einsetzen
Der Ablauf lässt sich schließlich in zwei Phasen aufteilen: In der Merge-Request-Phase werden die Einstellungen aufgelöst und die Struktur der Konfigurationsdateien geprüft. In der Release-Phase folgen die vollständige Archivierung und der Scan des Artefakts. Die erste Phase liefert schnelles Feedback, während die zweite das tatsächlich auszuliefernde Produkt als Maßstab verwendet. Jede fehlgeschlagene Umgebungs-Assertion muss einen Status ungleich null zurückgeben und darf nicht nur einen Hinweis im Protokoll erzeugen.
Vor dem Abschluss können Sie folgende Checkliste verwenden:
- Das Scheme ist geteilt, und die Zuordnung zwischen Configuration und xcconfig steht unter Versionskontrolle;
- für das Produktionsarchiv werden Workspace, Scheme und Configuration explizit angegeben;
- Umgebungsname, Bundle-ID und Protokollierungsschalter in
showBuildSettingsentsprechen den Erwartungen; - die Haupt-App und sämtliche Erweiterungen wurden durch Scans der Property Lists und Zeichenfolgen geprüft;
- CI-Protokolle geben keine vollständigen Variablenwerte aus;
- temporäre Überschreibungsdateien werden nach Abschluss des Auftrags gelöscht;
- nach einem Datenleck werden zuerst die Zugangsdaten rotiert und anschließend das Archiv neu erstellt und erneut geprüft.
Wenn Konfigurationsquelle, aufgelöste Einstellungen und finales Artefakt drei Belegebenen bilden, hängt die Auswahl der Umgebung nicht mehr von Bediengewohnheiten ab. Ein Release-Fehler wird erkannt, bevor das Archiv die Pipeline verlässt – und nicht erst von Benutzern, die ihn anstelle des Teams entdecken.
Häufig gestellte Fragen
Darf ein geheimer API-Schlüssel in einer xcconfig-Datei stehen?
Nein. Build-Werte können in Info.plist, Compileroptionen, Ressourcen oder der ausführbaren Datei landen. Ein App-Archiv gilt als öffentlich; privilegierte Schlüssel gehören deshalb ausschließlich auf den Server.
Warum archiviert die CI eine andere Umgebung als der lokale Mac?
Häufig fehlen ein geteiltes Scheme, eine korrekte Configuration-Zuordnung oder Variablen außerhalb der interaktiven Shell. Workspace, Scheme und Configuration sollten explizit gesetzt und showBuildSettings protokolliert werden.
Einen dedizierten Cloud-Mac für Ihre Entwicklungs-Pipeline konfigurieren
MangoVM bietet dedizierte physische Knoten mit Apple Silicon in den Varianten M4 und M4 Pro. Wählen Sie Laufzeit, Region und zusätzliche Speicheroptionen, um die vollständigen Bestelldetails zu prüfen.