Anleitung - Automatisierung

Fastlane + dedizierter Mac-Server: Vollständige Automatisierungsanleitung

Automatisieren Sie Ihren gesamten iOS-Release-Prozess -- Builds, Code-Signierung, Screenshots und TestFlight-Deployment -- mit Fastlane auf einem dedizierten Mac Mini M4 Server.

35 Min. Lesezeit Aktualisiert März 2026

1. Warum Fastlane auf einem dedizierten Mac?

Fastlane ist das Standard-Automatisierungstool für die iOS- und Android-Entwicklung. Es kümmert sich um alles von der Code-Signierung bis zum TestFlight-Deployment. Fastlane auf einem dedizierten Mac Mini M4 auszuführen bietet Ihnen:

Persistenter Schlüsselbund

Code-Signing-Zertifikate bleiben zwischen den Durchläufen erhalten. Kein Import/Export bei jedem Build erforderlich.

Schnelle inkrementelle Builds

DerivedData bleibt erhalten, sodass fastlane build 2-4 Minuten statt über 15 dauert.

Simulator-Screenshots

Führen Sie fastlane snapshot mit echten Simulatoren für alle Gerätegrößen aus.

Zuverlässige Deployments

Eine stabile, dedizierte Umgebung bedeutet weniger instabile Deployments und Code-Signing-Probleme.

2. Fastlane installieren

Verbinden Sie sich per SSH mit Ihrem Mac Mini M4 und installieren Sie Fastlane. Wir empfehlen Homebrew für die einfachste Einrichtung:

Option A: Installation über Homebrew (empfohlen)

# Install Homebrew (if not already installed)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"

# Install Fastlane
brew install fastlane

# Verify installation
fastlane --version
# fastlane 2.225.0

Option B: Installation über RubyGems

# Use the system Ruby or install rbenv for version management
gem install fastlane -NV

# Or with Bundler (recommended for team consistency):
# Create a Gemfile in your project root
cat > Gemfile <<'EOF'
source "https://rubygems.org"

gem "fastlane"
gem "cocoapods"  # if using CocoaPods
EOF

bundle install

Fastlane in Ihrem Projekt initialisieren

# Navigate to your project directory
cd /path/to/your/ios-project

# Initialize Fastlane
fastlane init

# Choose option 4: "Manual setup"
# This creates the fastlane/ directory with Appfile and Fastfile

3. Match für die Code-Signierung konfigurieren

Fastlane Match speichert Ihre Code-Signing-Zertifikate und Provisioning-Profile in einem privaten Git-Repository oder Cloud-Speicher. Dadurch wird sichergestellt, dass alle Maschinen (und Teammitglieder) dieselbe Signaturidentität verwenden.

Match initialisieren

# Initialize match (choose "git" for storage)
fastlane match init

# This creates fastlane/Matchfile

Matchfile konfigurieren

# fastlane/Matchfile

git_url("https://github.com/your-org/ios-certificates.git")

storage_mode("git")

type("appstore")  # default type, can be overridden per lane

app_identifier(["com.yourcompany.myapp"])
username("your-apple-id@example.com")

# For CI environments, use App Store Connect API key instead of username/password
# api_key_path("fastlane/AuthKey.json")

Zertifikate generieren

# Generate development certificates and profiles
fastlane match development

# Generate App Store distribution certificates and profiles
fastlane match appstore

# For ad-hoc distribution
fastlane match adhoc

# On CI, use readonly mode to avoid accidentally creating new certs
fastlane match appstore --readonly

4. Fastfile erstellen (Build-, Test-, Deploy-Lanes)

Hier ist ein vollständiges Fastfile mit Lanes zum Bauen, Testen und Deployen Ihrer iOS-App:

# fastlane/Fastfile

default_platform(:ios)

