Zum Hauptinhalt springen
CI/CD

Automatisierter Capacitor iOS Build mit GitHub Actions inklusive Zertifikat

CI/CD-Pipeline für deine iOS-Ionic-App mit fastlane und GitHub Actions in 5 Minuten einrichten (2024)

Automatischer Capacitor iOS-Build mit GitHub Actions und Zertifikat Capgo Blog-Illustration

Das Einrichten von CI/CD für Capacitor-Apps kann komplex und zeitaufwendig sein. Hier ist das Wichtigste:

Wir empfehlen jetzt Capgo Build mit Capgo CLI für native Capacitor Builds. Dieser Fastlane-Guide ist für Teams gedacht, die bestehende GitHub Actions-Pipelines pflegen. Neue iOS-Builds sollten jedoch Capgo CLI nutzen, damit ihr Fastlane, Xcode-Runner, Zertifikate und Upload-Skripte nicht selbst verwalten müsst.

Capgo Build für CI/CD von Capgo

Spart die Wartung von Fastlane, Xcode-Runnern, Zertifikaten, Provisioning Profiles und Upload-Skripten. Capgo Build führt signierte native iOS-Builds aus eurer bestehenden CI/CD-Pipeline aus:

  • Kompatibel mit eurer Pipeline: Löst den Capgo Build via GitHub Actions, GitLab CI, Jenkins oder lokale Skripte nach eurem Web-Build aus und npx cap sync.
  • Signing via CI-Secrets: Behaltet App Store Connect Keys, Zertifikate, Provisioning Profiles, Passwörter und Team-IDs sicher in euren eigenen CI-Secrets.
  • Kein Wartungsaufwand für Runner: Capgo Build bietet gewartete Apple-Build-Umgebungen, sodass ihr keine macOS-Runner, Xcode-Images oder Fastlane-Lanes verwalten müsst.
  • Artefakte und Einreichung: Lade signierte Artefakte für QA herunter oder reiche Release-Builds über Capgo CLI ein.

Preise

  • Capgo-Pläne ab 12 $/Monat
  • Inklusive OTA-Updates und ca. 15 Native Builds pro Monat
  • Zusätzliche Build-Minuten werden minutengenau über Credits abgerechnet

Capgo Build in CI/CD einrichten

Manuelle Setup-Anleitung

Das müssen Sie tun:

Continuous Delivery für iOS mit Fastlane, GitHub Actions und Zertifikaten

Voraussetzungen

Bevor du mit dem Tutorial fortfährst:

  • Stelle sicher, dass Fastlane installiert ist installiert ist auf deiner Entwicklungsmaschine.
  • Vergewissere dich, dass du Mitglied im iOS Developer Program bist.

Wichtige Informationen zum Preis

Preis der GitHub Action

https://github.com/features/actions

Der Service ist „kostenlos“ bis zum Limit, je nach gewählter Maschine.
Wir werden eine macOS Maschine nutzen; im Screenshot siehst du den Preis und die Limits (Preise zum Zeitpunkt der Tutorial-Erstellung, Änderungen vorbehalten).

Nachdem wir Anforderungen und Preise geklärt haben, geht es weiter.

Hinweis: Im Beitrag gehe ich davon aus, dass die App in App Store Connect bereits erstellt ist. Die wichtigen Informationen werden von Fastlane übernommen!

Das lernst du in diesem Tutorial

Schritte im Beitrag

  1. App Store Connect API mit Fastlane nutzen
    • Voraussetzungen:
      • App Store Connect API Key erstellen
      • Einen App Store Connect API Key verwenden
  2. Fastlane-Dateien kopieren
  3. GitHub Actions konfigurieren

1. App Store Connect API mit Fastlane nutzen

Seit Februar 2021 ist für alle Nutzer eine Zwei-Faktor-Authentifizierung oder eine Zwei-Schritt-Verifizierung erforderlich, um sich bei App Store Connect anzumelden. Diese zusätzliche Sicherheitsebene für Ihre Apple ID hilft sicherzustellen, dass nur Sie auf Ihr Konto zugreifen können.
Von Apple Support

Anforderungen

Damit Fastlane API von App Store Connect nutzen kann, um deine App hochzuladen, musst du Folgendes angeben: drei Dinge:

  1. Issuer-ID
  2. Key-ID
  3. Key-Datei oder Key-Inhalt

So erhältst du einen App Store Connect API Key

Um Keys zu generieren, benötigst du die Admin-Berechtigung in App Store Connect. Falls dir diese fehlt, kannst du die zuständige Person auf diesen Artikel verweisen.

  1. Anmelden bei App Store Connect.

  2. Wähle Benutzer und Zugriff.

