iOS Continuous Integration mit Xcode Server erklärt

Veröffentlicht: 2022-03-11

Einführung

Vor Xcode 9 war die Verwendung von Apple Continuous Integration Tools ein langwieriger und komplexer Prozess, der den Kauf und die Installation einer zusätzlichen macOS Server-App erforderte. Dies führte dazu, dass viele Entwickler die Idee der kontinuierlichen Integration für ihre iOS-Projekte verwarfen oder auf Lösungen von Drittanbietern zurückgriffen, mit sehr unterschiedlichem Erfolg.

Nach der Veröffentlichung von Xcode 9.0 im September 2017 wurde der Prozess jedoch stark vereinfacht, einschließlich der Option zum automatisierten Codesignieren, und ist jetzt vollständig in Xcode integriert. Daher sind keine zusätzlichen Apps oder Tools erforderlich.

Während Lösungen von Drittanbietern wie Fastlane, Bluepill usw. eine große Hilfe sind und eine Menge Routinearbeit für Sie erledigen können, wird dieser Artikel die Möglichkeiten der Verwendung von Xcode- und Apple-Tools allein für Ihre kontinuierlichen Integrationsanforderungen untersuchen. Wir werden auch die manuelle Codesignierung verwenden, da dies für viele Menschen oft ein Problem zu sein scheint und die automatische Signierung auch nicht die optimale Lösung ist, wenn es um mehrere Build-Konfigurationen geht.

Hinweis: Dieser Artikel basiert auf Xcode 9.4.1 und konzentriert sich auf die Entwicklung von iOS-Apps, aber vieles davon gilt für Xcode 10 (derzeit als Beta-5-Build verfügbar) und die Entwicklung von macOS-Apps.

Xcode-Server einrichten

Neben der Vereinfachung des eigentlichen Integrationsprozesses vereinfachte Xcode 9 auch den Einrichtungsprozess von Xcode Server.

Starten Sie die Xcode-App auf Ihrem macOS-Computer, der als CI-Server bestimmt wurde, und öffnen Sie die Einstellungen.

Navigieren Sie zur letzten Registerkarte namens Server & Bots .

Continuous Integration Tools: Screenshot der Registerkarte „Server & Bots“.

Aktivieren Sie die Xcode Server-Funktionen, indem Sie auf den Schalter in der oberen rechten Ecke klicken. Anschließend werden Sie aufgefordert, einen Benutzer auszuwählen, der Build-Skripts auf diesem Computer ausführen und ausführen soll. Es ist wahrscheinlich eine gute Idee, nur für diesen Zweck einen dedizierten Benutzer zu haben, anstatt einen bereits vorhandenen zu verwenden.

Beachten Sie, dass dieser Benutzer beim System angemeldet sein muss, damit ein Xcode-Bot ausgeführt werden kann. Nach der Anmeldung sollten Sie neben dem Benutzernamen einen grünen Kreis sehen.

Xcode Server und Bots nach erfolgreicher Anmeldung

Das ist es! Werfen wir einen genaueren Blick auf Xcode-Bots.

So konfigurieren Sie Xcode-Bots

Jetzt können Sie mit der Konfiguration von Xcode-Bots für die Ausführung auf diesem Server beginnen. Dies kann auf jedem Entwicklungscomputer erfolgen, der mit demselben Netzwerk wie der Server verbunden ist.

Öffnen Sie Xcode auf Ihrem Entwicklungscomputer und klicken Sie im oberen Menü auf Xcode > Einstellungen . Gehen Sie dann zur Registerkarte Konten und klicken Sie auf das Symbol + in der unteren linken Ecke. Wählen Sie im angezeigten Dialogfeld Xcode-Server aus.

Screenshot der Auswahl des Kontotyps

Um einen Bot zu erstellen, öffnen Sie einfach Ihr Projekt in Xcode und wählen Sie die Option Produkt > Bot erstellen… aus dem oberen Menü. Das Bot-Setup umfasst eine Reihe von Schritten, die wir in den kommenden Abschnitten untersuchen werden.

