Skip to main content

Installieren eines Apple-Zertifikats auf macOS-Runnern für die Xcode-Entwicklung

Du kannst Xcode-Apps innerhalb deines Continuous Integration-Workflows signieren (CI), indem du ein Apple-Codesignaturzertifikat für GitHub Actions-Runner installierst.

Hinweis: GitHub-gehostete Runner werden auf GitHub Enterprise Server derzeit nicht unterstützt. Weitere Informationen zur geplanten zukünftigen Unterstützung findest Du in der GitHub public roadmap.

Einführung

In diesem Leitfaden erfährst du, wie du deinem Continuous Integration-Workflow (CI) einen Schritt hinzufügst, der ein Apple-Codesignaturzertifikat und ein Bereitstellungsprofil auf GitHub Actions-Runnern installiert. Dies ermöglicht es dir, deine Xcode-Apps für die Veröffentlichung im Apple App Store zu signieren oder sie an Testgruppen zu verteilen.

Voraussetzungen

Du solltest mit YAML und der Syntax für GitHub Actions vertraut sein. Weitere Informationen findest du unter:

Du solltest sich mit dem Erstellen und Signieren von Xcode-Apps auskennen. Weitere Informationen findest du in der Apple-Entwicklerdokumentation.

Erstellen von Geheimnissen für dein Zertifikat und das Bereitstellungsprofil

Der Signaturprozess umfasst das Speichern von Zertifikaten und Bereitstellungsprofilen, das Übertragen an den Runner, das Importieren in die Keychain des Runners und das Verwenden in deinem Build.

Um dein Zertifikat und dein Bereitstellungsprofil auf einem Runner zu verwenden, wird empfohlen, GitHub-Geheimnisse zu nutzen. Weitere Informationen zum Erstellen von Geheimnissen und ihrer Verwendung in einem Workflow findest du unter Verwenden von Geheimnissen in GitHub-Aktionen.

Erstelle Geheimnisse für die folgenden Elemente in deinem Repository oder deiner Organisation:

  • Dein Apple-Signaturzertifikat

    • Dies ist deine p12-Zertifikatdatei. Weitere Informationen zum Exportieren ihres Signaturzertifikats aus Xcode findest du in der Xcode-Dokumentation.

    • Du solltest dein Zertifikat in Base64 konvertieren, wenn du es als Geheimnis speicherst. In diesem Beispiel heißt das Geheimnis BUILD_CERTIFICATE_BASE64.

    • Verwende den folgenden Befehl, um dein Zertifikat in Base64 zu konvertieren und in deine Zwischenablage zu kopieren:

      base64 -i BUILD_CERTIFICATE.p12 | pbcopy
      
  • Das Kennwort für dein Apple-Signaturzertifikat

    • In diesem Beispiel heißt das Geheimnis P12_PASSWORD.
  • Dein Apple-Bereitstellungsprofil

    • Weitere Informationen zum Exportieren ihres Bereitstellungsprofils aus Xcode findest du in der Xcode-Dokumentation.

    • Du solltest dein Bereitstellungsprofil in Base64 konvertieren, wenn du es als Geheimnis speicherst. In diesem Beispiel heißt das Geheimnis BUILD_PROVISION_PROFILE_BASE64.

    • Verwende den folgenden Befehl, um dein Bereitstellungsprofil in Base64 zu konvertieren und in deine Zwischenablage zu kopieren:

      base64 -i PROVISIONING_PROFILE.mobileprovision | pbcopy
      
  • Ein Keychainkennwort

    • Auf dem Runner wird eine neue Keychain erstellt, sodass das Kennwort für die neue Keychain eine beliebige neue, zufällige Zeichenfolge sein kann. In diesem Beispiel heißt das Geheimnis KEYCHAIN_PASSWORD.

Hinzufügen eines Schritts zu deinem Workflow

Dieser Beispielworkflow enthält einen Schritt, der das Apple-Zertifikat und das Bereitstellungsprofil aus den GitHub-Geheimnissen importiert und auf dem Runner installiert.

YAML
name: App build
on: push

jobs:
  build_with_signing:
    runs-on: macos-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      - name: Install the Apple certificate and provisioning profile
        env:
          BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
          P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
          BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }}
          KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
        run: |
          # create variables
          CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
          PP_PATH=$RUNNER_TEMP/build_pp.mobileprovision
          KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db

          # import certificate and provisioning profile from secrets
          echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
          echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_PATH

          # create temporary keychain
          security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
          security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
          security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH

          # import certificate to keychain
          security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
          security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
          security list-keychain -d user -s $KEYCHAIN_PATH

          # apply provisioning profile
          mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
          cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles
      - name: Build app
          # ...

Note

Für iOS-Buildziele sollte dein Bereitstellungsprofil über die Erweiterung .mobileprovision verfügen. Für macOS-Buildziele sollte die Erweiterung .provisionprofile sein. Der obige Beispielworkflow sollte aktualisiert werden, um deine Zielplattform widerzuspiegeln.

Erforderliche Bereinigung auf selbstgehosteten Runnern

Bei von GitHub gehosteten Runnern handelt es sich um isolierte VMs, die nach dem Ausführen eines Auftrags automatisch zerstört werden. Dies bedeutet, dass die Zertifikate und Bereitstellungsprofile, die während des Auftrags auf dem Runner verwendet werden, nach Abschluss des Auftrags mit dem Runner zerstört werden.

Bei selbstgehosteten Runnern wird das $RUNNER_TEMP-Verzeichnis am Ende der Auftragsausführung bereinigt, doch die Keychain und das Bereitstellungsprofil können noch auf dem Runner vorhanden sein.

Wenn du selbstgehostete Runner verwendest, solltest du deinem Workflow einen letzten Schritt hinzufügen, um sicherzustellen, dass diese vertraulichen Dateien am Ende des Auftrags gelöscht werden. Ein Beispiel für diese Vorgehensweise siehst du im unten gezeigten Workflowschritt.

- name: Clean up keychain and provisioning profile
  if: ${{ always() }}
  run: |
    security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
    rm ~/Library/MobileDevice/Provisioning\ Profiles/build_pp.mobileprovision