- Как пользоваться Product Flavors и Build Variants для создания нескольких версий приложения
- Android: создание динамических Product Flavors и Signing Configs
- Исходные данные
- Проблемы с которыми мы столкнулись
- Проблемы:
- Вынос информации о сертификатах
- Упрощение Product Flavors секции
- Динамическое создание Product Flavors
- Русские Блоги
- Обучение сборке Android Gradle (три): варианты сборки
- Product flavors
- Build Type + Product Flavor = Build Variant
- Product Flavor Configuration
- Building and Tasks
- Зависимость компиляции
- Определение App flavors для приложений Flutter
- Определение нового флейвора
- Android
- Проблемы при сборке
- Заключение
- Организация Flavors во Flutter
- Для чего нужны Flavors
- Flavouring Flutter?
- Android
- Файлы конфигураций
- Build Configurations. Умножай на два.
- Добавление Scheme
- И вроде бы всё.
- No Provisioning Profile
- Разные файлы для разных bundle id
- Создание и размещения файлов
- Добавление файлов в приложение во время сборки
- Мысли после
Как пользоваться Product Flavors и Build Variants для создания нескольких версий приложения
Product flavors — незаменимая gradle-фича, полезная при создании нескольких версий одного Android-приложения (имею ввиду, например, версии demo/full/pro, а также вариации под различные устройства). Достаточно добавить несколько строк кода в раздел android <. >файла build.gradle :
В productFlavors могут находиться все те же правила, что и в элементе defaultConfig . В данном случае я переопределил applicationId , чтобы в Google Play это было отдельным приложением, и versionName , чтобы у пользователя отображалась соответствующая версия. Кстати, из defaultConfig эти дублирующие правила можно будет убрать.
После правки обновите проект (нажмите Sync Now, либо Refresh Gradle projects). Теперь можно добавлять классы и ресурсы специально для каждой из версий приложения.
Например, чтобы добавить ресурс, нужно кликнуть ПКМ по названию модуля и выбрать New > Android resource file. Далее можно будет указать для какой версии приложения нужен данный ресурс:
Таким образом можно легко дать приложению информацию о том, в каком режиме оно запущено, debug или release. Достаточно иметь 2 value-ресурса, один в main , другой, скажем, в debug , и в каждый из них добавить строчку с нужным значением, которое затем проверять при запуске приложения:
Идём дальше. Чтобы добавить разные классы для разных версий, нужно сначала создать соответствующую файловую структуру, например, src/free/java и src/pro/java .
Обратите внимание, что в отличие от ресурсов, нельзя создать один и тот же класс в папке main и, например, в папке pro . Возникнет ошибка дублирования. Если вам нужно иметь модификацию одного класса для разных версий, то создавайте в каждой из веток свою версию этого класса, а из папки main его убирайте. После выбора нужного Build Variant соответствующая ветка станет активной:
Источник
Android: создание динамических Product Flavors и Signing Configs
При работе над Android-проектом, представляющий собой платформу для создания приложений для просмотра видео-контента, возникла необходимость динамического конфигурирования product flavors с выносом информации о signing configs во внешний файл. Подробности под катом.
Исходные данные
Имеется Android-проект, представляющий собой платформу для создания приложений для просмотра видео-контента. Кодовая база общая для всех приложений, различия заключаются в настройках параметров REST API и настройках внешнего вида приложения (баннеры, цвета, шрифты и т.д.). В проекте использованы три flavor dimension:
- market: «google» или «amazon». Т.к. приложения распространяются как в Google Play, так и в Amazon Marketplace, имеется необходимость разделять некоторый функционал в зависимости от места распространения. Например: Amazon запрещает использование In-App Purchases механизма от Google и требует реализацию своего механизма.
- endpoint: «pro» или «staging». Специфические конфигурации для production и staging версий.
- site: собственно dimension для конкретного приложения. Задается applicationId и signingConfig.
Проблемы с которыми мы столкнулись
При создании нового приложения необходимо было добавить Product Flavor:
Также, необходимо было добавить соответствующий Signing Config:
Проблемы:
Вынос информации о сертификатах
Первым шагом был вынос информации о сертификатах в отдельный json-файл. Для примера информация так-же хранится в plain-text, но ничего не мешает хранить файл в зашифрованном виде (мы используем GPG) и расшифровывать непосредственно во время сборки приложения. JSON-файл имеет следующую структуру:
Секцию signingConfigs в build.gradle файле удаляем.
Упрощение Product Flavors секции
Для сокращения количества строк, необходимых для описания Product Flavor с dimension = «site», был создан массив с необходимой информацией для описания конкретного приложения, а все Product Flavors с dimension=»site» были удалены.
Было:
Динамическое создание Product Flavors
Последним шагом оставалось динамически создавать product flavors и signing configs используя внешний JSON-файл с информацией о сертификатах из массива applicationDefinitions.
Для добавления чтения из зашифрованного хранилища необходимо заменить секцию
Источник
Русские Блоги
Обучение сборке Android Gradle (три): варианты сборки
Gradle позволяет создавать разные версии одного и того же приложения, настраивая Build Vaiants. Здесь есть два основных сценария использования:
- Разные версии одного и того же приложения. Например, бесплатная версия и платная профессиональная версия.
- Одно и то же приложение необходимо упаковать в другой apk для выпуска Google Play Store.
- Объедините 1 и 2 сценария.
Gradle позволяет создавать разные APK в одном проекте вместо использования одного проекта библиотеки и двух или более проектов приложений для создания разных APK.
Product flavors
Вкус продукта определяет пользовательскую версию приложения, созданного на основе проекта. В одном проекте можно одновременно определять несколько различных вариантов для изменения вывода приложения.
Эта новая концепция дизайна предназначена для решения ситуации, когда различия между разными версиями очень малы. Хотя в конечном итоге проект создал несколько настраиваемых версий, но по сути это одно и то же приложение, этот подход может быть лучшим способом реализации, чем использование проектов библиотеки.
Вкус продукта должен быть указан в контейнере DSL продукта.
Здесь создаются два аромата с названиями аромат1 и аромат2.
Примечание. Имя разновидности не может конфликтовать с sourceSet существующего типа сборки или androidTest.
Build Type + Product Flavor = Build Variant
Как упоминалось в предыдущей главе, каждый тип сборки будет генерировать новый APK. Product Flavor также выполняет следующие функции:Выходные данные проекта будут объединены со всеми возможными комбинациями типа сборки и аромата продукта (если существует определение аромата).. Каждая комбинация (включая тип сборки и вид продукта) является вариантом сборки (версией варианта сборки).
Например, в приведенном выше примере объявления Flavor с типами сборки по умолчанию для отладки и выпуска будут сгенерированы 4 варианта сборки:
- Flavor1 — debug
- Flavor1 — release
- Flavor2 — debug
- Flavor2 — release
Если в проекте не определена разновидность, также будет вариант сборки, но будут использоваться разновидность и конфигурация по умолчанию.Вариант / конфигурация по умолчанию (по умолчанию) не имеет имени, поэтому сгенерированный список вариантов сборки выглядит так же, как список типов сборки.。
Product Flavor Configuration
Каждый аромат настраивается через закрытие:
Обратите внимание на android.productFlavors типа ProductFlavor.Тип объекта такой же, как у объекта android.defaultConfig. это означаетУ них одинаковые атрибуты*。
defaultConfig предоставляет базовую конфигурацию для всех разновидностей, и каждая разновидность может сбросить эти значения конфигурации. В приведенном выше примере окончательный результат настройки будет следующим:
В обычных условиях конфигурация типа сборки имеет приоритет над другими конфигурациями. Например, packageNameSuffix типа Build Type будет добавлен к packageName для Product Flavor.
В некоторых случаях некоторые параметры могут быть установлены как в типе сборки, так и в типе продукта. В этом случае решение основывается на принципе индивидуального приоритета.
Например, signatureConfig является примером этого атрибута. SigningConfig позволяет использовать один и тот же SigningConfig для всех пакетов выпуска, установив android.buildTypes.release.signingConfig. Вы также можете указать собственный SigningConfig для каждого пакета выпуска, установив android.productFlavors. *. SigningConfig.
Building and Tasks
Мы упоминали ранее, что каждый тип сборки создает свой собственныйassemble task, Но вариант сборки представляет собой комбинацию типа сборки и вкуса продукта.
При использовании Product Flavor будет создано больше задач типа сборки. Они есть:
- Assembly позволяет напрямую построить версию Variant, такую как buildFlavor1Debug.
- Assembly позволяет собрать все APK указанного типа сборки. Например, buildDebug будет собирать две вариантные версии Flavor1Debug и Flavor2Debug.
- Assembly
позволяет собрать все APK указанного варианта. Например, buildFlavor1 построит две версии Variant Flavor1Debug и Flavor1Release.
Кроме того, задача сборки построит все возможные комбинации версий Variant.
Модель разработки программного обеспечения с открытым исходным кодом: использованиеGitделатьуправление версиями, Используя gradle +android Идея распределенного строительства Studio использует несколько ветвей для параллельной разработки. Публичные компоненты распределяются между разными командами разработчиков через maven и используются в любое время.
Зависимость компиляции
1. Скомпилируйте зависимость. Зависимости времени компиляции и, наконец, их упаковка.
2. Предоставленная зависимость. Зависит во время компиляции, но не упакован в конце.
Источник
Определение App flavors для приложений Flutter
Этот пост будет полезен для Flutter-разработчиков, которым хочется поработать с флейворами (flavours), изменить и дополнить их. Сегодня мы не будем говорить о процессе создания флейворов с разными иконками, названиями и идентификаторами, благо таких публикаций существует уже очень много. Вместо этого речь пойдет о том, как определять флейвор в Dart-коде, а также о решении некоторых часто встречающихся при сборке приложений проблем, связанных с введением флейворов.
Почему можем об этом рассказать: наше мобильное приложение для модуля HCM-платформы TalentTech Обучение создано на Flutter.
Итак, я рассчитываю, что вы знаете, что такое флейвор и зачем он нужен (если нет, почитайте, например, вот этот материал). Поэтому мы сразу перейдем к тем вопросам, с которыми сталкивается разработчик Flutter, когда у него возникает задача определить новый флейвор.
Определение нового флейвора
Выбрать стандартный флейвор достаточно просто. Для этого необходимо указать его имя в настройках фреймворка. Например, в Android Studio нужно перейти в Run → Edit Configurations → и указать имя флейвора в поле Build Flavor вот так:
Но если требуется что-то более оригинальное, необходимо подготовить ваше приложение для работы с другим флейфором. Для этого можно добавить несколько строк кода на Dart:
Android
Под iOS процесс будет более многоступенчатым и потребует выполнить ряд ручных действий:
1.Для начала, точно также как и для Android, нужно определить обработчик для MethodChannel в методе application:didFinishLaunchingWithOptions. Сделать это необходимо в ios/Runner/AppDelegate.swift. Для этого достаточно выполнить следующий код:
2.Открыть ios/Runner/Info.plist. Добавить ключ Flavor типа String со значением $
3.Открыть Targets → Runner → Build Settings, нажать на “+”, выбрать Add User-Defined Setting и добавить настройку с названием PRODUCT_FLAVOR. Для каждой конфигурации задать имя флейвора, которое будет передаваться во Flutter.
4.Если для какого-то флейвора изменялся application identifier, нужно создать provisioning profile для него:
Пойти на developer.apple.com → Certificates, Identifiers & Profiles → Identifiers → + → App IDs → …
Выбрать Bundle ID explicit и указать там новый application identifier
В capabilities выбрать те же самые параметры, что и у основного identifier
Выполнить fastlane match —app_identifier “ “
Проблемы при сборке
Нередко при сборке приложения с обновленный флейвором возникают ошибки. На нашем опыте они чаще всего встречаются под iOS. И сегодня разберем две самые популярные из них:
ERROR: iOS архив успешно собран, но выдается неизвестная ошибка
Подобная ошибка может быть вызвана невалидным названием флейвора. В нашем случае не принимались квадратные скобки в названии (а конкретно в строке “[S] TT обучение”). Поэтому, если у вас возникает подобная ошибка, попробуйте сменить название, убрав из него нестандартные символы.
ERROR: Ошибка сертификата на iOS
В реальности описание такой ошибки может выглядеть следующим образом:
Для подобной ситуации было найдено проверенное решение. Разобраться с невалидными провижнами и сертификатами можно в несколько шагов:
Зайти в Runner → Target → Signing & Capabilities и проверить, что нигде нет красных восклицательных знаков
Зайти в Runner → Target → Build Settings, выполнить поиск по слову provision и попытаться найти, есть ли какая-то ошибка в результатах
Если запускаете на локальной машине:
Скачать провижны с помощью fastlane match
Зайти в Xcode → Preferences → Accounts → выбрать нужный аккаунт → Download Manual Profiles.
Если есть ошибки, то убить процесс Xcode, запустить заново и проверить еще раз (это реально помогает).
Если все это не сработало, поискать дополнительные подсказки можно в документации здесь или здесь, а также на https://stackoverflow.com
Заключение
Флейворы — полезная и удобная штука, но при попытке работать с ними могут возникать ошибки и сложности. Надеюсь, что этот небольшой пост поможет вам избежать проблем с определением флейвора, а также окажется полезен тем, у кого возникли те же ошибки при сборке приложения. Учитывая, что Flutter набирает популярность и становится все более востребованным, обмен опытом должен оказаться полезен для всех нас.
Источник
Организация Flavors во Flutter
Для чего нужны Flavors
Представьте ситуацию: есть приложение с аналитикой. Есть команда разработки, тестировщики и конечные пользователи. И те, и те пользуются одной версией приложения. Допустим мы хотим проанализировать насколько пользователям интересна фича А. Что в этом случае мы делаем? Идём в аналитику и смотрим сколько было использований данной фичи (например, переходов на экран). Но что же мы видим: запредельное число переходов, которое ну никак невозможно с текущей аудиторией, причём все эти переходы были в какой-то определенный отрезок времени. Мы идём дальше и понимаем, что в это время проводились тесты данной фичи. А чуть ранее её разработка. При этом аналитика также отсылалась. Итог: аналитика получается грязной и некачественной.
Здесь можно заменить слово аналитика на любое другое: пуш-нотификации, креш-репортинг и т.д.
И в этой ситуации нас спасает разделение приложения на две версии отличающиеся минимально, например Bundle ID(package-name). Разработчики и тестеры используют только специальную dev версию, а пользователи продовую.
Это как раз и есть одна из задач flavor’ов. Здесь будет использоваться именно flavor, так как именно это название используется Flutter’ом. Люди, которые знакомы с Android-разработкой, думаю сразу узнали этот механизм.
Flavouring Flutter?
Хорошо, мы разобрались с задачей. Но как это реализовать? Всё ли так просто, как пишут?
Давайте сразу определимся: организация flavor’ов — чисто нативная задача. Сама информация о них не будет доступна из dart кода. Поэтому и за способами организации мы пойдём в нативную мобильную разработку.
Android
Здесь всё просто. Ничем не отличается от стандартных способов в android. Конечно может возникнуть вопрос: «А почему бы не использовать buildType?», но об этом позже.
Итак, всё, что нам потребуется в минимальном варианте:
И всё, теперь мы можем с лёгкостью запустить команду:
на нашем android девайсе.
У некоторых вдумчивых разработчиков может возникнуть вопрос: «А почему не buildType?» Отвечаю: команда Flutter захардкодила buildType под свои нужды. Собственно, вся магия дебаг сборки в этом и заключается.
Немного о типах сборок и различных конфигурациях.
Итак, мы вспомнили про builtTypes. Тут надо немного поговорить о них и об их аналогах в IOS.
Можно провести следующее соответствие:
Android | IOS |
---|---|
build types | build configurations |
flavors | targets |
И типы сборок и конфигурации — это скорее нечто влияющее на саму сборку, в идеале не влияющее на кодовую базу или различия в приложениях (хотя вопрос спорный). А вот flavor’ы и target’ы — вполне удобный инструмент для создания двух приложений из одного и настройки отличий версии для разработчиков от версии пользователей.
И всё бы было хорошо, и настраивалось именно так, если бы не одно «но».
Runner — захардкоженный таргет.
Как оказалось, использовать target для реализации flavors на стороне iOS невозможно. Дело в том, что команда разработчиков Flutter по некоторым причинам подвязалась на это имя. И на этом можно было бы закончить всю работу, казалось бы. Но нет. Ведь можно использовать конфигурации сборки.
Задача: реализовать две конфигурации (dev, prod, отличающиеся наличием суффикса у версии для разработчиков).
- Создаём две конфигурации.
- В разработческой указываем суффикс.
- Профит!
А теперь разберём подробнее.
Файлы конфигураций
В наших проектах имеется две конфигурации: dev, prod. Содержимое у них примерно следующее:
Как мы видим, в них задаётся bundle_suffix.
К слову, кроме этого сам Flutter имеет конфигурации Release и Debug. В них надо также добавить bundle_suffix. Мы же не хотим, чтобы по умолчанию наша версия была версией для пользователей при запуске из своей любимой IDE.
Можно видеть некоторый параметр IDENTIFIER — с ним мы ознакомимся ниже.
Итак, создаём две конфигурации и располагаем в следующих путях:
Создание можно провернуть и через XCode (даже лучше, чтобы они добавились именно как конфигурационные файлы). Делается это с помощью щелчка правой кнопки по Runner → New File → Configuration Settings File → дальше выбираем место сохранения.
Build Configurations. Умножай на два.
Теперь разберёмся с конфигурациями сборки. Открываем Runner.xcworkspace в Xcode и выбираем представление Project.
Там находим кнопку «+» в разделе Configurations и создаём четыре конфигурации: две для Release и две для Debug, где постфиксом пишем название нашего конфига и будущей схемы приложения.
Выглядеть это будет примерно так:
К сожалению, дублировать конфигурации пока необходимо, так как скрипт ответственный за сборку IOS очень чувствителен к неймингу.
Добавление Scheme
Кроме создания файлов конфигурации необходимо также правильно настроить схемы приложения, их также две.
Их создание крайне простое. Важный момент: выберите правильный таргет — Runner.
Теперь выберите пункт Edit Scheme и проставьте необходимые конфигурации на каждом из этапов для схем.
И последний штрих (спойлер: далеко не последний) — устанавливаем параметр Bundle Identifier в Info.plist как
И вроде бы всё.
И вроде бы всё сделали, проект запускается, на Android всё вообще круто, но если вы вдруг решили использовать fastlane gym для подписи iOS — не получится. И вообще, IOS подпись приложения почему-то не работает… Давайте разберёмся.
No Provisioning Profile
Первая проблема при выгрузке — не найден профайл. Причём в ошибке выведен не тот идентификатор, что мы указали в конфиге.
Как оказалось, установка идентификатора через Info.plist не срабатывает, gym смотрит именно на PRODUCT_BUNDLE_IDENTIFIER, а он у нас одинаковый для всех конфигураций.
Помните загадочный файл common.xcconfig и параметр IDENTIFIER? Вот как раз они и решают эту проблему.
Создаём ещё один конфигурационный файл, в котором мы будем устанавливать по, сути, базовую часть нашего PRODUCT_BUNDLE_IDENTIFIER.
Содержимое описано одной строкой:
Подключаем этот файл через include в остальные конфиги и устанавливаем новую User Defined
переменную IDENTIFIER:
Теперь придётся немного поработать мышкой внутри Xcode. Переходим в наш таргет на вкладку Build Settings:
Далее в поиске ищем Product Bundle Identifier (раздел Packaging):
И меняем значение для всех конфигов на:
Теперь переходим в Info.plist и убираем из строки с идентификатором bundle suffix, оставляя только :
Пробуем собрать и подписать. Всё работает как необходимо.
Разные файлы для разных bundle id
Но мы решили подключить аналитику. Если мы используем Firebase, то понадобится два проекта и четыре приложения соответственно (две платформы под две версии).
И что самое главное — нам необходимо иметь два файла google-services.json(Google-Services.Info.plist). На стороне Android всё будет просто: мы создаем папку с названием нашего flavor’а и закидываем туда наш файл.
А вот с IOS нас ждёт крутое приключение с шелл-скриптами и фазами сборки.
Создание и размещения файлов
Первым делом необходимо создать в проекте папку, где будут храниться эти файлы. Мы используем следующую структуру:
Важно: не создаём их через XCode. Они не должны быть привязаны к проекту. Если всё же XCode — это ваша любимая IDE, при создании снимите галочки с пункта Add to target.
Далее располагаем наши файлы в соответствующих папках.
Добавление файлов в приложение во время сборки
Так как файлы не привязаны к проекту, в целевой архив они не попадут. А чтобы они всё-таки туда попали, надо в ручную их туда добавить.
Добавим дополнительный этап сборки в виде Run Script (setup firebase как пример названия):
Обратите внимание на расположение, оно играет решающую роль!
Теперь добавим сам скрипт, как один из вариантов можно использовать подобный:
Мысли после
С помощью этих довольно хитрых манипуляций мы настроили флейворинг. При этом, я очень надеюсь, что решение временное и в скором времени завезут систему сборки под Flutter (ведутся активные работы). Но пока мы имеем то, что имеем. И делаем жизнь проще своими руками.
Источник