Настройка CI/CD для мобильного приложения через GitLab CI
Ручной запуск сборок и деплоя мобильного приложения — источник ошибок и потерянного времени. По статистике, до 30% времени разработки уходит на ручные операции сборки и деплоя. GitLab CI автоматизирует этот процесс: каждый коммит запускает сборку, тесты и доставку в сторы. Мы настраиваем CI/CD под ключ более 5 лет, гарантируем стабильность и поддержку. Оценим ваш проект за 1 день — просто напишите нам.
GitLab CI — оптимальный выбор для команд, которые уже держат репозиторий на GitLab (self-hosted или cloud). Конфигурация в .gitlab-ci.yml, раннеры — GitLab-managed или собственные. Для iOS-сборки нужен зарегистрированный macOS self-hosted runner: GitLab SaaS предоставляет только Linux/Windows-раннеры в стандартных планах. Сравнение с Jenkins: GitLab CI проще в настройке, не требует отдельного сервера и имеет встроенные registry, артефакты и environments.
Проблемы, которые решает GitLab CI
- Ручная сборка и подпись — ошибки из-за несовместимости профилей, забытых сертификатов.
- Отсутствие автоматических тестов — регрессии попадают в продакшен.
- Долгая доставка в стори — каждый релиз требует часа ручной работы.
- Невозможность повторить сборку — локальные окружения различаются.
- Отсутствие контроля версий артефактов — сложно откатить релиз.
GitLab CI решает все эти проблемы: сборка повторяема, тесты запускаются на каждый MR, артефакты хранятся с привязкой к коммиту. По нашим оценкам, автоматизация сокращает время релиза на 40%.
Почему self-hosted macOS runner критичен для iOS?
Standard GitLab SaaS runners не предоставляют macOS, поэтому сборка iOS возможна только на собственном Mac. Регистрация раннера:
# На Mac mini или MacBook, который будет CI-машиной
brew install gitlab-runner
gitlab-runner register \
--url https://gitlab.com \
--registration-token $RUNNER_TOKEN \
--executor shell \
--description "macos-m2-runner"
gitlab-runner startexecutor shell — раннер выполняет команды напрямую в shell, без Docker-контейнера. Для iOS это единственный реалистичный вариант, так как Xcode не работает в Docker.
Важно: раннер должен работать как LaunchDaemon, не как пользовательский процесс, иначе при перезагрузке Mac CI останавливается. Настройка через sudo gitlab-runner install --user runner. Мы используем Mac mini M2 с 16 ГБ RAM — этого хватает для параллельной сборки двух конфигураций. Гарантируем uptime 99.9%.
Структура .gitlab-ci.yml для iOS + Android
stages:
- test
- build
- distribute
variables:
FASTLANE_SKIP_UPDATE_CHECK: "true"
BUNDLE_PATH: vendor/bundle
.ios_job:
tags:
- macos-m2
before_script:
- bundle install --path $BUNDLE_PATH
.android_job:
image: androidsdk/android-34
tags:
- linux-docker
ios:test:
extends: .ios_job
stage: test
script:
- bundle exec fastlane test
artifacts:
reports:
junit: fastlane/test_output/report.junit
paths:
- fastlane/test_output/
expire_in: 1 week
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == "main"
ios:beta:
extends: .ios_job
stage: distribute
script:
- bundle exec fastlane beta
environment:
name: beta
rules:
- if: $CI_COMMIT_BRANCH == "main"
needs: [ios:test]
android:build:
extends: .android_job
stage: build
script:
- ./gradlew test assembleRelease
cache:
key: $CI_COMMIT_REF_SLUG
paths:
- .gradle/
- vendor/bundle
artifacts:
paths:
- app/build/outputs/apk/release/
expire_in: 3 days
Сравнение этапов для iOS и Android:
| Стадия | iOS (macOS runner) | Android (docker runner) |
|---|---|---|
| Test | fastlane test |
./gradlew test |
| Build | fastlane beta (archive) |
./gradlew assembleRelease |
| Distribute | TestFlight / App Store | Google Play Console / Firebase |
Как настроить code signing без утечки ключей?
GitLab хранит секреты в Settings → CI/CD → Variables. Для iOS code signing используем:
---
before_script:
- echo "$MATCH_KEYSTORE" | base64 -d > /tmp/match.keystore
- bundle exec fastlane match adhoc --readonly true
- echo "$ASC_API_KEY" > /tmp/AuthKey.p8
- export APP_STORE_CONNECT_API_KEY_PATH=/tmp/AuthKey.p8
MATCH_KEYSTORE и MATCH_PASSWORD — masked variables в GitLab. Masked переменные не выводятся в логах даже при echo. Согласно документации GitLab, такой подход обеспечивает защиту от утечки.
Для App Store Connect API Key — File-тип переменной с .p8-файлом. С помощью Fastlane match можно автоматически обновлять provisioning profiles при смене устройства или добавлении нового разработчика.
Кэширование для ускорения сборки
GitLab CI кэш привязан к ключу. Для CocoaPods:
cache: key: files: - Podfile.lock paths: - Pods/ - vendor/bundle Ключ кэша по Podfile.lock инвалидируется автоматически при изменении зависимостей. Для Gradle аналогично через *.gradle*. Это сокращает время сборки на 40–60%.
Environments и деплой по веткам
ios:staging:
stage: distribute
script:
- bundle exec fastlane beta
environment:
name: staging
rules:
- if: $CI_COMMIT_BRANCH == "develop"
ios:production:
stage: distribute
script:
- bundle exec fastlane release
environment:
name: production
rules:
- if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/
when: manual # Требует подтверждения в UI
when: manual для production — нажатие кнопки в GitLab UI как gate перед релизом. Полезно, когда QA должен подтвердить перед отправкой в App Store. Production release блокируется до ручного одобрения — это стандартная практика для контроля качества.
Что входит в настройку CI/CD под ключ
При заказе настройки CI/CD вы получаете:
- Файл
.gitlab-ci.ymlс этапами test, build, distribute для iOS и Android. - Настроенный self-hosted раннер (macOS для iOS, Linux/Windows для Android).
- Интеграцию с Fastlane для code signing и деплоя в TestFlight / Google Play.
- Настройку кэширования артефактов и зависимостей.
- Конфигурацию environments и правил для разных веток/тегов.
- Документацию по пайплайну и обучение команды (1 час).
- Поддержку в течение 2 недель после запуска — исправляем любые проблемы.
Сроки и стоимость
Базовая настройка (macOS-раннер, test + beta lanes): 3–5 дней. Полная конфигурация с environments, Android-конвейером, кэшированием, review-apps: 1.5–2 недели. Стоимость рассчитывается индивидуально.
Закажите настройку CI/CD для своего мобильного приложения. Оценим проект за 1 день — просто напишите нам.







