Настраиваем fastlane на выделенном сборочном сервере Mac
На сборочном сервере Mac установите fastlane через Bundler, как предпочитает fastlane, или через Homebrew. Храните подпись в match, запускайте его в CI в режиме readonly и входите в Apple с ключом App Store Connect API. Начинайте lanes для CI с setup_ci, чтобы fastlane использовал временную связку ключей. Тогда задача CI выполняет одну команду: bundle exec fastlane beta.
Что нужно заранее
- Mac с Xcode, правами администратора и Homebrew.
- Агент CI на этом Mac: GitHub Actions, GitLab, Buildkite, Jenkins или CircleCI.
- Аккаунт App Store Connect с правом создавать API-ключи.
- Приватный Git-репозиторий для match или бакет в Google Cloud или S3.
1. Установите fastlane
Документация fastlane, которую мы читали в октябре 2026 года, предпочитает Bundler. Поддерживается Ruby 3.2 или новее, а предпочтителен 3.3 или новее. Системный Ruby из macOS использовать не советуют. Установите актуальный Ruby через менеджер версий, например rbenv. Затем добавьте в проект Gemfile:
source "https://rubygems.org" gem "fastlane"
gem install bundler bundle update git add Gemfile Gemfile.lock
Bundler фиксирует версию fastlane в Gemfile.lock. Каждая машина и каждый запуск CI получают одну и ту же. Запускайте его как bundle exec fastlane.
На одном сборочном сервере проще путь через Homebrew. Он приносит свой Ruby:
brew install fastlane
Выберите один путь для проекта. Если их смешать, на одной машине окажутся две версии fastlane.
2. Создайте ключ App Store Connect API
fastlane советует API-ключи вместо входа через Apple ID: нет запроса двухфакторной аутентификации, выше скорость и надёжность. В App Store Connect откройте Users and Access, затем Integrations, затем App Store Connect API. Создайте Team Key. fastlane отмечает, что вызовам для provisioning нужен именно командный ключ. Дайте ему минимальную роль, которой достаточно. Запишите Issuer ID и Key ID. Сразу скачайте файл .p8, потому что Apple даёт скачать его только один раз.
mkdir -p ~/.appstoreconnect mv ~/Downloads/AuthKey_ABC123XYZ.p8 ~/.appstoreconnect/ chmod 600 ~/.appstoreconnect/AuthKey_ABC123XYZ.p8
Храните ключ на сборочном Mac или в хранилище секретов вашего CI. Никогда не коммитьте его.
3. Настройте match один раз с машины разработчика
bundle exec fastlane match init bundle exec fastlane match development bundle exec fastlane match appstore
match init спрашивает, где хранить сертификаты, и создаёт Matchfile. Следующие две команды создают сертификаты и профили и сохраняют их в это хранилище в зашифрованном виде. Выберите надёжную парольную фразу. CI читает её из переменной MATCH_PASSWORD.
fastlane советует режим readonly в любой CI-системе. Тогда CI только скачивает то, что уже есть, и ничего не создаёт и не отзывает.
4. Напишите lanes
default_platform(:ios)
platform :ios do
lane :test do
run_tests(
scheme: "MyApp",
devices: ["iPhone 17"],
result_bundle: true
)
end
lane :beta do
setup_ci
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"]
)
match(type: "appstore", readonly: is_ci, api_key: api_key)
increment_build_number(
build_number: latest_testflight_build_number(api_key: api_key) + 1
)
build_app(scheme: "MyApp")
upload_to_testflight(api_key: api_key, skip_waiting_for_build_processing: true)
end
endsetup_ci создаёт временную связку ключей, переводит match в режим readonly и настраивает пути для логов и результатов тестов. Он срабатывает, только когда fastlane определяет запуск в CI. Если ваш CI не определяется, передайте force: true. Без ожидания обработки сборки задача заканчивается раньше. Но fastlane отмечает, что тогда пропускается и раздача внешним тестировщикам.
5. Вызовите это из CI
Любая CI-система выполняет одни и те же строки shell. Храните секреты в CI, а не в репозитории.
export LANG=en_US.UTF-8 export LC_ALL=en_US.UTF-8 bundle install bundle exec fastlane beta # needs MATCH_PASSWORD, ASC_KEY_ID, ASC_ISSUER_ID and ASC_KEY_PATH set as CI secrets
В GitHub Actions эти строки идут в шаг run, а секреты передаются через env. На Mac от MacRun ПО раннера GitHub Actions уже установлено. Наше руководство по настройке iOS в GitHub Actions показывает полный workflow. В GitLab, Buildkite или CircleCI положите те же строки в script задачи. В Jenkins используйте шаг sh.
Как это переживает перезагрузки
fastlane не служба. Он работает внутри задачи вашего агента CI. Перезагрузку должны пережить агент и его сессия пользователя. Настройте агента как LaunchAgent с автоматическим входом, как в наших руководствах по GitLab Runner и Buildkite. Временная связка ключей из setup_ci создаётся заново при каждом запуске. Заблокированная после перезапуска связка ключей входа не может её остановить.
Частые ошибки и их решения
Они описаны в документации fastlane.
- Странные ошибки кодировки или падения в CI. fastlane нужна локаль UTF-8. Задайте
LANGиLC_ALLравнымиen_US.UTF-8. - Задача зависает на запросе двухфакторной аутентификации. Используйте API-ключ. С Apple ID задайте
SPACESHIP_ONLY_ALLOW_INTERACTIVE_2FA, чтобы задача вместо этого быстро падала. - match пытается создать новые сертификаты в CI. Используйте
readonlyили сначала вызовитеsetup_ci. - match не может клонировать свой репозиторий. GitHub не принимает один deploy key для двух репозиториев. Используйте машинный аккаунт только для чтения, или
git_private_key, илиMATCH_GIT_BASIC_AUTHORIZATION. - Профили установлены, но Xcode их не видит. В Xcode 16 папка профилей переехала. fastlane следует выбранному Xcode, поэтому на машинах с двумя Xcode вызывайте
xcode_selectперед match.
Чем помогает выделенный Mac
build_app и run_tests это сборки Xcode. На машине, которая хранит DerivedData и установленные gems, они идут гораздо быстрее. В нашем тесте на iOS-приложении Wikipedia с Xcode 26.6 чистая сборка заняла 86 секунд на M6. На hosted раннере macos-26 у GitHub она заняла 183 секунды. Задача после небольшого изменения заняла 27 секунд на прогретой машине против 269 на свежей.
Когда сборочный сервер не нужен
Если вы выкладываете сборку в TestFlight раз в неделю, hosted раннер или Xcode Cloud потребуют меньше работы. Этот выбор разобран в нашем руководстве об альтернативе Xcode Cloud. Также учтите, чего MacRun не делает. Мы не управляем подписью кода за вас. Вы сами запускаете match, как на этой странице. SLA мы тоже не предлагаем.
Готовы к сборочному серверу? На странице цен есть все конфигурации, а документация по настройке показывает, как подключиться.
Частые вопросы
Как ставить fastlane на сборочный сервер: через Homebrew или Bundler?
+
fastlane предпочитает Bundler, потому что Gemfile.lock фиксирует версию. На одной машине проще Homebrew, и он приносит свой Ruby.
Что делает fastlane setup_ci?
+
Он создаёт временную связку ключей, переводит match в режим readonly и настраивает пути для логов и результатов тестов. Он срабатывает только в CI, если не передать force: true.
Зачем использовать с fastlane ключ App Store Connect API?
+
Ему не нужен запрос двухфакторной аутентификации. И fastlane называет его более быстрым и надёжным, чем сессия Apple ID. Для доступа к provisioning создайте Team Key.
Должен ли match работать в CI в режиме readonly?
+
Да. fastlane это советует. Тогда CI только скачивает существующие сертификаты и профили и никогда не создаёт и не отзывает их.