App-Clip-Aufruf und Host-Bundle auf einem Cloud-Mac zuverlässig prüfen

App-Clip-Aufruf und Host-Bundle auf einem Cloud-Mac zuverlässig prüfen

Dass sich ein App Clip auf dem Entwicklungs-Mac über ein Scheme starten lässt, beweist noch nicht, dass das auslieferbare Artefakt korrekt ist. Häufig übersehen werden nicht fehlgeschlagene Builds, sondern ein App Clip, der nicht in das Host-Archiv eingebettet wurde, inkonsistente Kennungen von übergeordneter und untergeordneter App oder eine Aufruf-URL, die nur den idealen Ablauf abdeckt. Erst wenn diese Prüfungen in die Continuous-Integration-Jobs auf einem Cloud-Mac integriert sind, wird jeder Commit mit derselben Xcode-Version, demselben Simulator und denselben Abnahmeskripten geprüft.

Zuerst ein überprüfbares Lieferergebnis definieren

„Build Succeeded“ darf nicht das einzige Erfolgskriterium sein. Eine vollständige Abnahme sollte mindestens das .xcarchive des Hosts, ein separates Build-Protokoll des App Clips, die ausgewerteten Entitlements-Dateien und eine Aufzeichnung der Aufrufszenarien erzeugen. Test-URLs sollten in der Repository-Konfiguration hinterlegt werden, statt über persönliche Scheme-Einstellungen verteilt zu sein.

Prüfebene Eingabe Erfolgskriterium
Build App Clip Scheme Das Simulator-Target lässt sich bauen
Einbettung Host-Archiv Unter AppClips ist der Clip vorhanden
Zuordnung Kennungen und Entitlements beider Apps Die Eltern-Kind-Beziehung ist konsistent
Aufruf Basis-URL, parametrisierte URL und fehlerhafte URL Routing und Fallback verhalten sich wie erwartet

Der separate Start des Clips überprüft den fachlichen Einstiegspunkt. Erst die Archivierung des Hosts mit anschließender Kontrolle der Einbettung bestätigt die auslieferbare Struktur. Beide Prüfungen können einander nicht ersetzen.

Build-Verzeichnis stabil festlegen

Cloud-Jobs sollten ein separates DerivedData-Verzeichnis verwenden, damit Artefakte eines vorherigen Laufs keine Fehler in der Kopierphase verdecken. Bauen Sie zunächst die Simulator-Version des App Clips und archivieren Sie anschließend den Host. Werden die Scheme-Namen über Umgebungsvariablen übergeben, lässt sich dasselbe Skript für verschiedene Branches wiederverwenden.

set -euo pipefail

ROOT="$PWD"
OUT="$ROOT/.ci-artifacts"
DERIVED="$OUT/DerivedData"
ARCHIVE="$OUT/HostApp.xcarchive"

rm -rf "$OUT"
mkdir -p "$OUT"

xcodebuild \
  -workspace "$WORKSPACE" \
  -scheme "$CLIP_SCHEME" \
  -sdk iphonesimulator \
  -destination "$SIMULATOR_DESTINATION" \
  -derivedDataPath "$DERIVED" \
  clean build | tee "$OUT/app-clip-build.log"

xcodebuild \
  -workspace "$WORKSPACE" \
  -scheme "$HOST_SCHEME" \
  -destination "generic/platform=iOS" \
  -archivePath "$ARCHIVE" \
  archive | tee "$OUT/host-archive.log"

SIMULATOR_DESTINATION kann auf einen in der Pipeline installierten Gerätetyp und eine bestimmte Systemversion festgelegt werden. Aktualisieren Sie nach einem Xcode-Upgrade zuerst den Baseline-Job. Ein gewöhnlicher Feature-Commit sollte nicht nebenbei auch die Testlaufzeitumgebung ändern.

Bundle-Beziehung zwischen Host und Clip prüfen

Eingebettetes Artefakt finden

Suchen Sie nach Abschluss der Archivierung unter Products/Applications nach der .app des Hosts. Prüfen Sie anschließend, ob deren Verzeichnis AppClips genau das erwartete Target enthält. Verlassen Sie sich nicht auf einen fest vorgegebenen Dateinamen der App, sondern suchen Sie anhand der Erweiterung und kontrollieren Sie die Anzahl der Ergebnisse.

HOST_APP="$(find "$ARCHIVE/Products/Applications" -maxdepth 1 -name '*.app' -print -quit)"
CLIP_APP="$(find "$HOST_APP/AppClips" -maxdepth 1 -name '*.app' -print -quit)"

test -n "$HOST_APP"
test -n "$CLIP_APP"

HOST_ID="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleIdentifier' "$HOST_APP/Info.plist")"
CLIP_ID="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleIdentifier' "$CLIP_APP/Info.plist")"

printf '%s
' "$HOST_ID" > "$OUT/host-bundle-id.txt"
printf '%s
' "$CLIP_ID" > "$OUT/clip-bundle-id.txt"

Fehlt das Verzeichnis AppClips, prüfen Sie zuerst die Einbettungsphase des Host-Targets, ob das Clip-Target zum aktuell archivierten Scheme gehört und ob die Release-Konfiguration jene Einstellungen übernimmt, die unter Debug funktionieren.

Endgültige Entitlements vergleichen