App Store Connect Benutzerzugriff

3 — Wähle den Tab Integration.

App Store Connect API Integration

  1. Klicke auf Generate API Key oder das Add (+)-Symbol.

App Store Connect API Keys erstellen

  1. Gib einen Namen für den Key ein. Der Name dient nur deiner Referenz und ist nicht Teil des Keys selbst.

App Store Connect API Keys: Namen erstellen

6 — Wähle unter Access die Rolle für den Key. Die verfügbaren Rollen für Keys entsprechen den Rollen deiner Teammitglieder. Siehe Rollenberechtigungen. Wir empfehlen die Auswahl von App Manager.

  1. Klicke auf Generate.

Der Zugriff eines API Keys kann nicht auf bestimmte Apps beschränkt werden.

Der Name des neuen Keys, die Key-ID, ein Download-Link und weitere Infos werden auf der Seite angezeigt.

App Store Connect Download-Keys

Hier findest du alle drei benötigten Informationen.
<1> Issue-ID. (APPLE_ISSUER_ID geheim)
<2> Key ID. (APPLE_KEY_ID geheim)
<3> Klicke auf „Download API Key“, um deinen API Private Key herunterzuladen. Der Download-Link erscheint nur, wenn der Private Key noch nicht heruntergeladen wurde. Apple speichert keine Kopie des Private Keys. Du kannst ihn also nur einmal herunterladen.

🔴 Speichere deinen Private Key an einem sicheren Ort. Du solltest deine Keys niemals teilen, sie nicht in einem code-Repository speichern oder in clientseitigem code einbinden.

Einen App Store Connect API Key verwenden

Die API Key-Datei (die heruntergeladene p8-Datei), die Key ID und die Issuer ID werden benötigt, um den JWT-Token für die Autorisierung zu erstellen. Es gibt verschiedene Wege, diese Informationen an Fastlane zu übergeben. Ich habe mich für die neue Fastlane-Action entschieden: app_store_connect_api_key. Weitere Methoden findest du in der Fastlane-Dokumentation. Ich zeige diese Methode, weil sie meiner Meinung nach am einfachsten mit den meisten CI-Systemen funktioniert, bei denen man Umgebungsvariablen setzen kann.

Bitte konvertiere die heruntergeladene p8-Datei in Base64 und speichere sie als Secret (APPLE_KEY_CONTENT).

base64 -i APPLE_KEY_CONTENT.p8 | pbcopy

Jetzt können wir App Store Connect mit Fastlane und dem API Key verwalten, super!

2. Zertifikate

Öffne Xcode und gehe zu Einstellungen > Konten > Apple ID > Teams und wähle dein Team aus.

Code Signing-Identitäten

Klicken Sie auf Zertifikate verwalten.

Falls du noch kein Zertifikat erstellt hast, kannst du ein neues erstellen.

Klicken Sie auf + und wählen Apple-Distribution

Apple-Distribution

Dann musst du in die Schlüsselbundverwaltung, um das Zertifikat als .p12 Datei.

Dazu musst du in der Schlüsselbundverwaltung zum Schlüsselbund Anmeldung wechseln und dann zum Tab Meine Zertifikate.

Meine Zertifikate

Dann kannst du das Zertifikat auswählen, das du herunterladen möchtest. (Achte auf das Datum des Zertifikats)

Klicke dann mit der rechten Maustaste auf den privaten Schlüssel des Zertifikats und wähle Exportieren.

Wähle das Dateiformat Austausch persönlicher Informationen (.p12).

Damit wird das Zertifikat als .p12 Datei.

Öffne die Datei im Terminal und nutze diesen Befehl, um sie in Base64 zu konvertieren:

base64 -i BUILD_CERTIFICATE.p12 | pbcopy

This will become your BUILD_CERTIFICATE_BASE64 Secret. Gib auf Nachfrage bitte das Passwort des Zertifikats an. Dieses Passwort ist dein P12_PASSWORD Secret.

3. Provisioning Profiles

Öffne Apple Developer und wähle das richtige Team aus.

Erstelle dann ein neues Profil, indem du auf +

Neues Profil erstellen

Und wähle App Store Connect.

App Store Connect auswählen

Wähle dann die richtige App aus; achte darauf, keine Wildcards zu verwenden, da sonst das Signing fehlschlägt.

Wähle die richtige App

Wähle das zuvor erstellte, passende Zertifikat aus (achte auf das Ablaufdatum; es sollte den gleichen Tag und Monat wie heute haben) und klicke auf Weiter.

Wähle das richtige Zertifikat

