Pular para o conteúdo

Fastlane Cheat Sheet

Overview

Fastlane is an open-source platform for automating the building, testing, and releasing of iOS and Android applications. It handles tedious tasks like generating screenshots, managing code signing certificates and provisioning profiles, running tests, and deploying apps to the App Store and Google Play Store. Fastlane uses a Ruby-based DSL where automation steps are defined as “lanes” in a Fastfile, with each step calling built-in “actions” that wrap complex platform tools.

Fastlane dramatically reduces the time and complexity of mobile release processes. It manages iOS code signing through the “match” system (storing certificates in a shared git repo or cloud storage), automates screenshot generation across multiple device sizes and languages, handles beta distribution through TestFlight and Firebase App Distribution, and manages metadata and app store listings. The tool integrates seamlessly with CI/CD systems like GitHub Actions, Bitrise, CircleCI, and Jenkins.

Installation

# Install via Homebrew (recommended for macOS)
brew install fastlane

# Install via RubyGems
sudo gem install fastlane

# Install via Bundler (recommended for teams)
# Create Gemfile
cat > Gemfile << 'EOF'
source "https://rubygems.org"
gem "fastlane"
EOF
bundle install

# Initialize in project
cd my-app
fastlane init

# iOS: Choose setup option
# 1. Automate screenshots
# 2. Automate beta distribution
# 3. Automate App Store distribution
# 4. Manual setup

# Android
fastlane init
# Provide path to Google Play JSON key

# Verify
fastlane --version
fastlane env  # Print environment info

Project Structure

my-app/
├── Gemfile                    # Ruby dependencies
├── Gemfile.lock
└── fastlane/
    ├── Fastfile                # Lane definitions
    ├── Appfile                 # App identifiers
    ├── Matchfile               # Code signing config
    ├── Deliverfile             # App Store metadata config
    ├── Scanfile                # Test configuration
    ├── Screengrabfile          # Android screenshot config
    ├── Snapfile                # iOS screenshot config
    ├── Pluginfile               # Fastlane plugins
    ├── metadata/               # App Store metadata
    │   ├── en-US/
    │   │   ├── description.txt
    │   │   ├── keywords.txt
    │   │   ├── release_notes.txt
    │   │   └── name.txt
    │   └── review_information/
    ├── screenshots/            # Generated screenshots
    └── report.xml              # Build report

Appfile

# fastlane/Appfile

# iOS
app_identifier("com.example.myapp")
apple_id("developer@example.com")
team_id("ABCDEF1234")
itc_team_id("12345678")

# Android
json_key_file("path/to/google-play-key.json")
package_name("com.example.myapp")

# Per-lane overrides
for_platform :ios do
  for_lane :enterprise do
    app_identifier("com.example.myapp.enterprise")
  end
end

Fastfile (Lanes)

# fastlane/Fastfile

default_platform(:ios)

platform :ios do
  desc "Run unit tests"
  lane :test do
    scan(
      scheme: "MyApp",
      devices: ["iPhone 15 Pro"],
      clean: true,
      code_coverage: true
    )
  end

  desc "Build and push to TestFlight"
  lane :beta do
    ensure_git_clean
    increment_build_number(xcodeproj: "MyApp.xcodeproj")
    match(type: "appstore")
    build_app(
      scheme: "MyApp",
      workspace: "MyApp.xcworkspace",
      export_method: "app-store",
      output_directory: "./build",
      output_name: "MyApp.ipa"
    )
    upload_to_testflight(
      skip_waiting_for_build_processing: true
    )
    slack(
      message: "New iOS beta uploaded to TestFlight!",
      slack_url: ENV["SLACK_WEBHOOK"]
    )
    commit_version_bump(message: "Bump build number [skip ci]")
    push_to_git_remote
  end

  desc "Deploy to App Store"
  lane :release do
    ensure_git_clean
    increment_version_number(bump_type: "patch")
    increment_build_number
    match(type: "appstore")
    build_app(scheme: "MyApp", workspace: "MyApp.xcworkspace")
    upload_to_app_store(
      force: true,
      submit_for_review: true,
      automatic_release: true,
      submission_information: {
        add_id_info_uses_idfa: false
      }
    )
    commit_version_bump(message: "Release v#{lane_context[SharedValues::VERSION_NUMBER]}")
    add_git_tag
    push_to_git_remote
  end

  desc "Generate screenshots"
  lane :screenshots do
    capture_ios_screenshots
    upload_to_app_store(
      skip_binary_upload: true,
      skip_metadata: true,
      overwrite_screenshots: true
    )
  end

  error do |lane, exception|
    slack(
      message: "#{lane} failed: #{exception.message}",
      slack_url: ENV["SLACK_WEBHOOK"],
      success: false
    )
  end
