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:
Sertifikat code signing bertahan di antara eksekusi. Tidak perlu impor/ekspor pada setiap build.
DerivedData persisten, jadi fastlane build memakan waktu 2-4 menit alih-alih 15+.
Jalankan fastlane snapshot dengan simulator asli untuk semua ukuran perangkat.
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
- Buka App Store Connect > Users and Access > Keys
- Klik tombol + untuk menghasilkan kunci API baru
- Pilih peran App Manager
- Unduh file
.p8 - 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
Tambahkan Gemfile dengan versi Fastlane yang disematkan. Jalankan bundle exec fastlane untuk memastikan versi yang konsisten di semua lingkungan.
Kunci API menghindari prompt 2FA dan lebih aman untuk lingkungan CI.
match --readonly di CI
Mencegah pembuatan sertifikat baru secara tidak sengaja. Hanya hasilkan sertifikat secara manual saat diperlukan.
setup_ci di lingkungan CI
Ini membuat keychain sementara untuk menghindari pengotoran keychain sistem dan mencegah dialog izin keychain.
Di Mac dedikasi, tentukan derived_data_path untuk menggunakan kembali artifact build di antara eksekusi.