Каждый iOS-разработчик хотя бы раз проходил через это: нужно выложить сборку в TestFlight, а ты полтора часа сидишь и вручную обновляешь сертификаты, пересобираешь архив, ждёшь загрузки, получаешь ошибку от App Store Connect — и начинаешь сначала. Это не разработка, это страдание.

Fastlane решает именно эту проблему. А CI/CD делает так, чтобы вся эта боль вообще не требовала твоего участия.

Что такое Fastlane и зачем он нужен

Fastlane — это набор инструментов командной строки для автоматизации рутины в iOS (и Android) разработке. Его написали на Ruby, и он умеет:

  • собирать приложение (gym)
  • управлять сертификатами и provisioning profile (match)
  • загружать сборку в TestFlight и App Store (pilot, deliver)
  • запускать тесты (scan)
  • делать скриншоты для стора (snapshot)

Без Fastlane типичный релизный цикл выглядит так: открыл Xcode, обновил версию, собрал архив (минут 10-15), открыл Organizer, нажал Distribute, прошёл через пять экранов мастера, подождал загрузки — ещё минут 20. И так каждый раз. Если релизы частые или команда большая — это реальная проблема.

С Fastlane весь процесс сворачивается в одну команду в терминале.

Установка и первичная настройка

Fastlane ставится через Bundler — это правильный способ, который фиксирует версию и не ломает окружение.

Создай Gemfile в корне проекта:

source "https://rubygems.org"
gem "fastlane"

Потом:

bundle install
bundle exec fastlane init

Fastlane спросит, что ты хочешь делать — выбери «Automate beta distribution to TestFlight» или «Manual setup». Для первого знакомства подойдёт автоматический режим, но в реальных проектах лучше настраивать руками — так понимаешь, что происходит.

После инициализации появится папка fastlane/ с двумя файлами:

  • Appfile — настройки приложения (bundle ID, Apple ID, team ID)
  • Fastfile — сами сценарии (lanes)

Fastfile: как устроены lanes

Lane — это просто набор действий, которые выполняются последовательно. Вот базовый пример:

default_platform(:ios)

platform :ios do
  lane :beta do
    increment_build_number
    build_app(
      scheme: "MyApp",
      configuration: "Release",
      export_method: "app-store"
    )
    upload_to_testflight(
      skip_waiting_for_build_processing: true
    )
  end
end

Запускаешь bundle exec fastlane beta — и через несколько минут новая сборка уже в TestFlight.

increment_build_number автоматически поднимает build number, что избавляет от «ой, забыл обновить» перед каждым деплоем.

Match — главная боль с сертификатами

Сертификаты и provisioning profiles — больная тема для любой команды. Один разработчик создал сертификат локально, другой не может собрать проект, третий случайно отозвал чужой профиль. Классика.

Match решает это радикально: все сертификаты хранятся зашифрованными в отдельном git-репозитории (или S3/Google Cloud Storage), а каждый разработчик и CI-сервер скачивает их через единую команду.

Настройка:

bundle exec fastlane match init

Fastlane спросит, где хранить сертификаты. Для команды удобнее всего приватный git-репозиторий. Укажи его URL.

Потом создаёшь сертификаты для нужных окружений:

bundle exec fastlane match appstore
bundle exec fastlane match development

В Fastfile использование match выглядит так:

lane :beta do
  match(type: "appstore", readonly: true)
  build_app(scheme: "MyApp")
  upload_to_testflight
end

Параметр readonly: true важен для CI — он говорит «только скачай существующие, ничего не создавай». Создание сертификатов делается отдельно, вручную, один раз.

Пароль для расшифровки передаётся через переменную окружения MATCH_PASSWORD. Никогда не хардкодь его в Fastfile.

CI/CD: автоматизация без участия человека

Fastlane — это инструмент для локального запуска и для CI. CI/CD (Continuous Integration / Continuous Delivery) — это система, которая запускает твои скрипты автоматически при каждом пуше или по расписанию.

Для iOS-проектов популярны несколько вариантов:

GitHub Actions — бесплатно для открытых репозиториев, для приватных есть лимиты. MacOS-раннеры стоят дороже Linux, но они необходимы для сборки iOS.

Bitrise — специализированный сервис для мобильной разработки. Много готовых шагов для iOS, удобный UI, но платный.

GitLab CI — хорошо подходит, если уже используешь GitLab. Нужен собственный macOS-раннер или платный облачный.

Xcode Cloud — встроенный CI от Apple. Интегрирован в Xcode и App Store Connect, бесплатный тариф есть, но функциональность ограничена.