end

platform :android do
  desc "Run tests"
  lane :test do
    gradle(task: "test")
  end

  desc "Build and deploy to Play Store beta"
  lane :beta do
    gradle(
      task: "bundle",
      build_type: "Release",
      properties: {
        "android.injected.signing.store.file" => ENV["KEYSTORE_PATH"],
        "android.injected.signing.store.password" => ENV["KEYSTORE_PASSWORD"],
        "android.injected.signing.key.alias" => ENV["KEY_ALIAS"],
        "android.injected.signing.key.password" => ENV["KEY_PASSWORD"]
      }
    )
    upload_to_play_store(
      track: "beta",
      aab: "android/app/build/outputs/bundle/release/app-release.aab"
    )
  end

  desc "Deploy to Play Store production"
  lane :release do
    gradle(task: "bundle", build_type: "Release")
    upload_to_play_store(
      track: "production",
      rollout: "0.1"  # 10% staged rollout
    )
  end
end

Code Signing (Match)

# fastlane/Matchfile
git_url("https://github.com/myorg/certificates.git")
storage_mode("git")
type("appstore")
app_identifier(["com.example.myapp"])
team_id("ABCDEF1234")
# Initialize match (creates certs and profiles)
fastlane match development
fastlane match appstore
fastlane match adhoc

# Read-only mode (CI/CD)
fastlane match appstore --readonly

# Nuke and recreate (when certs expire)
fastlane match nuke development
fastlane match nuke appstore

# Using cloud storage instead of git
# In Matchfile:
# storage_mode("google_cloud")
# google_cloud_bucket_name("my-certs-bucket")

Common Actions

ActionDescription
build_app / gymBuild iOS app (IPA)
scanRun tests
matchManage code signing
deliverUpload to App Store
pilot / upload_to_testflightUpload to TestFlight
snapshot / capture_ios_screenshotsGenerate iOS screenshots
screengrabGenerate Android screenshots
gradleRun Android Gradle tasks
supply / upload_to_play_storeUpload to Google Play
increment_build_numberBump build number
increment_version_numberBump version
slackSend Slack notification
firebase_app_distributionDistribute via Firebase
cocoapodsRun pod install

CLI Commands

# Run a lane
fastlane ios beta
fastlane android release

# List available lanes
fastlane list

# Run single action
fastlane run increment_build_number

# Get action documentation
fastlane action build_app
fastlane actions  # List all actions

# Install plugins
fastlane add_plugin firebase_app_distribution
fastlane add_plugin badge

# Update fastlane
fastlane update_fastlane
bundle update fastlane

Advanced Usage

# Before/after hooks
before_all do
  ensure_git_clean
  cocoapods(repo_update: true)
end

after_all do |lane|
  clean_build_artifacts
  notification(
    title: "Fastlane",
    message: "#{lane} completed successfully!"
  )
end

# Environment variables
lane :deploy do
  api_key = app_store_connect_api_key(
    key_id: ENV["ASC_KEY_ID"],
    issuer_id: ENV["ASC_ISSUER_ID"],
    key_filepath: ENV["ASC_KEY_PATH"],
  )
  
  pilot(api_key: api_key)
end

# Multiple app targets
lane :build_all do
  ["MyApp", "MyAppPro", "MyAppLite"].each do |scheme|
    build_app(
      scheme: scheme,
      output_name: "#{scheme}.ipa"
    )
  end
end

# Firebase App Distribution
lane :firebase_beta do
  build_app(scheme: "MyApp")
  firebase_app_distribution(
    app: "1:123456789:ios:abcdef",
    groups: "internal-testers",
    release_notes: changelog_from_git_commits
  )
end

# Conditional logic
lane :smart_deploy do
  if git_branch == "main"
    release
  elsif git_branch.start_with?("release/")
    beta
  else
    test
  end
end

Troubleshooting

IssueSolution
”No signing certificate found”Run fastlane match to sync certificates
Code signing issuesUse match system; check team ID and bundle identifier
”Build failed”Check Xcode build settings; run xcodebuild manually to debug
Play Store upload rejectedVerify JSON key permissions; check AAB signing
Match git clone failsCheck SSH keys; use HTTPS URL with MATCH_PASSWORD env var
Screenshots wrong sizeUpdate device list in Snapfile; check simulator availability
Slow builds in CIUse derived_data_path to cache; enable skip_build where possible
”Could not find gem”Run bundle install; check Ruby version compatibility
TestFlight processing timeoutUse skip_waiting_for_build_processing: true
Lane not foundCheck platform declaration; verify lane name spelling