Подготовка проекта Flutter к автоматическому деплою
Прежде чем интегрировать CI/CD, необходимо убедиться, что проект готов к безручной сборке и подписанию.
-
Файлы конфигурации
pubspec.yamlдолжен содержать все зависимости и версии.flutter_launcher_iconsиflutter_native_splashрекомендуется настроить заранее, чтобы генерация ресурсов происходила в ходе сборки.
-
Скрипты сборки
- Добавьте в
tool/скриптbuild_ios.sh, который выполнитflutter build ios --releaseи скопирует полученный.ipaв директориюbuild/ios. - Аналогичный скрипт
build_android.shзапускаетflutter build apk --release(илиappbundleдля AAB) и сохраняет артефакт вbuild/android.
- Добавьте в
-
Подпись
- Для iOS используйте Fastlane (
matchилиsigh) для управления сертификатами и профилями. - Для Android храните
key.jksиkey.propertiesв защищённом хранилище CI, а вgradle.propertiesукажите переменныеMYAPP_RELEASE_STORE_FILE,MYAPP_RELEASE_KEY_ALIASи т.д.
- Для iOS используйте Fastlane (
Настройка GitLab Runner
GitLab CI требует раннеров, способных выполнять macOS‑команды (для iOS) и Linux‑команды (для Android).
- macOS‑раннер: предпочтительно использовать self‑hosted macOS‑машину с установленным Xcode, CocoaPods и Fastlane.
- Linux‑раннер: любой Docker‑контейнер с предустановленным Flutter SDK, Android SDK и Fastlane.
Пример регистрации macOS‑раннера:
gitlab-runner register \
--url https://gitlab.com/ \
--registration-token $TOKEN \
--executor shell \
--description "macos-runner" \
--tag-list "macos,ios" \
--run-untagged="false"
Для Linux‑раннера удобно использовать Docker‑образ cirrusci/flutter:stable.
Управление секретами в GitLab
Все ключи и пароли должны храниться в переменных CI/CD:
| Переменная | Описание |
|---|---|
MATCH_PASSWORD | пароль для Fastlane match (iOS) |
APP_STORE_CONNECT_API_KEY | API‑ключ для загрузки в TestFlight |
SIGNIFICA_API_TOKEN | токен доступа к Significa |
GOOGLE_PLAY_SERVICE_ACCOUNT_JSON | JSON‑файл сервисного аккаунта Google Play |
ANDROID_KEYSTORE_BASE64 | Base64‑закодированный keystore для Android |
Для Android‑ключа используйте base64‑кодирование, а в пайплайне декодируйте его в файл key.jks.
Fastlane‑плейбуки для iOS
Fastlane упрощает работу с TestFlight и сторонними сервисами. Два основных lane:
platform :ios do
desc "Сборка и загрузка в TestFlight"
lane :beta do
match(type: "appstore")
build_app(scheme: "MyApp")
upload_to_testflight
end
desc "Сборка и загрузка в Significa"
lane :significa do
match(type: "appstore")
build_app(scheme: "MyApp")
upload_to_significa(
api_token: ENV["SIGNIFICA_API_TOKEN"],
changelog: "Automated build #{Time.now}"
)
end
end
upload_to_significa — пользовательская action, реализованная в Fastfile, которая отправляет .ipa через HTTP‑POST к API Significa.
Автоматизация публикации в Google Play
Для Android используется Fastlane supply. Требуется сервисный аккаунт с ролями Release Manager и Edit.
platform :android do
desc "Сборка и публикация в Google Play (internal track)"
lane :play_internal do
gradle(task: "clean assembleRelease")
supply(
track: "internal",
json_key: ENV["GOOGLE_PLAY_SERVICE_ACCOUNT_JSON"],
apk: "build/android/app-release.apk"
)
end
end
Для публикации в alpha или production меняется параметр track.
Пример .gitlab-ci.yml
stages:
- build
- deploy_ios
- deploy_android
variables:
FLUTTER_VERSION: "3.22.0"
PUB_CACHE: "$CI_PROJECT_DIR/.pub-cache"
.cache:
paths:
- .pub-cache/
- build/
build_ios:
stage: build
tags: ["macos"]
script:
- brew install flutter
- flutter --version
- ./tool/build_ios.sh
artifacts:
paths:
- build/ios/*.ipa
only:
- main
build_android:
stage: build
tags: ["linux"]
image: cirrusci/flutter:stable
script:
- flutter pub get
- ./tool/build_android.sh
artifacts:
paths:
- build/android/*.apk
only:
- main
deploy_testflight:
stage: deploy_ios
tags: ["macos"]
script:
- gem install bundler
- bundle install
- bundle exec fastlane beta
dependencies:
- build_ios
only:
- main
deploy_significa:
stage: deploy_ios
tags: ["macos"]
script:
- gem install bundler
- bundle install
- bundle exec fastlane significativa
dependencies:
- build_ios
only:
- main
deploy_google_play:
stage: deploy_android
tags: ["linux"]
image: cirrusci/flutter:stable
script:
- gem install bundler
- bundle install
- bundle exec fastlane play_internal
dependencies:
- build_android
only:
- main
Пайплайн состоит из трёх фаз: сборка, деплой iOS (две ветки) и деплой Android. Артефакты передаются между задачами через dependencies.
Частые проблемы и способы их обхода
| Проблема | Причина | Решение |
|---|---|---|
xcodebuild не находит профиль | Профиль не привязан к текущему сертификату | Убедиться, что match синхронизировал профиль, и переменные MATCH_PASSWORD актуальны |
Fastlane не видит APP_STORE_CONNECT_API_KEY | API‑ключ не экспортирован в окружение | Добавить переменную в GitLab CI и использовать app_store_connect_api_key в lane |
supply ругается на недоступный JSON‑ключ | JSON‑строка обрезана переводом строки | Хранить ключ в переменной как один‑строчный Base64 и декодировать перед запуском |
Сборка Android падает из‑за отсутствия JAVA_HOME | Docker‑образ не содержит JDK | Добавить image: openjdk:17 в задачу или установить JDK в контейнере |
Расширение пайплайна под дополнительные цели
GitLab CI позволяет добавить шаги после публикации:
- Отправка уведомлений в Slack/Telegram через встроенный
scriptилиintegration. - Запуск интеграционных тестов на реальных устройствах с помощью Firebase Test Lab (iOS) и Android VTS.
- Создание артефактов (например,
.zipсipa/aab) и их хранение в GitLab Packages для последующего скачивания.
Эти расширения повышают прозрачность процесса и позволяют быстро реагировать на сбои.
Итоги реализации
Полностью автоматизированный процесс доставки Flutter‑приложений в TestFlight, Significa и Google Play достигается за счёт комбинации:
- Fastlane – единый слой абстракции над платформенными API.
- GitLab CI/CD – оркестрация сборки, управление артефактами и безопасное хранение секретов.
- Self‑hosted раннеры – возможность выполнять macOS‑команды без ограничений облачных провайдеров.
После настройки пайплайна команда разработки освобождается от рутинных задач по подписи и загрузке приложений, а каждый коммит в ветку main автоматически превращается в готовый к тестированию или публикации билд.