Налаштування CI/CD для мобільного додатку через GitLab CI
GitLab CI—оптимальний вибір для команд, які вже тримають репозиторій на GitLab (self-hosted або cloud). Конфігурація в .gitlab-ci.yml, раннери—GitLab-керовані або self-hosted. Для iOS-сборки потрібен зареєстрований macOS self-hosted раннер: GitLab SaaS надає тільки Linux/Windows-раннери в стандартних планах.
Self-hosted macOS-раннер для iOS
Реєстрація раннера:
# На 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 start
executor shell—раннер виконує команди прямо в shell, без Docker-контейнера. Для iOS це єдиний реалістичний варіант, так як Xcode не працює в Docker.
Важливо: раннер повинен працювати як LaunchDaemon, не як користувацький процес, інакше при перезавантаженні Mac CI зупиняється. Настройка через sudo gitlab-runner install --user runner.
Структура .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
Кодування підписів через GitLab CI/CD Variables
GitLab зберігає секрети в Settings → CI/CD → Variables. Для iOS-кодування підписей:
before_script:
- echo "$MATCH_KEYSTORE" | base64 -d > /tmp/match.keystore
- bundle exec fastlane match adhoc --readonly true
MATCH_KEYSTORE та MATCH_PASSWORD—masked змінні в GitLab. Masked змінні не выводятся в логах навіть при echo.
Для App Store Connect API Key—File-тип змінної з .p8-файлом:
- echo "$ASC_API_KEY" > /tmp/AuthKey.p8
- export APP_STORE_CONNECT_API_KEY_PATH=/tmp/AuthKey.p8
Кешування
GitLab CI кеш прив'язаний до ключа. Для CocoaPods:
cache:
key:
files:
- Podfile.lock
paths:
- Pods/
- vendor/bundle
key.files—кеш інвалідується автоматично при зміні Podfile.lock. Для Gradle аналогічно через .gradle.
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 як врата перед релізом. Корисно, коли QA повинен підтвердити перед отправкой в App Store.
Часова шкала
Базова настройка (macOS-раннер, test + beta lanes): 3–5 днів. Повна конфігурація з environments, Android-конвейєром, кешуванням, review-apps: 1.5–2 тижні. Стоимость рассчитывается индивидуально.