Gib abschließend den Namen des Profils ein und klicke auf Generieren.

Der Name dient zur Identifizierung des Profils in Fastlane unter dem Wert APPLE_PROFILE_NAME.

Profil generieren

You can download the profile as a .mobileprovision Datei.

Profil herunterladen

Bitte konvertiere das Profil in Base64 und speichere es als Secret (BUILD_PROVISION_PROFILE_BASE64).

base64 -i BUILD_PROVISION_PROFILE.mobileprovision | pbcopy

4. Fastlane-Dateien kopieren

Fastlane ist eine Ruby-Library, mit der sich gängige Aufgaben in der Mobile-Entwicklung automatisieren lassen. Mit Fastlane kannst du eigene „Lanes“ konfigurieren, die eine Reihe von „Actions“ bündeln, um Aufgaben auszuführen, die du normalerweise in Android Studio erledigst. Mit Fastlane lässt sich viel erreichen, aber in diesem Tutorial nutzen wir nur eine Handvoll Core-Actions.

Erstelle den Fastlane-Ordner im Root deines Capacitor/Ionic-Projekts und füge dort die Fastfile hinzu:

  • Ordner: <project-root>/fastlane/
  • Datei: <project-root>/fastlane/Fastfile

Dies liegt auf derselben Ebene wie package.json, capacitor.config.*, und die ios/ Ordner. Erstelle ihn nicht innerhalb von ios/App/.

platform :ios do
  desc 'Export ipa and submit to TestFlight'
  lane :beta do
    keychain_info = { keychain_name: "ios-build-#{Time.now.to_i}.keychain", keychain_password: SecureRandom.uuid }
    
    begin
      setup_signing(keychain_info)
      bump_build_number
      build_app_with_signing(keychain_info)
      submit_to_testflight
    ensure
      cleanup_keychain(keychain_info)
    end
  end

  private_lane :setup_signing do |options|
    create_keychain(
      name: options[:keychain_name],
      password: options[:keychain_password],
      unlock: true,
      timeout: 0,
      lock_when_sleeps: false, 
      add_to_search_list: true
    )
    import_cert(options)
    install_profile
    update_project_settings
  end

  lane :bump_build_number do
		file = File.read('../package.json')
		data_hash = JSON.parse(file)
		api_key = app_store_connect_api_key(
      key_id: ENV['APPLE_KEY_ID'],
      issuer_id: ENV['APPLE_ISSUER_ID'],
      key_content: ENV['APPLE_KEY_CONTENT'],
      is_key_content_base64: true,
      duration: 1200,
      in_house: false
    )
		build_num = app_store_build_number(
      api_key: api_key,
			app_identifier: ENV['BUNDLE_IDENTIFIER'],
			live: false
    )
		build_num = build_num + 1
		UI.message("Bumped build number to #{build_num}")
		increment_build_number(
			build_number: build_num,
			xcodeproj: "./ios/App/App.xcodeproj",
			skip_info_plist: true
		)
	end

  private_lane :import_cert do |options|
    cert_path = "#{Dir.tmpdir}/build_certificate.p12"
    File.write(cert_path, Base64.decode64(ENV['BUILD_CERTIFICATE_BASE64']))
    import_certificate(
      certificate_path: cert_path,
      certificate_password: ENV['P12_PASSWORD'] || "",
      keychain_name: options[:keychain_name],
      keychain_password: options[:keychain_password],
      log_output: true
    )
    File.delete(cert_path)
  end  
  
  private_lane :cleanup_keychain do |options|
    delete_keychain(
      name: options[:keychain_name]
    )
  end  

  private_lane :install_profile do
    profile_path = "#{Dir.tmpdir}/build_pp.mobileprovision"
    File.write(profile_path, Base64.decode64(ENV['BUILD_PROVISION_PROFILE_BASE64']))
    UI.user_error!("Failed to create provisioning profile at #{profile_path}") unless File.exist?(profile_path)
    ENV['PROVISIONING_PROFILE_PATH'] = profile_path
    install_provisioning_profile(path: profile_path)
    File.delete(profile_path)
  end

  private_lane :update_project_settings do
    update_code_signing_settings(
      use_automatic_signing: false,
      path: "./ios/App/App.xcodeproj",
      code_sign_identity: "iPhone Distribution",
      profile_name: ENV['APPLE_PROFILE_NAME'],
      bundle_identifier: ENV['BUNDLE_IDENTIFIER'],
      team_id: ENV['APP_STORE_CONNECT_TEAM_ID']
    )
    update_project_team(
      path: "./ios/App/App.xcodeproj",
      teamid: ENV['APP_STORE_CONNECT_TEAM_ID']
    )
  end

  private_lane :build_app_with_signing do |options|
    unlock_keychain(
      path: options[:keychain_name],
      password: options[:keychain_password],
      set_default: false
    )
    build_app(
      workspace: "./ios/App/App.xcworkspace",
      scheme: "App",
      configuration: "Release",
      export_method: "app-store",
      output_name: "App.ipa",
      export_options: {
        provisioningProfiles: {
          ENV['BUNDLE_IDENTIFIER'] => ENV['APPLE_PROFILE_NAME']
        }
      },
      xcargs: "-verbose",
      buildlog_path: "./build_logs",
      export_xcargs: "-allowProvisioningUpdates",
    )
  end   

  private_lane :submit_to_testflight do
    api_key = app_store_connect_api_key(
      key_id: ENV['APPLE_KEY_ID'],
      issuer_id: ENV['APPLE_ISSUER_ID'],
      key_content: ENV['APPLE_KEY_CONTENT'],
      is_key_content_base64: true,
      duration: 1200,
      in_house: false
    )
    pilot(
      api_key: api_key,
      skip_waiting_for_build_processing: true,
      skip_submission: true,
      distribute_external: false,
      notify_external_testers: false,
      ipa: "./App.ipa"
    )
  end
