Статьяmobile

CI/CD для Flutter: автоматическая сборка и публикация в App Store и Google Play

Разбираем, как настроить CI/CD для Flutter: выбираем между Codemagic, GitHub Actions и Bitrise, настраиваем подпись и автозагрузку в TestFlight и Google Play.

Георгий Лихачев7 мин чтения

CI/CD для Flutter: автоматическая сборка и публикация в App Store и Google Play

Пятница, вечер, нужно срочно выпустить хотфикс. Разработчик собирает iOS-билд на своём MacBook, и вдруг Xcode сообщает, что сертификат истёк. Через час выясняется, что версия Flutter на его машине отличается от той, на которой собирали прошлый релиз. Знакомо?

CI/CD для Flutter решает эту проблему системно. Каждая сборка выполняется в чистом окружении с зафиксированными версиями SDK, тесты запускаются автоматически, а готовый билд сам попадает в TestFlight и Google Play Console.

По нашему опыту, ручной релиз Flutter-приложения для двух платформ занимает от 40 минут до двух часов. Это время разработчика, который мог бы писать код. Если релизы выходят раз в неделю, за год набегает до 100 часов впустую, не считая ошибок из-за человеческого фактора.

В этой статье мы разберём, зачем команде нужен автоматический пайплайн, сравним Codemagic, GitHub Actions и Bitrise, пошагово настроим сборку, тесты и подпись, а затем автоматизируем выгрузку в сторы. В конце собрали типичные ошибки с сертификатами, provisioning profiles и версионированием, на которые команды тратят дни.

Зачем Flutter-команде CI/CD: цена ручных сборок и релизов

Главная причина внедрять автоматизацию не в скорости, а в предсказуемости. Ручная сборка зависит от конкретной машины, установленных версий Flutter, Xcode, Gradle и от того, не забыл ли кто-то обновить зависимости. Фраза «у меня локально собирается» становится нормой, а не исключением.

Посчитаем реальную цену. Допустим, команда из пяти разработчиков делает два релиза в неделю на обе платформы. Каждый релиз отнимает около часа: сборка, подпись, выгрузка, проверка. Это 8 часов в месяц только на механические действия, а ещё не учтены повторные попытки после ошибок.

Вот что даёт CI/CD на практике:

  • Воспроизводимые сборки: одна и та же версия Flutter и зависимостей на каждом запуске.
  • Раннее обнаружение багов: анализатор и тесты запускаются на каждый pull request.
  • Независимость от людей: релиз может выпустить любой участник команды, даже без Mac.
  • Прозрачная история: по логам видно, какой коммит попал в какой билд.

Отдельная боль Flutter-проектов связана с iOS. Собрать приложение для App Store можно только на macOS, и если в команде нет выделенного Mac, релизы превращаются в очередь к чьему-то ноутбуку. Облачный CI снимает это ограничение полностью.

📘

Если вы только планируете проект, заложите CI/CD в архитектуру с первого спринта. Настроить пайплайн на пустом репозитории занимает полдня, а встраивать его в живой проект с накопившимся техдолгом — неделю и больше. Мы делаем это в рамках разработки Flutter-приложений.

Сравнение Codemagic, GitHub Actions и Bitrise для Flutter-проектов

Выбор платформы зависит от размера команды, бюджета и того, насколько глубоко вы готовы настраивать окружение. Рассмотрим три самых популярных варианта.

Codemagic Flutter-пайплайны создавались специально под Flutter. Платформа сама подтягивает нужную версию SDK, умеет автоматически управлять подписью iOS через App Store Connect API и публикует в сторы буквально в несколько строк конфигурации. Бесплатный тариф включает около 500 минут в месяц на macOS-машинах, чего хватает небольшому проекту.

GitHub Actions Flutter сборка — вариант для тех, кто уже живёт в GitHub. Преимущества: тесная интеграция с pull request, огромный маркетплейс actions и гибкость. Из минусов: подпись iOS придётся настраивать вручную, а минуты на macOS-раннерах тарифицируются с множителем 10 относительно Linux.

Bitrise предлагает визуальный редактор workflow и богатую библиотеку шагов. Он хорошо подходит командам, где есть и нативная, и Flutter-разработка. Но цена растёт быстрее, а бесплатных ресурсов меньше.

Краткие рекомендации по выбору:

  1. Небольшая команда, только Flutter, нужен быстрый старт: Codemagic.
  2. Код в GitHub, нужен полный контроль и единая экосистема: GitHub Actions.
  3. Смешанный стек, много интеграций, нужен визуальный конфигуратор: Bitrise.
💡

Гибридная схема тоже работает: тесты и анализ гоняйте в GitHub Actions на дешёвых Linux-раннерах, а iOS-сборку и публикацию отдавайте Codemagic. Так вы экономите дорогие macOS-минуты.

Сравнение Codemagic, GitHub Actions и Bitrise для Flutter-проектов

Настройка пайплайна: сборка, тесты, подпись iOS и Android

Рассмотрим базовый пайплайн на примере GitHub Actions. Логика одинакова для любой платформы: получить код, подготовить окружение, проверить качество, собрать и подписать артефакт.

Минимальный набор шагов выглядит так:

  1. Checkout репозитория и установка Flutter через subosito/flutter-action с зафиксированной версией SDK.
  2. Кэширование pub-зависимостей и Gradle, что сокращает сборку на 30–50%.
  3. Запуск flutter analyze и flutter test с отчётом о покрытии.
  4. Сборка Android: flutter build appbundle --release.
  5. Сборка iOS: flutter build ipa --release на macOS-раннере.