Automatisierung der App-Verteilung

Eine der häufigsten Anwendungen der iOS-App-Build-Automatisierung ist die Konfiguration eines Bots zum Hochladen einer App auf eine iOS-Verteilungsplattform wie TestFlight, Fabric usw.

Wie ich bereits erklärt habe, wird dieser Artikel nur das Hochladen auf App Store Connect und das direkte Herunterladen von Ihrem Xcode-Server untersuchen, da dies die nativen Tools von Apple für die Verteilung von iOS-Apps sind.

App Store Connect-Verteilung mit Xcode

Stellen Sie vor dem Konfigurieren eines Bots sicher, dass Sie über einen App Store Connect-App-Datensatz verfügen, der mit der Bundle-ID Ihres App-Entwicklungsprojekts übereinstimmt. Es ist auch erwähnenswert, dass jeder Build eine eindeutige Kennung haben muss, die aus der Build-Version und der Build-Nummer besteht. Wir werden untersuchen, wie Sie sicherstellen können, dass diese Bedingungen erfüllt sind, wenn wir später die Xcode-Bot-Einstellungen besprechen.

Schritt 1: Das Einrichten der richtigen Build-Konfiguration ist der entscheidende Schritt, um das zu bekommen, was Sie wollen. Stellen Sie sicher, dass Sie das Schema und die Konfiguration auswählen, die die App hervorbringen, die Sie in App Store Connect hochladen möchten. Dazu gehört sicherzustellen, dass die Build-Konfiguration die entsprechende Bundle-ID verwendet, die im Apple Developer Portal Ihres Teams (dies wird für Codesignaturen verwendet) sowie in Ihrem App Store Connect-Portal (dies wird für das automatische Hochladen der App verwendet) registriert ist. .

Schritt 2: Während wir uns noch auf der Registerkarte „Konfiguration“ befinden, müssen wir die Exportoptionen festlegen. Wir werden uns die Eigenschaftsliste der Exportoptionen ansehen, stellen Sie also sicher, dass „Use Custom Export Options Plist“ ausgewählt ist.

Schritt 3: Jetzt ist es an der Zeit, dass wir unsere Eigenschaftsliste für Exportoptionen erstellen. Eine vollständige Liste der in dieser Datei zu verwendenden Schlüssel ist verfügbar, wenn Sie xcodebuild --help , aber wir werden die in dieser Bot-Konfiguration verwendeten hier untersuchen:

  • compileBitcode – Bitcode ist Apples vorläufiges Ausgabeformat für den App-Quellcode. Mit anderen Worten, es ist das Format, in das Ihr Quellcode konvertiert wird, bevor er in Maschinencode für eine bestimmte Architektur kompiliert wird. Es zielt darauf ab, einen einzelnen Code-Container zu haben, der weiter optimiert werden kann, wenn eine Optimierung im Befehlssatz vorgenommen wird, und ihn auch aus demselben Format für zukünftige Architekturen kompilieren zu können. Dies hat jedoch keine Auswirkungen auf Ihre Bewerbung. Es liegt an Ihnen, zu entscheiden, ob Sie es aktivieren möchten oder nicht.
  • method – Dieses Argument gibt an, welche Art von Produkt Sie exportieren. Apple unterscheidet Produkte nach ihrer festgelegten Zielgruppe – die Entwicklung erlaubt Ihnen nur, sie auf Geräten zu installieren, die im Bereitstellungsprofil angegeben sind, Unternehmen erlauben es jedem, sie zu installieren, aber sie müssen diesem Entwicklungsprofil ausdrücklich vertrauen, bevor sie die App ausführen, und der App-Store ist für Verteilung an den App Store oder App Store Connect, also werden wir diesen Wert verwenden.
  • provisioningProfiles – Dies ist selbsterklärend. Hier sind jedoch einige Dinge zu beachten: Die Bereitstellungsprofile in der Eigenschaftsliste der Exportoptionen sind ein Wörterbuch, in dem ein Schlüssel der Bundle-ID eines Produkts entspricht und der Wert dem Namen des Bereitstellungsprofils entspricht, das zum Cosignieren verwendet wird.
  • signingCertificate – Ein weiteres selbsterklärendes Argument. Der Wert dieses Felds kann ein vollständiger Zertifikatsname oder ein SHA-1-Hash sein.
  • teamID – Ein weiteres selbsterklärendes Argument. Dies ist die 10 Zeichen lange Kennung, die Apple Ihrer Organisation zugeteilt hat, als Sie sich für das Apple Developer Program angemeldet haben.
  • uploadBitcode – Ob Bitcode hochgeladen werden soll oder nicht (wenn Sie sich dafür entschieden haben, darin zu kompilieren), damit er in AppStore Connect verwendet werden kann, um neue optimierte Builds oder Builds für zukünftige Architekturen zu generieren.
  • uploadSymbols – Lädt Ihre Debug-Symbole hoch, sodass Sie einen aussagekräftigen Absturzbericht erhalten und nicht nur einen Speicherauszug und einen Assembly-Stack.

