Налаштування 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 start executor 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 день — просто напишіть нам.







