Irbisa · Шпаргалка

CI/CD и DevOps

GitHub Actions, Fastlane, Firebase Distribution, flavors

Senior-разработчик · 19 вопросов

  1. 01

    Чем APK отличается от AAB и что нужно, чтобы собрать подписанный релиз для Google Play и App Store?

    APK представляет собой пакет, который устройство ставит напрямую; AAB (Android App Bundle) служит форматом публикации, из которого Google Play собирает APK под каждое устройство, и для новых приложений Play требует его.

    // android/app/build.gradle.ktsimport java.util.Properties val keystoreProperties = Properties().apply {    val file = rootProject.file("key.properties")   // gitignored, written by CI    if (file.exists()) file.inputStream().use { load(it) }…
  2. 02

    Как управлять версиями Flutter-приложения: имя версии, номер сборки и кто их повышает?

    version: 1.4.2+87 в pubspec.yaml содержит два числа: 1.4.2 означает версию, которую видят пользователи, а 87 означает номер сборки, а сторы проверяют его по-разному: Google Play требует versionCode больше, чем у любой предыдущей загрузки; App Store Connect требует больший номер сборки для той же версии.

  3. 03

    Trunk-based или GitFlow для мобильного приложения: как выпустить хотфикс для версии в сторе, если в main уже лежат недоделанные фичи следующей недели?

    Trunk-based development с релизной веткой на каждую версию в сторе: хотфикс ответвляется от тега сборки, которая стоит у пользователей, получает исправление через cherry-pick из main и выходит новой патч-версией, а main тем временем идёт дальше, и хотфикс его не затрагивает.

    # Store: 1.4.2 (tag v1.4.2). main: 1.5 work, unfinished parts behind flags.# 1) The fix is merged into main through a normal PR first.FIX=$(git log origin/main --format=%H -1 --grep='fix: crash on empty cart') # 2) Branch from what users run, not from main.git switch -c release/1.4 v1.4.2   # or switch to the existing release/1.4…
  4. 04

    Что такое flavors во Flutter и как настроить сборки dev, staging и production?

    Flavors задают варианты сборки из одной кодовой базы: dev, staging и production собираются как отдельные приложения, которые могут стоять рядом на одном устройстве, и у каждого свой app id, название, иконка, подпись и бэкенд.

    // android/app/build.gradle.ktsandroid {    flavorDimensions += "environment"    productFlavors {        create("dev") {            dimension = "environment"…
  5. 05

    Чем --dart-define-from-file отличается от --flavor и как сборка, подписанная для production, может ходить в staging API?

    --flavor выбирает нативный вариант (app id, подпись, файлы Firebase), а --dart-define и --dart-define-from-file зашивают константы в Dart-код.

    // flutter build appbundle --flavor prod --dart-define-from-file=config/prod.json// config/prod.json: {"API_URL": "https://api.example.com"}import 'package:flutter/services.dart' show appFlavor; class AppConfig {  // const and no defaultValue: a missing define is an empty string, never "dev"…
  6. 06

    Что такое fastlane и что он даёт по сравнению с самописным скриптом в CI?

    fastlane представляет собой инструмент на Ruby, который упаковывает длинную цепочку команд подписи, сборки и загрузки в именованные lanes в Fastfile; после этого fastlane beta делает одно и то же и на ноутбуке, и на любой CI-машине.

    # ios/fastlane/Fastfiledefault_platform(:ios) platform :ios do  before_all do    setup_ci                      # temporary keychain; no-op outside CI…
  7. 07

    Как выбрать между GitHub Actions, Codemagic, Bitrise и Xcode Cloud для Flutter-приложения?

    Выбирают по тому, кто поддерживает пайплайн и где собирается iOS: Codemagic и Bitrise дают готовые Mac-машины и мобильные шаги, GitHub Actions даёт полный контроль рядом с кодом, а Xcode Cloud закрывает только сторону Apple.

  8. 08

    Как подписывать Android- и iOS-сборки в CI без утечки ключей?

    Материалы для подписи живут только в хранилище секретов CI, на время сборки раскодируются во временный файл и удаляются по окончании джобы; ничего связанного с подписью в репозиторий не коммитится.

    # .github/workflows/release.yml (Android part)jobs:  android:    runs-on: ubuntu-latest    environment: production          # secrets released only after approval    steps:…
  9. 09

    Как раздавать бета-сборки: Firebase App Distribution, TestFlight или тестовые треки Play?

    На iOS бета-каналом служит TestFlight; на Android выбирают между Firebase App Distribution для быстрых инженерных сборок и внутренним или закрытым тестовыми треками Play Console, которые доставляются через сам стор.

    # .github/workflows/beta.ymlname: betaon:  push:    branches: [main]…
  10. 10

    Как автоматизировать загрузку в Play Store и App Store из CI?

    Оба стора дают API для загрузки, и CI ходит в них с машинными учётными данными: сервисный аккаунт Google Cloud для Play и ключ App Store Connect API для Apple, но никогда не с логином конкретного человека.

    # android/fastlane/Fastfiledefault_platform(:android) platform :android do  lane :internal do    upload_to_play_store(…
  11. 11

    По каким причинам App Review или Google Play обычно отклоняют Flutter-приложение и как поймать их до отправки?

    Большинство отказов вызывает то, что видит ревьюер, а не Dart: вход, который он не может пройти, разрешения или данные, которые плагин принёс без декларации, iOS-метаданные с Android или слишком «тонкое» приложение.

  12. 12

    В debug приложение работает, а в release падает или остаётся без сети. Какие причины типичны и как поймать их раньше пользователей?

    Релизная сборка даёт другой бинарник: AOT-компиляция, вырезанные assert, сжатие R8, другой ключ подписи и релизный манифест.

    #!/usr/bin/env bashset -euo pipefail # 1) Build the binary users will get; `flutter test` never builds it.flutter build apk --release --flavor prod \  --dart-define-from-file=config/prod.json \…
  13. 13

    iOS-джоба в CI падает с «Generated.xcconfig must exist», хотя Xcode на раннере тот же, что у вас. Чего не хватает свежему клону?

    Файлов, которые генерирует flutter pub get: ios/Flutter/Generated.xcconfig и .flutter-plugins-dependencies лежат в gitignore, а Podfile читает этот xcconfig, чтобы найти Flutter SDK и поды плагинов.

    #!/usr/bin/env bashset -euo pipefail # Pin the Xcode this project is tested with; images ship several.sudo xcode-select -s "/Applications/Xcode_${XCODE_VERSION}.app"…
  14. 14

    Как бы вы спроектировали CI/CD для Flutter-приложения: что запускается на каждый pull request, что на релиз и на каких раннерах?

    Разделите его на две части: быстрый CI на каждый pull request, который доказывает корректность кода, и CD на main или на тег версии, который собирает подписанные артефакты и доставляет их тестировщикам, а затем в сторы.

    # .github/workflows/ci.ymlname: cion:  pull_request:  push:    tags: ['v*']…
  15. 15

    Что делает Flutter-приложение готовым к первому релизу в production, помимо зелёных тестов?

    Готовое к релизу приложение воспроизводимо собирается и подписывается в CI, сообщает вам, когда ломается у пользователей, может быть принудительно обновлено, имеет рискованные функции, которые можно отключить удалённо, и соответствует текущим техническим требованиям и требованиям приватности каждого стора.

  16. 16

    Каждый pull request ждёт CI 40 минут. Куда уходит время во Flutter-пайплайне и что резать в первую очередь?

    Прежде чем что-то менять, посмотрите время каждого шага.

    name: cion: [pull_request] concurrency:                       # a new push cancels the old run  group: ${{ github.workflow }}-${{ github.ref }}  cancel-in-progress: true…
  17. 17

    Как раскатывать релиз поэтапно и что делать, если новая версия оказалась сломанной?

    Поэтапная раскатка ограничивает число пользователей, до которых дойдёт плохая сборка, а заранее подготовленный план реагирования позволяет остановить ущерб, не дожидаясь ревью стора.

  18. 18

    Что такое code push через Shorebird, что может изменить патч и как принудительно перевести пользователей на новую версию, когда патч не поможет?

    Shorebird доставляет новый Dart-код в опубликованное приложение: shorebird release собирает версию для стора, shorebird patch выпускает исправление на следующий запуск.

    # The store build must come from Shorebird, not from plain `flutter build`.# Arguments after `--` are passed through to flutter build.shorebird release android --flavor prod -- --dart-define-from-file=config/prod.jsonshorebird release ios --flavor prod -- --dart-define-from-file=config/prod.json # Later: a Dart-only fix for users on 1.4.2+87, built with the same defines.…
  19. 19

    В монорепозитории с приложением и пятнадцатью пакетами правка одной строки запускает все тесты. Как тестировать в CI только то, что она может сломать?

    Фильтруйте по графу зависимостей, а не по папке, которую кто-то тронул: Melos умеет выбирать пакеты, изменённые с определённого git-ref (ветки или коммита), плюс все пакеты, которые от них зависят, и CI анализирует и тестирует только этот набор.

    # pubspec.yaml at the repo root (pub workspace + Melos 7)name: acme_workspaceenvironment:  sdk: ^3.9.0workspace:  - apps/shop…