platform :ios do

  # ---- SHARED ----

  before_all do
    setup_ci if ENV['CI']  # Configures keychain for CI environments
  end

  # ---- BUILD ----

  desc "Build the app for testing"
  lane :build do
    match(type: "development", readonly: true)

    build_app(
      workspace: "MyApp.xcworkspace",
      scheme: "MyApp",
      configuration: "Debug",
      destination: "generic/platform=iOS Simulator",
      derived_data_path: "DerivedData",
      skip_archive: true,
      skip_codesigning: true
    )
  end

  # ---- TEST ----

  desc "Run all unit and UI tests"
  lane :test do
    run_tests(
      workspace: "MyApp.xcworkspace",
      scheme: "MyApp",
      devices: ["iPhone 16 Pro"],
      derived_data_path: "DerivedData",
      result_bundle: true,
      output_directory: "fastlane/test_results",
      parallel_testing: true,
      concurrent_workers: 4
    )
  end

  # ---- BETA ----

  desc "Build and push a new beta to TestFlight"
  lane :beta do
    # Ensure we are on a clean git state
    ensure_git_status_clean

    # Fetch App Store certificates
    match(type: "appstore", readonly: true)

    # Increment build number
    increment_build_number(
      build_number: latest_testflight_build_number + 1
    )

    # Build the app
    build_app(
      workspace: "MyApp.xcworkspace",
      scheme: "MyApp",
      export_method: "app-store",
      derived_data_path: "DerivedData",
      output_directory: "fastlane/builds"
    )

    # Upload to TestFlight
    upload_to_testflight(
      skip_waiting_for_build_processing: true,
      api_key_path: "fastlane/AuthKey.json"
    )

    # Commit the version bump
    commit_version_bump(
      message: "chore: bump build number [skip ci]",
      force: true
    )

    # Tag the release
    add_git_tag(
      tag: "beta/#{lane_context[SharedValues::BUILD_NUMBER]}"
    )

    push_to_git_remote
  end

  # ---- RELEASE ----

  desc "Build and submit to App Store Review"
  lane :release do
    match(type: "appstore", readonly: true)

    # Increment version number (patch)
    increment_version_number(bump_type: "patch")
    increment_build_number(
      build_number: latest_testflight_build_number + 1
    )

    build_app(
      workspace: "MyApp.xcworkspace",
      scheme: "MyApp",
      export_method: "app-store",
      derived_data_path: "DerivedData"
    )

    upload_to_app_store(
      submit_for_review: true,
      automatic_release: false,
      api_key_path: "fastlane/AuthKey.json",
      precheck_include_in_app_purchases: false
    )

    commit_version_bump(message: "chore: release #{lane_context[SharedValues::VERSION_NUMBER]}")
    add_git_tag
    push_to_git_remote
  end

  # ---- ERROR HANDLING ----

  error do |lane, exception|
    # Send notification on failure (Slack, email, etc.)
    # slack(
    #   message: "Lane #{lane} failed: #{exception.message}",
    #   success: false
    # )
  end
end

5. Automatisierte Screenshots einrichten

Fastlane Snapshot erstellt automatisch App-Store-Screenshots über mehrere Geräte und Sprachen hinweg. Auf einem dedizierten Mac läuft dies zuverlässig, ohne um Ressourcen zu konkurrieren.

# Initialize snapshot
fastlane snapshot init

# This creates:
# - fastlane/Snapfile
# - fastlane/SnapshotHelper.swift (add to UI test target)

Snapfile konfigurieren

# fastlane/Snapfile

devices([
  "iPhone 16 Pro Max",
  "iPhone 16 Pro",
  "iPhone SE (3rd generation)",
  "iPad Pro 13-inch (M4)"
])

languages([
  "en-US",
  "fr-FR",
  "de-DE",
  "ja"
])

scheme("MyAppUITests")
output_directory("./fastlane/screenshots")
clear_previous_screenshots(true)

# Speed up by running in parallel
concurrent_simulators(true)

Snapshot zu Ihren UI-Tests hinzufügen

// In your XCUITest file:
import XCTest

class ScreenshotTests: XCTestCase {

    override func setUp() {
        continueAfterFailure = false
        let app = XCUIApplication()
        setupSnapshot(app)
        app.launch()
    }

    func testHomeScreen() {
        snapshot("01_HomeScreen")
    }

    func testDetailScreen() {
        let app = XCUIApplication()
        app.cells.firstMatch.tap()
        snapshot("02_DetailScreen")
    }