Пример: GitHub Actions + Fastlane

Создай файл .github/workflows/beta.yml:

name: Beta Deploy

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: macos-14
    
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      
      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: '3.2'
          bundler-cache: true
      
      - name: Deploy to TestFlight
        env:
          MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
          APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.API_KEY_ID }}
          APP_STORE_CONNECT_API_ISSUER_ID: ${{ secrets.API_ISSUER_ID }}
          APP_STORE_CONNECT_API_KEY_CONTENT: ${{ secrets.API_KEY_CONTENT }}
        run: bundle exec fastlane beta

Все секреты — пароли, ключи API — хранятся в настройках репозитория (Settings → Secrets), не в коде.

Для авторизации в App Store Connect лучше использовать API Key вместо логина и пароля — он надёжнее и не ломается от двухфакторной аутентификации. Ключ создаётся в App Store Connect → Users and Access → Keys.

В Fastfile подключаешь его так:

app_store_connect_api_key(
  key_id: ENV["APP_STORE_CONNECT_API_KEY_ID"],
  issuer_id: ENV["APP_STORE_CONNECT_API_ISSUER_ID"],
  key_content: ENV["APP_STORE_CONNECT_API_KEY_CONTENT"]
)

Что ещё умеет Fastlane

Автоматические скриншоты. snapshot запускает UI-тесты на симуляторах разных размеров и делает скриншоты. frameit добавляет к ним рамки устройств. Особенно полезно, когда приложение локализовано — вместо того чтобы вручную делать 5 скриншотов × 6 локалей × 3 устройства = 90 картинок, запускаешь одну команду.

Управление версиями. increment_version_number и increment_build_number можно настроить так, чтобы версия поднималась автоматически по тегу в git.

Уведомления. Fastlane умеет отправлять сообщения в Slack, когда сборка прошла или упала. Добавляется одной строкой:

slack(
  message: "Beta успешно задеплоена!",
  slack_url: ENV["SLACK_URL"]
)

Прогон тестов. scan запускает тесты и генерирует HTML-отчёт. В CI это выглядит так: пуш в ветку → тесты → если прошли, собираем и деплоим.

Типичные ошибки при настройке

Не используют Bundler. Устанавливают Fastlane глобально через gem install fastlane и потом удивляются, почему на CI другая версия и что-то ломается. Всегда фиксируй версию через Gemfile.

Хранят секреты в Fastfile. Видел это не раз: кто-то закоммитил Apple ID и пароль прямо в репозиторий. Все чувствительные данные — только через переменные окружения.

Не используют readonly: true для match на CI. Если CI попытается создать новый сертификат и не сможет (нет прав), пайплайн упадёт в самый неподходящий момент.

Забывают про xcode-select. На CI нужно явно указывать версию Xcode. Разные версии Xcode могут давать разные результаты сборки. В GitHub Actions это делается через xcode-select -s /Applications/Xcode_15.4.app.

Слишком длинные lanes. Если lane делает 15 вещей подряд, найти проблему сложно. Лучше разбить на маленькие lanes и вызывать одни из других.

Сколько времени это экономит

Конкретные цифры из практики: ручной деплой в TestFlight занимает 20-40 минут активного внимания разработчика. С Fastlane — 2-3 минуты на запуск команды, остальное работает само.

Если деплоить раз в неделю, это около 30 минут экономии. Если два раза в день — несколько часов в неделю. Плюс снижается число ошибок: забытый bump версии, неправильный provisioning profile, не тот scheme — всё это уходит.

Для команды из трёх разработчиков настройка Fastlane + CI занимает примерно день работы. Окупается за месяц.

С чего начать прямо сейчас

Если никогда не пробовал Fastlane — начни с малого. Возьми существующий проект и настрой один lane, который просто собирает приложение и загружает в TestFlight. Без match, без CI — просто локальный запуск.

Когда это заработает и ты поймёшь механику, добавь match. Потом подключи GitHub Actions или другой CI. Не пытайся сразу настроить всё идеально — это путь к тому, что ничего не будет настроено вообще.

Документация Fastlane на docs.fastlane.tools подробная и хорошо структурированная — там есть примеры для большинства типичных сценариев.

Если разрабатываешь мобильное приложение в связке с бэкендом или веб-частью — REEXY занимается и серверной разработкой, и интеграциями, так что автоматизацию можно выстроить сквозную: от коммита до продакшена на всех платформах одновременно.

Автоматизация сборки — это не про сложность. Это про то, чтобы не делать руками то, что машина делает лучше.