Nun könnte Ihre Eigenschaftsliste für Exportoptionen in etwa so aussehen:

 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>compileBitcode</key> <false/> <key>method</key> <string>app-store</string> <key>provisioningProfiles</key> <dict> <key>com.bundle.id</key> <string>ProvisioningProfileName</string> </dict> <key>signingCertificate</key> <string>Signing Certificate Exact Name or SHA-1 hash value</string> <key>teamID</key> <string>??????????</string> <key>uploadBitcode</key> <false/> <key>uploadSymbols</key> <true/> </dict> </plist>

Schritt 4: Wählen Sie die von Ihnen erstellte .plist als Eigenschaftsliste der Exportoptionen aus.

Schritt 5: Als nächstes kommt die Registerkarte „Zeitplan“ – richten Sie sie nach Ihren Wünschen ein.

Schritt 6: Deaktivieren Sie auf der Registerkarte „Signieren“ die Option „Xcode Server erlauben, meine Zertifikate und Profile zu verwalten“ und laden Sie selbst ein passendes Signaturzertifikat und Bereitstellungsprofil auf der Seite „Zertifikate und Profile “ hoch.

Schritt 7: Die Registerkarte Geräte sollte unverändert bleiben, da wir die App hochladen, anstatt sie zu testen.

Schritt 8: Auf der Registerkarte Argumente können Sie explizit xcodebuild-Argumente oder Umgebungsvariablen festlegen, die in Ihren Build- oder Prä-Integrations- und Post-Integrations-Skripten verwendet werden können.

Schritt 9: Schließlich erreichen wir die Registerkarte Triggers , die auch die letzte Registerkarte bei der Konfiguration des Xcode Continuous Integration Bots ist. Dies ist das leistungsstärkste Tool im Arsenal von Xcode Server. Für den Anfang füge ich gerne die folgenden zwei Befehle als Vorintegrationsskript hinzu:

 #!/bin/sh set printenv

Der erste druckt alle Variablen, die Xcode Server verwendet, und ihre Werte im aktuellen Integrationslauf. Der zweite gibt alle Umgebungsvariablen und ihre Werte aus. Wie erwartet kann dies beim Debuggen Ihrer Skripts hilfreich sein, daher nenne ich es treffend „Debug-Informationen“.

Denken Sie daran, dass wir erwähnt haben, dass wir sicherstellen müssen, dass jeder auf App Store Connect hochgeladene Build ein eindeutiges Paar aus Build-Version und Build-Nummer haben muss. Wir können das integrierte PlistBuddy-Tool verwenden, aber wir brauchen auch eine Möglichkeit, eine eindeutige Build-Nummer zu haben. Eine Sache, die während der Xcode Server-Integration immer vorhanden ist – und praktischerweise auch eindeutig ist – ist die Integrationsnummer, da sie automatisch erhöht wird. Wir erstellen ein weiteres Vorintegrationsskript mit dem Namen „set build number“ mit folgendem Inhalt, um sicherzustellen, dass wir jedes Mal eine eindeutige Build-Nummer haben:

 #!/bin/sh buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${PROJECT_DIR}/${INFOPLIST_FILE}") buildNumber=$XCS_INTEGRATION_NUMBER /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "${PROJECT_DIR}/${INFOPLIST_FILE}"

