Panduan - Otomatisasi

Fastlane + Server Mac Dedikasi: Panduan Otomatisasi Lengkap

Otomatiskan seluruh proses rilis iOS Anda -- build, code signing, tangkapan layar, dan deployment TestFlight -- menggunakan Fastlane di server Mac Mini M4 dedikasi.

Baca 35 menit Diperbarui Maret 2026

1. Mengapa Fastlane di Mac Dedikasi?

Fastlane adalah alat otomatisasi standar untuk pengembangan iOS dan Android. Ia menangani segalanya mulai dari code signing hingga deployment TestFlight. Menjalankan Fastlane di Mac Mini M4 dedikasi memberi Anda:

Keychain Persisten

Sertifikat code signing bertahan di antara eksekusi. Tidak perlu impor/ekspor pada setiap build.

Build Inkremental Cepat

DerivedData persisten, jadi fastlane build memakan waktu 2-4 menit alih-alih 15+.

Tangkapan Layar Simulator

Jalankan fastlane snapshot dengan simulator asli untuk semua ukuran perangkat.

Deploy yang Andal

Lingkungan dedikasi yang stabil berarti lebih sedikit deployment yang tidak stabil dan masalah code signing.

2. Instal Fastlane

SSH ke Mac Mini M4 Anda dan instal Fastlane. Kami merekomendasikan Homebrew untuk penyiapan paling sederhana:

Opsi A: Instal melalui Homebrew (Direkomendasikan)

# 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

Opsi B: Instal melalui 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

Inisialisasi Fastlane di Proyek Anda

# 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. Konfigurasikan Match untuk Code Signing

Fastlane Match menyimpan sertifikat code signing dan provisioning profile Anda di repositori Git privat atau penyimpanan cloud. Ini memastikan semua mesin (dan anggota tim) menggunakan identitas penandatanganan yang sama.

Inisialisasi Match

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

# This creates fastlane/Matchfile

Konfigurasikan Matchfile

# 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")

Hasilkan Sertifikat

# 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. Buat Fastfile (Lane Build, Test, Deploy)

Berikut Fastfile lengkap dengan lane untuk mem-build, menguji, dan men-deploy aplikasi iOS Anda:

# 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. Siapkan Tangkapan Layar Otomatis

Fastlane Snapshot menangkap tangkapan layar App Store di berbagai perangkat dan bahasa secara otomatis. Di Mac dedikasi, ini berjalan andal tanpa bersaing untuk sumber daya.

# Initialize snapshot
fastlane snapshot init

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

Konfigurasikan Snapfile

# 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)

Tambahkan Snapshot ke UI Test Anda

// 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")
    }
}

Tambahkan Lane Tangkapan Layar

  # 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. Deploy ke TestFlight

Untuk lingkungan CI, gunakan kunci API App Store Connect alih-alih kredensial Apple ID Anda. Ini menghindari prompt 2FA di server headless.

Buat Kunci API

  1. Buka App Store Connect > Users and Access > Keys
  2. Klik tombol + untuk menghasilkan kunci API baru
  3. Pilih peran App Manager
  4. Unduh file .p8
  5. Catat Key ID dan Issuer ID

Buat JSON Kunci API

# 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

Jalankan Deployment

# Deploy to TestFlight
fastlane beta

# Or run the full release pipeline
fastlane release

7. Integrasikan dengan CI/CD

Fastlane berintegrasi mulus dengan platform CI/CD apa pun. Berikut contoh GitHub Actions menggunakan self-hosted runner Mac Mini M4 Anda:

# .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. Praktik Terbaik

Gunakan Bundler untuk menyematkan versi Fastlane

Tambahkan Gemfile dengan versi Fastlane yang disematkan. Jalankan bundle exec fastlane untuk memastikan versi yang konsisten di semua lingkungan.

Gunakan kunci API App Store Connect, bukan kredensial Apple ID

Kunci API menghindari prompt 2FA dan lebih aman untuk lingkungan CI.

Gunakan match --readonly di CI

Mencegah pembuatan sertifikat baru secara tidak sengaja. Hanya hasilkan sertifikat secara manual saat diperlukan.

Gunakan setup_ci di lingkungan CI

Ini membuat keychain sementara untuk menghindari pengotoran keychain sistem dan mencegah dialog izin keychain.

Simpan DerivedData untuk build lebih cepat

Di Mac dedikasi, tentukan derived_data_path untuk menggunakan kembali artifact build di antara eksekusi.

Panduan Terkait

Otomatiskan Rilis iOS Anda Hari Ini

Dapatkan Mac Mini M4 dedikasi dan jalankan Fastlane dengan build tanpa batas. Mulai dari $85/bulan.

Butuh detail lebih lanjut?

Jelajahi dokumentasi lengkap untuk panduan langkah demi langkah, referensi konfigurasi, dan pemecahan masalah.

Buka dokumentasi →