Домой Android разработкаОрганизация кода и DevOps Удобный deploy android приложения

Удобный deploy android приложения

by dilix

Deploy (выкатывание) андроид приложения можно разделить на несколько стадий — публикация для внутренней команды тестирования, развертывание на альфа и бета тестировщиков и, наконец, релиз приложения в Google play маркет. Давайте разберемся, как сделать это удобным для всех и что классный руководитель команды разработки должен учесть при построении системы. Поехали…

Все сказанное ниже (и выше) применимо не только к сборке android, но и вообще любых мобильных приложений, да что там — вообще любых продуктов, которые в конечном итоге надо доставить до потребителя.

Для кого мы это делаем?

Для начала давайте выделим широкие группы людей, их цели и интересы.

Разработчики приложения

Собственно команда разработки, которая пишет код и хочет

  • Чтобы их не дергали, когда нужно в очередной раз выкатить сборку для тестировщиков
  • Быть уверенной в том, что тестировщики проверяют именно ту версию, которая пойдет в релиз
  • Спокойно по очереди уйти в отпуск и не остановить весь проект, потому что «некому собрать приложение»
  • Чтобы дебаг ошибок, обнаруженных у других людей был максимально просто и прозрачен

Команда тестирования — QA

Те, кто отвечает за качество конечного продукта и надеется, что

  • Именно протестированная версия уйдет в релиз
  • Если задача закрыта в таск трекере, то сборка с фиксом уже доступна для скачивания
  • Получение очередной сборки не будет причинять боль и страдания, а будет проходить максимально легко и непринужденно

Внешние тестировщики, инвесторы и другие причастные

Наши бета тестеры, которые будут получать предрелизные сборки, и которые

  • Не будут ставить приложения из полученного не пойми как APK
  • Не всегда смогут справится с любым flow, отличным от «зайти в google play, установить приложение»
  • Хотят получаться максимально стабильный билд с новым функционалом

Конечные пользователи приложения

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

Люди из этой группы

  • Будут пользоваться финальным зарелиженным продуктом
  • Могут «надавать по шапке» за очевидные баги
  • Ждут стабильной, оттестированной версии продукта как только она будет готова

Что нужно знать?

Чтобы обеспечить постоянный контроль того, что делает команда разработки (а если этого не сделать, то чёрт его знает что в итоге может получиться), мы будем придерживаться принципов Continuous Integration (непрерывная интеграция) и Continious delivery (непрерывная доставка) которые предполагают, что как только очередной функционал готов с точки зрения команды разработки — он тут же будет доставлен дальше по цепочке.

Для примера мы будем использовать

  • CircleCI как сервер для сборки нашего приложения, хотя можно использовать по сути что угодно, будь то Jenkins, TeamCity или любой другой, да хоть самописный, продукт
  • Beta from Fabric поможет доставить ваше приложение для внутренних тестировщиков, если вы хотите
    • использоваться несколько разных сборок, но не создавать «приложение» в google play под каждую
    • начать deploy вашего приложения, не заполняя перед этим всех данных для приложения в google play (иначе не выйдет использовать их каналы дистрибуции)
  • Tiple-T плагин, который поможет автоматизировать доставку приложения в google play

Как это работает

Удобный deploy android приложения

Как только код попадает в стабильную ветку, например develop, master, rc (исходя из gitflow) сервер сборки упакует приложение и отправит определенным группам получателей.


Подключения вашего репозитория к CircleCI

Если проект у вас на Github, Bitbucket — то интеграция с CircleCI работает из коробки.

Возможный конфиг для CircleCI