Wenn Sie CocoaPods verwenden und sich entschieden haben, das Pods-Verzeichnis nicht an Ihr DVCS zu übergeben, sollten Sie auch ein Vorintegrationsskript mit den folgenden Inhalten einfügen:

 #!/bin/sh cd $XCS_PRIMARY_REPO_DIR pod install

Schritt 10: Wir sind fast fertig, aber wir haben nirgendwo angegeben, dass wir den Build auf AppStore Connect oder auf welches Konto hochladen möchten. Zu diesem Zweck fügen wir ein Post-Integration-Skript und ein weiteres integriertes Tool namens Application Loader hinzu. Folgendes in das Skript einfügen:

 #!/bin/sh /Applications/Xcode.app/Contents/Applications/Application\ Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Support/altool --upload-app -f $XCS_PRODUCT -u $TESTFLIGHT_USERNAME -p $TESTFLIGHT_PASSWORD

Das $XCS_PRODUCT ist eine Xcode Server-Variable und enthält den Pfad zu der App, die im aktuellen Integrationslauf erstellt wurde. Allerdings sind $TESTFLIGHT_USERNAME und $TESTFLIGHT_PASSWORD weder System- noch Xcode Server-Variablen. Diese müssen von Ihnen eingerichtet werden und den Wert Ihrer Apple-ID und Ihres Passworts haben. Leider hat Apple die Unterstützung für das Generieren eines API-Schlüssels für das Hochladen von AppStore Connect-Builds eingestellt. Da es sich um vertrauliche Informationen handelt, empfiehlt es sich, sie direkt auf dem Mac-Server (vorausgesetzt, es handelt sich um Ihre eigenen) als Umgebungsvariable und nicht in der Xcode Server-Bot-Konfiguration einzurichten.

Xcode-Serververteilung

Der Xcode Server-Verteilungsbot verwendet tatsächlich dieselbe Konfiguration wie die für die App Store Connect-Verteilung, mit Ausnahme der Post-Integration-Skripts. Das Herunterladen und Installieren der Anwendung kann jedoch immer noch schwierig sein. Sie müssen weiterhin sicherstellen, dass das Bereitstellungsprofil, mit dem Sie Ihre App signiert haben, die Installation der App auf dem von Ihnen verwendeten Gerät zulässt.

Danach müssen Sie Safari auf Ihrem iOS-Gerät öffnen und zum Xcode Server-Web-Dashboard Ihres Servers navigieren. Wenn der Name Ihres Servers beispielsweise „Mac-Server“ lautet, finden Sie ihn unter „mac-server-name.local/xcode“, wenn Sie sich im selben Netzwerk wie der Server befinden. Dort finden Sie eine Liste aller Ihrer Xcode-Bots und die Statistiken ihrer neuesten Integrationen.

Wählen Sie diejenige aus, die die App erstellt hat, die Sie herunterladen möchten. Auf dem folgenden Bildschirm haben Sie zwei Schaltflächen – Installieren und Profil . Wenn Sie zum ersten Mal von diesem Server herunterladen, müssen Sie auf Profil klicken, um das Zertifikat zur Liste der vertrauenswürdigen Quellen hinzuzufügen. Klicken Sie anschließend auf derselben Seite auf die Schaltfläche „ Installieren “ und Sie werden mit dem iOS-Bestätigungsdialogfeld „Sind Sie sicher, dass Sie * auf Ihrem Gerät installieren möchten?“ begrüßt. Bestätigen Sie es, indem Sie auf Ja klicken, und Ihre App wird installiert und kann vom Startbildschirm aus ausgeführt werden.