    func testSettings() {
        let app = XCUIApplication()
        app.tabBars.buttons["Settings"].tap()
        snapshot("03_Settings")
    }
}

Eine Screenshot-Lane hinzufügen

  # Add to your Fastfile:
  desc "Capture App Store screenshots"
  lane :screenshots do
    capture_screenshots
    frame_screenshots(white: true)  # Add device frames
    upload_to_app_store(
      skip_binary_upload: true,
      skip_metadata: true,
      api_key_path: "fastlane/AuthKey.json"
    )
  end

6. Auf TestFlight deployen

Verwenden Sie für CI-Umgebungen den App Store Connect API-Schlüssel anstelle Ihrer Apple-ID-Anmeldedaten. Dies vermeidet 2FA-Aufforderungen auf Servern ohne Bildschirm.

Einen API-Schlüssel erstellen

  1. Gehen Sie zu App Store Connect > Users and Access > Keys
  2. Klicken Sie auf die Schaltfläche +, um einen neuen API-Schlüssel zu generieren
  3. Wählen Sie die Rolle App Manager
  4. Laden Sie die .p8-Datei herunter
  5. Notieren Sie sich die Key ID und die Issuer ID

Das API-Schlüssel-JSON erstellen

# fastlane/AuthKey.json
{
  "key_id": "YOUR_KEY_ID",
  "issuer_id": "YOUR_ISSUER_ID",
  "key": "-----BEGIN PRIVATE KEY-----\nYOUR_P8_KEY_CONTENT\n-----END PRIVATE KEY-----",
  "in_house": false
}

# IMPORTANT: Add this to .gitignore!
echo "fastlane/AuthKey.json" >> .gitignore

Das Deployment ausführen

# Deploy to TestFlight
fastlane beta

# Or run the full release pipeline
fastlane release

7. In CI/CD integrieren

Fastlane lässt sich nahtlos in jede CI/CD-Plattform integrieren. Hier ist ein GitHub-Actions-Beispiel mit Ihrem selbst gehosteten Mac Mini M4 Runner:

# .github/workflows/deploy.yml
name: Deploy to TestFlight

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: [self-hosted, macOS, ARM64, M4]

    env:
      MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
      MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_TOKEN }}

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up App Store Connect API Key
        run: |
          mkdir -p fastlane
          echo '${{ secrets.APP_STORE_CONNECT_API_KEY }}' > fastlane/AuthKey.json

      - name: Install dependencies
        run: |
          bundle install
          pod install  # if using CocoaPods

      - name: Deploy to TestFlight
        run: bundle exec fastlane beta

      - name: Clean up API key
        if: always()
        run: rm -f fastlane/AuthKey.json

8. Best Practices

Bundler für das Pinnen der Fastlane-Version verwenden

Fügen Sie ein Gemfile mit einer festgelegten Fastlane-Version hinzu. Führen Sie bundle exec fastlane aus, um konsistente Versionen in allen Umgebungen sicherzustellen.

App Store Connect API-Schlüssel statt Apple-ID-Anmeldedaten verwenden

API-Schlüssel vermeiden 2FA-Aufforderungen und sind für CI-Umgebungen sicherer.

In CI match --readonly verwenden

Verhindert die versehentliche Erstellung neuer Zertifikate. Generieren Sie Zertifikate nur bei Bedarf manuell.

In CI-Umgebungen setup_ci verwenden

Dies erstellt einen temporären Schlüsselbund, um den System-Schlüsselbund nicht zu belasten, und verhindert Berechtigungsdialoge für den Schlüsselbund.

DerivedData für schnellere Builds behalten

Geben Sie auf einem dedizierten Mac derived_data_path an, um Build-Artefakte zwischen den Durchläufen wiederzuverwenden.

Verwandte Anleitungen

Automatisieren Sie Ihre iOS-Releases noch heute

Holen Sie sich einen dedizierten Mac Mini M4 und führen Sie Fastlane mit unbegrenzten Builds aus. Ab $85/Monat.

Mehr Details gesucht?

Durchsuchen Sie die vollständige Dokumentation für Schritt-für-Schritt-Anleitungen, Konfigurationsreferenzen und Fehlerbehebung.

Dokumentation öffnen →