version: 2
jobs:
  develop_build:
    working_directory: ~/code
    docker:
    - image: circleci/android:api-28-alpha
    environment:
      JVM_OPTS: -Xmx3200m
    steps:
    - checkout
    - restore_cache:
        key: jars-{{ checksum "build.gradle" }}-{{ checksum  "app/build.gradle" }}
    - run:
        name: Pull Submodules
        command: |
          git submodule sync --recursive
          git submodule update --recursive --init
    - run:
        name: Chmod permissions
        command: chmod +x gradlew
    - run:
        name: Download Dependencies
        command: ./gradlew androidDependencies
    - save_cache:
        paths:
        - ~/.gradle
        key: jars-{{ checksum "build.gradle" }}-{{ checksum  "app/build.gradle" }}
    - run:
        name: Generate fabric config
        command: ./gradlew fabricProp
    - run:
        name: Build dev release
        command: ./gradlew assembleDevDebug -PversionCode=$CIRCLE_BUILD_NUM
    - run:
        name: Upload dev release to fabric
        command: ./gradlew crashlyticsUploadDistributionDevDebug
  rc_build:
    working_directory: ~/code
    docker:
    - image: circleci/android:api-28-alpha
    environment:
      JVM_OPTS: -Xmx3200m
    steps:
    - checkout
    - restore_cache:
        key: jars-{{ checksum "build.gradle" }}-{{ checksum  "app/build.gradle" }}
    - run:
        name: Pull Submodules
        command: |
          git submodule sync --recursive
          git submodule update --recursive --init
    - run:
        name: Chmod permissions
        command: chmod +x gradlew
    - run:
        name: Download Dependencies
        command: ./gradlew androidDependencies
    - save_cache:
        paths:
          - ~/.gradle
        key: jars-{{ checksum "build.gradle" }}-{{ checksum  "app/build.gradle" }}
    - run:
        name: Generate fabric config
        command: ./gradlew fabricProp
    - run:
        name: Build RC
        command: ./gradlew assembleRcRelease -PversionCode=$CIRCLE_BUILD_NUM
    - run:
        name: Upload RC to fabric
        command: ./gradlew crashlyticsUploadDistributionRcRelease
  master_build:
    working_directory: ~/code
    docker:
    - image: circleci/android:api-28-alpha
    environment:
      JVM_OPTS: -Xmx3200m
    steps:
    - checkout
    - restore_cache:
        key: jars-{{ checksum "build.gradle" }}-{{ checksum  "app/build.gradle" }}
    - run:
        name: Pull Submodules
        command: |
          git submodule sync --recursive
          git submodule update --recursive --init
    - run:
        name: Chmod permissions
        command: chmod +x gradlew
    - run:
        name: Download Dependencies
        command: ./gradlew androidDependencies
    - save_cache:
        paths:
        - ~/.gradle
        key: jars-{{ checksum "build.gradle" }}-{{ checksum  "app/build.gradle" }}
    - store_artifacts:
        path: app/build/reports
        destination: reports
    - store_test_results:
        path: app/build/test-results
    - run:
        name: Upload Prod build to Google play
        command: ./gradlew publishProdReleaseBundle -PversionCode=$CIRCLE_BUILD_NUM
workflows:
  version: 2
  build_app:
    jobs:
    - develop_build:
        filters:
          branches:
            only: develop
    - master_build:
        filters:
          branches:
            only: master
    - rc_build:
        filters:
          branches:
            only: /rc\/.*/

Workflows содержит 3 конфигурации, которые запускаются в случаях, попадаемых под фильтры, а именно

  • Если был залит код в ветку develop, то соберется devDebug версия и отправится в Fabric Beta
  • Если был залит код в ветку rc/{что-угодно}, то соберется rcRelease версия и отправится в Fabric Beta
  • Если был залит код в ветку master, то соберется releaseBundle версия и отправится в Google play в канал для внутреннего тестирования

Чтобы обфускация не усложняла жизнь разработчику, для внутреннего тестирования можно выкатывать версию без нее, но важно проверить приложение и с обфускацией, потому что она может сломать сборку!

В данном конкретном случае каждый flavor нацелен на разные контура на сервере и у каждого свой отдельный суффикс и иконка, что удобно при тестировании.

Метод fabricPror выставляет необходимые ключи для деплоя версии в fabric beta:

task('fabricProp') {
    doLast {
        def propertiesFile = file('fabric.properties')
        def commentMessage = "This is autogenerated fabric property from system environment to prevent key to be committed to source control."
        ant.propertyfile(file: "fabric.properties", comment: commentMessage) {
            entry(key: "apiSecret", value: System.getenv('crashlyticsBountyApisecret'))
            entry(key: "apiKey", value: System.getenv('crashlyticsBountyApikey'))
        }
    }
}

При этом crashlyticsBountyApisecret и crashlyticsBountyApikey это переменные, заданные на сервере CircleCI, т.е. необязательно ведь всей команде знать конфиденциальные данные, верно?

Там же, кстати, хранятся и ключи для сертификатов подписи приложения.

Удобный deploy android приложения

Доставка приложения в Fabric Beta

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

def getBuildNumber = { ->
    def DEFAULT_CODE = 1
    def code = project.hasProperty('versionCode') ? versionCode.toInteger() : DEFAULT_CODE
    println "BuildNumber is set to $code"
    return code
}

....
    versionCode getBuildNumber()
....

Доставка приложения в Google play

Как только приложение протестировано на внутренней сборки, можно отправить версию в канал дистрибуции для внутреннего тестирования в Google play, с чем нам и поможет плагин Triple-T, настройку которого можно найти у него же на странице на github.

Вместо заключения

Ценно не только то, на сколько хорошо вы пишите код, но и то, как вы умеете коммуницировать со своей командой и делать жизнь каждого проще и приятнее. А если продукт, над которым ваша команда работает планирует развиваться, то упрощение процесса разработки и деплоя сэкономит уйму сил, времени и нервов, потому что это то, что будет происходит каждый ваш рабочий день и то, что точно стоит автоматизировать.

Успех — это сумма маленьких достижений, повторяющихся изо дня в день

Хочешь обсудить Android разработку?
Заходи к нам Вконтакте, на Facebook и в Телеграм!

Добавить комментарий

Может быть интересно

Этот сайт использует Cookie файлы для улучшения вашего пользовательского взаимодействия. Используя данный сайт вы соглашается с этим. Принять Читать

Политика конфиденциальности и Cookies