Screenshot der App-Installationsoptionen

Bei iOS 10.3 und höher kann ein Grund für das Scheitern mit „Cannot connect to *.local“ darin liegen, dass dem selbstsignierten Zertifikat manuell in den Einstellungen auf dem Testgerät vertraut werden muss.

Folge diesen Schritten:

Schritt 1: Installieren Sie selbstsignierte Zertifikate von der Bots-Seite des Xcode-Servers auf Ihrem iPhone.

Schritt 2: Gehen Sie zu den iPhone- Einstellungen > Allgemein > Info > Zertifikatsvertrauenseinstellungen .

Schritt 3: Suchen Sie das/die selbstsignierte(n) Zertifikat(e) Ihres Servers unter dem Abschnitt ENABLE FULL TRUST FOR ROOT CERTIFICATES und schalten Sie den Schalter auf ON.

Schritt 4: Kehren Sie zur Bot-Integrationsseite auf Xcode Server zurück und klicken Sie auf Installieren .

Automatische Xcode Server-App-Tests

Eine weitere großartige Verwendung von Xcode Server ist das automatische Testen von Apps, ob es sich um Einheiten- oder UI-Tests handelt. Dazu müssen Sie das entsprechende Ziel für Ihr Projekt einrichten. Das heißt, Sie benötigen ein Ziel, das Unit- oder UI-Tests ausführt, abhängig von Ihrem Ziel.

Der Einrichtungsprozess ist derselbe wie der vorherige, aber wir werden andere Optionen auswählen. Der erste große Unterschied liegt in der Registerkarte Konfiguration . Natürlich werden wir die Kästchen „Analysieren“ und „Testen“ ankreuzen, da dies unser primäres Ziel ist. Ich würde auch dazu raten, das Produkt mit diesem Bot weder zu archivieren noch zu exportieren. Es ist möglich, sowohl Tests als auch Verteilung mit derselben Bot-Konfiguration zu erreichen. Diese beiden Szenarien unterscheiden sich jedoch sowohl in ihrer Leistung als auch in ihrem Zeitplan. Die Verteilung erfolgt häufig am Ende des Zyklus.

Ob Sie in Scrum oder Kanban oder einem anderen Framework arbeiten, es sollte einen vordefinierten zeitgesteuerten oder ereignisgesteuerten Zyklus geben, an dessen Ende Sie ein exportiertes und verwendbares Produkt haben sollten. Andererseits sollten Sie Ihren Test-Bot bei jedem Commit ausführen, da dies Ihre erste Verteidigungslinie gegen Regressionen ist. Da der Test-Bot offensichtlich häufiger ausgeführt wird, könnte das Zusammenführen dieser beiden Bots zu einem einzigen schnell den Speicherplatz auf Ihrem Server verbrauchen. Und es würde auch jede Integration mehr Zeit in Anspruch nehmen.

Nachdem das aus dem Weg geräumt ist, wechseln wir zur Registerkarte „Zeitplan“, und wir haben dies bereits im vorherigen Absatz angesprochen. Das nächste interessante Thema ist also das Code-Signing. Beachten Sie Folgendes: Auch wenn Ihr Testziel möglicherweise angibt, dass es kein Bereitstellungsprofil auf Ihrer Projekteinstellungsseite benötigt, sollten Sie es so einrichten, dass es dasselbe Team- und Signaturzertifikat wie die Hostanwendung verwendet. Dies ist erforderlich, wenn Sie Ihre App auf einem iOS-Gerät und nicht nur auf einem Simulator testen möchten. Wenn dies der Fall ist, müssen Sie auch sicherstellen, dass das zum Testen verwendete iOS-Gerät nicht aufgrund von Inaktivität gesperrt wird, da dies dazu führen kann, dass Ihr Integrationslauf auf unbestimmte Zeit hängen bleibt, ohne Sie zu benachrichtigen.