Die Deklarationen in den Projektdateien entsprechen nicht zwangsläufig dem endgültigen Inhalt des signierten Artefakts. Exportieren Sie die Entitlements von Host und Clip jeweils mit codesign -d --entitlements :- und überführen Sie sie anschließend mit plutil in ein stabiles Format. Das Gate muss sicherstellen, dass der Wert für die übergeordnete App des Clips auf den aktuellen Host verweist. Zugleich sind Funktionen einzuschränken, die nicht übernommen werden dürfen.

codesign -d --entitlements :- "$HOST_APP" > "$OUT/host-entitlements.plist"
codesign -d --entitlements :- "$CLIP_APP" > "$OUT/clip-entitlements.plist"

plutil -lint "$OUT/host-entitlements.plist"
plutil -lint "$OUT/clip-entitlements.plist"

Vergleichen Sie nicht einfach die kompletten Dateien als Text, da sich die Reihenfolge der Schlüssel zwischen Xcode-Versionen ändern kann. Extrahieren Sie stattdessen die Schlüssel, die stabil bleiben müssen, und vergleichen Sie diese einzeln. Schreiben Sie außerdem die tatsächlichen Werte in die Build-Artefakte, damit sie nach einem Fehler überprüft werden können.

Routing mit drei URL-Typen prüfen

Die Aufruftests müssen mindestens den Basiseinstieg, gültige Parameter und fehlerhafte Eingaben abdecken. Der Basiseinstieg sollte beispielsweise die leichte Standardansicht öffnen. Eine URL mit Ressourcenkennung muss zum angegebenen Inhalt führen. Fehlende oder ungültige Parameter sollten dagegen auf eine sichere Seite zurückfallen, statt eine leere Ansicht anzuzeigen.

URL als Testeingabe verwenden

Die Verwendung von _XCAppClipURL im App Clip Scheme eignet sich für die manuelle Fehlersuche. Die Continuous Integration sollte jedoch nicht vom lokalen Scheme-Zustand einzelner Entwickler abhängen. Robuster ist es, den Routing-Parser eine URL entgegennehmen zu lassen und die Eingaben direkt mit Unit-Tests abzudecken. Ergänzend bleibt ein Smoke-Test im Simulator bestehen, der den Lebenszyklus der App überprüft.

func testInvocationRoutes() throws {
    let base = try XCTUnwrap(URL(string: invocationBaseURL))
    XCTAssertEqual(router.route(for: base), .home)

    let item = try XCTUnwrap(URL(string: invocationItemURL))
    XCTAssertEqual(router.route(for: item), .item(id: "42"))

    let malformed = try XCTUnwrap(URL(string: invocationMalformedURL))
    XCTAssertEqual(router.route(for: malformed), .fallback)
}

So lassen sich Domainauflösung, Pfadabgleich, Validierung von Abfrageparametern und Start der Benutzeroberfläche voneinander trennen. Die Routing-Unit-Tests decken alle Verzweigungen ab, während der Simulator-Job nur bestätigt, dass der reale Prozess startet und die erste Ansicht darstellt. Dadurch lässt sich die Fehlerursache direkter eingrenzen.

Gates verschärfen und Fehlerzustand sichern

Schlägt ein Gate fehl, müssen mindestens die xcodebuild-Protokolle, beide Info.plist-Dateien, die exportierten Entitlements-Dateien, die Kennungen von Host und Clip sowie die Namen der fehlgeschlagenen Testfälle archiviert werden. Enthalten die Protokolle Zugriffstoken, temporäre Zugangsdaten oder vertrauliche Bestandteile lokaler Pfade, müssen diese Informationen vor dem Upload maskiert werden.

Die Prüfungen sollten in einer festen Reihenfolge ausgeführt werden: separates Build-Verzeichnis bereinigen, Clip bauen, Host archivieren, Einbettung kontrollieren, wichtige Entitlements vergleichen, Routing-Tests ausführen und den Smoke-Test im Simulator starten. Schlägt eine vorgelagerte Strukturprüfung fehl, sollte der Job sofort beendet werden, damit keine Simulatorzeit für ein fehlerhaftes Archiv verbraucht wird.

Auch Jobs auf GPUMini sollten xcodebuild -version, das ausgewählte SDK und die verwendete Simulator-Laufzeit explizit protokollieren. Langfristig gepflegt werden muss nicht der Screenshot eines einzelnen erfolgreichen Laufs, sondern eine Reihe von Prüfungen mit klar definierten Eingaben, nachvollziehbaren Artefakten und schnell reproduzierbaren Fehlern.

Häufig gestellte Fragen

Reicht ein Build des App-Clip-Targets aus?

Nein. Er findet Kompilierungsfehler, bestätigt aber weder die Einbettung im Host-Archiv noch passende Kennungen und endgültige Berechtigungen.

Sollte nur eine feste Aufruf-URL getestet werden?

Nein. Prüfen Sie eine Basisroute, eine Route mit Parametern und fehlerhafte Eingaben, damit Routing, Auswertung und sichere Rückfallebene abgedeckt sind.

Warum ist eine Archivprüfung trotz erfolgreichem lokalem Start nötig?

Ein lokales Scheme kann den Clip direkt starten. Dadurch bleiben Fehler in Kopierphase, Host-Zuordnung oder Berechtigungen möglicherweise unentdeckt.

Exklusiver physischer Knoten

Für Entwicklungs- und Build-Aufgaben einen Cloud-Mac auswählen

Zwei M4-Konfigurationen, vier Mietzeiträume und vier verfügbare Knoten vergleichen und anschließend die Bereitstellung passend zur Aufgabe abschließen.

Konfiguration auswählen und bestellen