С подписью Android всё проще. Создайте upload keystore, закодируйте его в base64 и сохраните в секретах репозитория вместе с паролем и алиасом. На этапе сборки декодируйте файл и создайте key.properties, на который ссылается build.gradle. Никогда не коммитьте keystore в репозиторий.

С iOS сложнее. Нужны сертификат распространения (.p12), provisioning profile и корректный ExportOptions.plist. Современный подход — использовать App Store Connect API key: так инструменты вроде fastlane match или встроенное управление подписью Codemagic сами создают и обновляют сертификаты, и вам не нужно хранить .p12 вручную.

⚠️

Потеряв upload keystore без включённого Play App Signing, вы не сможете обновлять приложение. Всегда храните резервную копию ключа в менеджере секретов и включайте Play App Signing при первой публикации.

Для сложных многомодульных проектов и нескольких окружений (dev, staging, prod) используйте flavors и передавайте параметры через --dart-define. Подробнее о построении такой архитектуры мы рассказываем на странице кроссплатформенной разработки.

Автоматическая загрузка в TestFlight и Google Play Console

Сборка без доставки — это половина работы. Финальный этап пайплайна отправляет артефакты тестировщикам и в сторы, и именно здесь экономия времени максимальна.

Для публикации Flutter приложения в App Store через TestFlight нужен API-ключ App Store Connect с ролью App Manager. Загрузить ipa можно командой xcrun altool, через fastlane pilot или встроенной публикацией Codemagic. После обработки билда Apple отправит его внутренним тестировщикам автоматически, если включена соответствующая группа. Обработка обычно занимает 10–30 минут.

Для Google Play потребуется сервисный аккаунт в Google Cloud с доступом к Play Console и JSON-ключ. Загрузку выполняют через fastlane supply или готовый action. Рекомендуем публиковать сначала в трек internal, затем продвигать в closed, open и production.

Разумная стратегия веток и треков:

  • Pull request: анализ, тесты, debug-сборка без публикации.
  • Ветка develop: релизная сборка и выгрузка в TestFlight и internal-трек.
  • Тег вида v1.4.0: сборка для production и отправка на ревью с ручным подтверждением.

Полностью автоматическую отправку в production мы не советуем. Оставьте ручной шаг одобрения, например через environment protection rules в GitHub, чтобы человек подтверждал релиз.

Если в проекте есть веб-версия, тот же пайплайн можно расширить деплоем на хостинг, о чём мы писали в разделе про Flutter Web.

Автоматическая загрузка в TestFlight и Google Play Console

Типичные ошибки: сертификаты, provisioning profiles, версионирование

Большинство сбоев в мобильных пайплайнах повторяются из проекта в проект. Разберём главные и способы их избежать.

Истёкший сертификат. Сертификат распространения Apple живёт один год, и истекает он всегда в неудобный момент. Решение: перейти на автоматическое управление подписью через API-ключ и добавить календарное напоминание за месяц до даты окончания.

Несоответствие provisioning profile. Ошибка «No matching provisioning profile found» возникает, когда bundle ID, команда или тип профиля не совпадают с конфигурацией сборки. Проверьте, что для App Store используется профиль типа Distribution, а не Development, и что в ExportOptions указан правильный метод экспорта.

Конфликт версий. Магазины отклоняют билд, если build number не больше предыдущего. Не правьте номер вручную: берите его из переменной окружения, например из номера запуска CI или количества коммитов, и задавайте через --build-number.

Другие частые проблемы:

  • Нефиксированная версия Flutter, из-за чего сборка внезапно ломается после обновления.
  • Секреты в логах из-за неаккуратного вывода переменных.
  • Отсутствие кэша, раздувающее время и стоимость сборок.
  • Нет описания изменений для TestFlight, и тестировщики не понимают, что проверять.

Если в команде нет времени разбираться с инфраструктурой, имеет смысл привлечь внешнего специалиста: консультация по мобильной разработке обычно окупается за первый же спасённый релиз.

Ключевые выводы

  • Автоматизация релизов экономит десятки часов в год и устраняет зависимость от одной машины разработчика.
  • Codemagic быстрее всего стартует для Flutter, GitHub Actions даёт гибкость, Bitrise подходит смешанным стекам.
  • Фиксируйте версию Flutter, автоматизируйте подпись через API-ключи и генерируйте build number из CI.

Заключение

Настроенный CI/CD превращает релиз из стрессового ритуала в рутинную операцию: запушили тег, получили билд в TestFlight и Google Play. Команда перестаёт зависеть от чьего-то ноутбука, а ошибки подписи и версий отлавливаются до того, как их увидят пользователи.

Начните с малого. Сначала добавьте анализ и тесты на каждый pull request, затем автоматизируйте сборку, потом подключите публикацию во внутренние треки. Через несколько итераций у вас появится надёжный конвейер, который можно развивать: добавлять скриншот-тесты, проверки размера приложения и поэтапные выкатки.

Выберите инструмент под свои задачи, зафиксируйте версии, автоматизируйте сертификаты и оставьте ручное подтверждение для production. Эти четыре шага закрывают большинство проблем, с которыми сталкиваются Flutter-команды.

Получать разборы на почту

Пока собираем подписчиков. Когда запустим регулярные разборы — вы узнаете первыми.

Обсудим вашу задачу

Хотите настроить CI/CD для вашего Flutter-проекта без потерянных недель? Наши специалисты проведут бесплатную консультацию и предложат решение под ваш стек.
Оставить заявкуНаписать в TelegramОбычно отвечаем в течение 24 часов.