Jetzt befinden wir uns auf der Registerkarte „Geräte“, die keiner besonderen Erklärung bedarf. Wählen Sie einfach ein, mehrere oder alle Geräte (iOS und Simulator) aus, mit denen Sie Ihren Code testen möchten. Sie können auch prüfen, ob Sie Tests auf mehreren Geräten parallel oder nacheinander ausführen möchten. Um dies einzurichten, sollten Sie Ihre Projektanforderungen (ob Sie auf eine bestimmte Gruppe von Geräten oder alle unterstützten iOS-Geräte abzielen) und auch die Hardwareressourcen des Servers berücksichtigen.

Auf der Registerkarte Argumente . Es ist nicht erforderlich, etwas explizit anzugeben, da wir nur integrierte Umgebungsvariablen verwenden.

Schließlich führen wir auf der Registerkarte „Trigger “ ein Skript vor der Integration und ein Skript nach der Integration ein. Der erste ist nur da, um uns beim Debuggen zu helfen, falls wir auf Probleme stoßen. Es ist eigentlich das, was wir bereits verwendet haben:

 #!/bin/sh set printenv

Der zweite ist derjenige, der uns benachrichtigt, falls einer oder mehrere unserer Tests in der aktuellen Integration fehlschlagen. Stellen Sie sicher, dass es so eingestellt ist, dass es nur bei Testfehlern ausgeführt wird. Und folgendes eingeben:

 #!/bin/sh echo "$XCS_TEST_FAILURE_COUNT test(s) failed for $XCS_BOT_NAME bot on build $XCS_INTEGRATION_NUMBER" echo "You can see bot integration at:" echo "https://$HOSTNAME/xcode/bots/$XCS_BOT_TINY_ID/integrations/$XCS_INTEGRATION_TINY_ID"

Es gibt ein paar Dinge, die hier erklärt werden sollten. Zunächst einmal speichern $HOSTNAME-Variablen den Wert im folgenden Format: Computername.lokal. Offensichtlich würde der Link nur funktionieren, wenn Sie diesen Server über das lokale Netzwerk erreichen können. Außerdem erhalten Sie höchstwahrscheinlich eine Sicherheitswarnung von Ihrem Browser, wenn Sie diesen Link besuchen, da es sich um eine https-Verbindung zu einem nicht vertrauenswürdigen Ziel handelt. Schließlich ist dies nur ein Ausgangspunkt für Ihr Skript „Testausfall“. Sie können eine E-Mail an das gesamte Entwicklungsteam senden oder ein JIRA-Problem über eine API-Anfrage oder etwas anderes öffnen, das Sie für am geeignetsten und produktivsten halten.

Einpacken

Hoffentlich hat Sie dieser Artikel ermutigt, sich die Zeit zu nehmen, die Funktionen von Xcode Server zu erkunden, die über das einfache Erstellen einer App hinausgehen. Auch wenn dieser Beitrag Ihnen vielleicht nicht genau so geholfen hat, wie Sie es wollten oder erwarteten, war das Ziel, Ihnen eine aufgeschlossene Art der Verwendung integrierter Umgebungen und Xcode Server-Variablen vorzustellen, um ein höheres Maß an Automatisierung zu erreichen.

Es gibt viele Dienste von Drittanbietern, die mehr Funktionalität ermöglichen und viel mehr Arbeit für Sie erledigen können, darunter Fabric, Bluepill und Fastlane. Wenn Sie sich jedoch auf einen Drittanbieter verlassen, führt dies zwangsläufig zu einer neuen Abhängigkeit in Ihrem Projekt und erfordert manchmal eine einfache, manchmal eine komplexe Einrichtung und Konfiguration. Die hier beschriebenen Techniken erfordern nur Tools, die bereits auf jedem Mac installiert sind, sodass keine Einrichtungszeit erforderlich ist, außer der Konfiguration genau der Bots, die Ihre automatisierten Builds ausführen!