end

5. Secrets einrichten

GitHub Actions nutzt die Repository-Secrets, die du im nächsten Schritt konfigurierst. Du benötigst nur eine lokale .env Datei, wenn du Fastlane von deinem eigenen Rechner aus ausführen oder testen willst.

Erstelle für lokale Tests <project-root>/fastlane/.env direkt neben Fastfile. Committe diese Datei nicht. Füge sie fastlane/.env in deine .gitignore zuerst hinzu (oder prüfe, ob sie bereits ignoriert wird). Hier ist ein Beispiel:

APP_STORE_CONNECT_TEAM_ID=UVTJ336J2D
BUNDLE_IDENTIFIER=ee.forgr.testfastlane
# See previous section for these secrets
BUILD_CERTIFICATE_BASE64=
BUILD_PROVISION_PROFILE_BASE64=
APPLE_KEY_ID=
APPLE_ISSUER_ID=
APPLE_KEY_CONTENT=
P12_PASSWORD=
APPLE_PROFILE_NAME=

Die APP_STORE_CONNECT_TEAM_ID ermitteln

Gehe zu Developer Center und scrolle nach unten zu Membership details Abschnitt. Den Team ID is the value you need to set in the APP_STORE_CONNECT_TEAM_ID secret.

app-store-connect-team-id

Den BUNDLE_IDENTIFIER abrufen

  1. Xcode öffnen
  2. Doppelklicke auf den App im Project Navigator
  3. Klicke dann auf den Tab Signing and Capabilities
  4. Kopiere den Wert von Bundle identifier. Dies ist der Wert, den du im BUNDLE_IDENTIFIER secret.
bundle-identifier-xcode

6. Build-Verarbeitung

In GitHub Actions erfolgt die Abrechnung basierend auf den Minuten, die du für deinen CI/CD-Workflow verbraucht hast. Meiner Erfahrung nach dauert es etwa 10–15 Minuten, bis ein Build in App Store Connect verarbeitet werden kann.

Bei privaten Projekten können die geschätzten Kosten pro Build bis zu $0,08/Min. x 15 Min. = $1,2betragen oder sogar höher ausfallen, je nach Konfiguration und Abhängigkeiten deines Projekts.

Wenn du dir wegen der Kosten für private Projekte Sorgen machst, kannst du skip_waiting_for_build_processing zu true. Das spart Build-Minuten, da man nicht warten muss, bis App Store Connect die Verarbeitung des Builds abgeschlossen hat.

Es gibt jedoch einen Kompromiss: Du musst die Compliance-Informationen deiner App in App Store Connect manuell aktualisieren, bevor du den Build an Nutzer verteilen kannst.

This optimization is mainly useful for private projects where build minutes cost money. For public/free projects, the build minutes are free so there’s no need to enable this setting. See GitHub’s Preisseite für weitere Details.

7. GitHub Actions einrichten

GitHub Secrets konfigurieren

Bitte kopiere die Secrets aus der .env Datei und füge sie in die GitHub Repository-Secrets ein.

Gehe zu Einstellungen > Secrets und Variablen > Aktionen > Neues Repository-Secret

github-Secrets

2. BUILD_CERTIFICATE_BASE64 - Base64-kodiertes Zertifikat.

3. BUILD_PROVISION_PROFILE_BASE64 - Base64-kodiertes Provisioning Profile.

4. BUNDLE_IDENTIFIER - dem Bundle Identifier deiner App.

5. APPLE_KEY_ID — App Store Connect API Key 🔺Key ID.

6. APPLE_ISSUER_ID — App Store Connect API Key 🔺Issuer ID.

7. APPLE_KEY_CONTENT — App Store Connect API Key 🔺 Key-Inhalt von .p8, Prüfen

8. GitHub Workflow-Datei konfigurieren

Erstelle ein GitHub Workflow-Verzeichnis.

cd .github/workflows

Im workflow Ordner erstelle eine Datei namens build-upload-ios.ymlund füge Folgendes hinzu.

name: Build source code on ios

on:
  push:
    tags:
      - '*'

jobs:
  build_ios:
    runs-on: macOS-latest
    steps:
      - uses: actions/checkout@v6
      - name: Set Node.js
        uses: actions/setup-node@v6
        with:
          node-version: 24
          cache: npm
      - name: Install dependencies
        id: install_code
        run: npm ci
      - name: Build
        id: build_code
        run: npm run build
      - uses: actions/cache@v5
        with:
          path: ios/App/Pods
          key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
          restore-keys: |
            ${{ runner.os }}-pods-
      - name: Sync
        id: sync_code
        run: npx cap sync
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: '3.0'
          bundler-cache: true
      - uses: maierj/fastlane-action@v3.1.0
        env:
          APP_STORE_CONNECT_TEAM_ID: ${{ secrets.APP_STORE_CONNECT_TEAM_ID }}
          BUNDLE_IDENTIFIER: ${{ secrets.BUNDLE_IDENTIFIER }}
          BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
          BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }}
          APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
          APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
          APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }}
          P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
          APPLE_PROFILE_NAME: ${{ secrets.APPLE_PROFILE_NAME }}
        with:
          lane: ios beta
      - name: Upload release bundle
        uses: actions/upload-artifact@v6
        with:
          name: ios-release
          path: ./App.ipa
          retention-days: 10

Dieser Workflow sollte nach jedem GitHub ausgelöst werden Tag, falls du das Tagging automatisieren möchtest, schau bitte in Automatischer Build und Release mit GitHub Actions zuerst.

Anschließend lädt dieser Workflow deine NodeJS-Abhängigkeiten herunter, installiert sie und baut deine JavaScript-App.

Jedes Mal, wenn du einen neuen Commit pushst, wird ein Release in TestFlight erstellt.

Deine App muss nicht Ionic nutzen, nur die Capacitor Basis ist Pflicht. Sie kann alte Cordova-Module enthalten, aber Capacitor JS-Plugins sollten bevorzugt werden.

8. Workflow auslösen

Einen Commit erstellen

Erstelle einen Commit, dann solltest du den aktiven Workflow im Repository sehen.

Workflow auslösen

Neue Commits in den Branch pushen main oder development um den Workflow auszulösen.

Gestartet mit Commit

Nach wenigen Minuten sollte der Build in deinem App Store Connect Dashboard verfügbar sein.

TestFlight-Dashboard

9. Kann ich vom lokalen Rechner aus deployen?

Ja, das geht und ist absolut mühelos.

Du kannst wie gewohnt Xcode zum Builden und Signieren deiner App nutzen.

CI/CD Setup-Guides

Alternative CI/CD-Plattformen

Live Updates &amp; Deployment

Danke

Dieser Blogpost basiert auf folgenden Artikeln:

Weiter mit automatischem Capacitor iOS Build via GitHub Actions mit Zertifikat

Wenn du es nutzt Automatisierter Capacitor iOS Build mit GitHub Actions inklusive Zertifikat um CI/CD-Automatisierung zu planen, verbinde es mit Capgo CI/CD für den Produkt-Workflow in Capgo CI/CD, Capgo Native Builds optimieren für den Produkt-Workflow in Capgo Native Builds, Capgo Integrationen für den Produkt-Workflow in Capgo Integrations, CI/CD-Integration für die Implementierungsdetails in der CI/CD-Integration und GitHub Actions-Integration für die Implementierungsdetails in der GitHub Actions-Integration.

Live-Updates für Capacitor-Apps

Wenn ein Bug im Web-Layer live ist, liefere den Fix über Capgo aus, statt Tage auf die App-Store-Freigabe zu warten. Nutzer bekommen das Update im Hintergrund, während native Änderungen im normalen Review-Prozess bleiben.

Neues aus unserem Blog

Capgo gibt dir die besten Insights, um eine wirklich professionelle Mobile App zu erstellen.