Android Studio: Gradle Product Flavors: определение пользовательских свойств
Я создаю различные продукты для Android-приложений в Gradle (Android Studio).
Следовательно, я определил следующие ароматы продукта:
android {
project.ext.set("customer", "")
project.ext.set("server", "")
//Configuration happens here - code removed for readability
buildTypes {
debug {
server = "test"
}
release {
server = "release"
}
}
//Available product flavors
productFlavors {
customerA{
customer = "a"
}
customerB{
customer = "b"
}
customerC{
customer = "c"
}
}
}
Однако позже, когда я получаю доступ к определенному свойству проекта "клиент" (значение которого задано в цвете продукта, которое я сейчас создаю) в одной из моих задач сборки, оно всегда имеет значение "c", хотя iam (в этом случае клиент недвижимости должен быть "а", а не "с" ). Например, я выполняю следующую задачу позже:
preBuild << {
println "Building customer: " + customer
}
и он всегда печатает:
Клиент здания: c
Итак, я предполагаю, что происходит переписывание? Возможно, связано с фазой выполнения VS-конфигурации конфигурации? Не знаю, как и почему, поэтому любая помощь будет принята с благодарностью.
UPDATE. В качестве альтернативы, это уже позволило бы мне определить название продукта (без прикрепленного к нему типа типа сборки) и типа сборки (опять же: без названия аромата продукта к нему) во время фазы выполнения сборки Gradle.
Учитывая приведенную выше конфигурацию, ожидаемые названия аромата продукта будут: customerA, customerB и customerC.
Ответы
Ответ 1
Во время фазы оценки Gradle выполняет весь код в вашем блоке android
; он не просто выполняет код, относящийся к вкусам, которые вы хотите скомпилировать. Фактически, на этапе оценки он даже не знает, что такое ваши вкусы; он должен оценить это, чтобы узнать.
Итак, все три строки customer = "a"
, customer = "b"
и customer = "c"
будут выполнены.
Это одна из тонких вещей о Gradle, которые делают ее немного трудной для изучения.
Итак, я объяснил, почему ваш код работает не так, как вы ожидаете, но этот ответ неполный, потому что я не много говорил о том, что делать, чтобы он работал правильно, но трудно сказать, что потому что я не уверен, чего вы пытаетесь достичь. В общем, я могу сказать, что вам следует подумать о том, чтобы попытаться выполнить то, что вы хотите, используя пользовательские задачи, и настроить внутризадачные зависимости, чтобы убедиться, что все будет выполнено в правильном порядке. Получение с Android Gradle сборками заключается в том, что даже эти задачи не определяются до этапа оценки (он не может знать, какие задачи ему нужно для создания всех ваших вкусов до тех пор, пока он не оценит файл сборки и не знает, что такое эти вкусы) поэтому следите за тем, как подключаться к задачам сборки Android Gradle - вам нужно настроить свои задачи в конце этапа оценки после того, как плагин Android сделал свою работу.
Ответ 2
Большое спасибо Скотту Барте за его предложения и объяснение, почему мое решение не сработало (что также заставило меня пересмотреть несколько вещей). Я в основном придумал разные способы достижения того, что мне нужно.
Если вам не нужно ничего делать, просто организуя дерево Android-ресурсов на основе типов и ароматов сборки (то есть через соглашение), я бы рекомендовал вариант 2. Хотя я сохранил вариант 1 для справочных целей, так как он охватывает интересный объект расширения свойства продуктаFlavor.
- Пользовательский вариант на основе свойств: Product Flavors позволяет вам определять пользовательские свойства и, таким образом, расширять productFlavor. Пример приведен здесь Xavier Ducrohet: fooobar.com/questions/275711/...
Я предлагаю очень простой и похожий пример, как указано выше, хотя в моем случае мне понадобилось свойство String, а не логическое.
// This class will be used to create our custom property
class StringExtension {
String value
StringExtension (String value) {
this.value = value
}
public void setValue(String value) {
this.value = value
}
public String getValue() {
return value
}
}
android {
// Add our new property to each product flavor upon creation
productFlavors.whenObjectAdded { flavor ->
//I am suspecting the last argument is the default value
flavor.extensions.create("myProperty", StringExtension , '')
}
// then we can set the value on the extension of any flavor object
productFlavors {
customerA{
myProperty.value 'customerA'
}
customerB{
myProperty.value 'customerB'
}
}
}
//Adds a custom action to the preBuild task
preBuild << {
//Iterate over all application variants. We name our application variant object "variant" as indicated by "variant ->"
android.applicationVariants.all { variant ->
//Here we can iterate over the flavors of our variant, well call the flavor "flavor" as indicated by "flavor ->"
variant.productFlavors.each { flavor ->
//Access our custom property "customerName"
println "Building customer" + flavor.customerName.value
}
}
}
Я понял, что это было совершенно не нужно, потому что все, что я хотел, было именем моего вкуса (без типа сборки в нем), и как только я нашел свойство, которое дает мне название моего вкуса, я смог для изменения всего вышеуказанного кода следующим образом:
-
Просто используйте название своего вкуса в качестве имени клиента, обратившись к уже существующему вкусу продукта, названному "имя".
android {
productFlavors {
customerA{
}
customerB{
}
}
}
//Adds a custom action to the preBuild task
preBuild << {
//Iterate over all application variants. We name our application variant object "variant" as indicated by "variant ->"
android.applicationVariants.all { variant ->
//Here we can iterate over the flavors of our variant, well call the flavor "flavor" as indicated by "flavor ->"
variant.productFlavors.each { flavor ->
//Access our product flavor name
println "Building customer" + flavor.name
}
}
}
Вышеизложенное также имеет смысл, потому что моя структура каталогов для ресурсов Android названа в честь фактических вкусов.
Последнее также привело меня к моему окончательному решению по оригинальному вопросу:
- Подход к каталогу Ressource
Цель заключалась в том, чтобы изменить файл в папке xml каждого клиента на основе того, является ли это выпуском или сборкой отладки. Это может быть достигнуто с помощью соответствующей структуры папок. Исходя из первоначального вопроса, у нас есть 3 клиента, и каждый клиент имеет отладочную и выпускную сборку. Вышеупомянутые xml файлы отличаются для каждого клиента и типа сборки. Следовательно, следующая структура каталогов:
src/
- customerA
//Contains all relevant resource files specific to customer A
- customerB
//Contains all relevant resource files specific to customer B
- customerC
//Contains all relevant resource files specific to customer C
- customerADebug
//Contains debug server-settings file for customer A
- customerBDebug
//Contains debug server-settings file for customer B
- customerCDebug
//Contains debug server-settings file for customer C
- customerARelease
//Contains release server-settings file for customer A
- customerBRelease
//Contains release server-settings file for customer B
- customerCRelease
//Contains release server-settings file for customer C
Таким образом, основное содержание каждого аромата продукта было в папке с тем же названием, что и аромат (customerA, customerB и т.д. см. первую часть вышеприведенного фрагмента). Теперь этот один файл, который отличается от того, была ли это отладочной или релизной сборкой для каждого клиента, помещается в соответствующие папки, такие как customerADebug → содержит файл с настройками сервера для режима отладки и т.д.
И когда вы создаете customerA, например, правильный файл будет выбран, если вы будете строить отладочную или выпускную сборку.
Чтобы ответить на часть сообщения UPDATE моего сообщения:
Имя вкуса продукта (без buildType):
flavor.name(где аромат - продуктFlavor)
Ответ 3
Следующее работало для меня, чтобы добавить пользовательские свойства к вкусам продукта:
android {
// ...defaultConfig...
productFlavors.whenObjectAdded { flavor ->
// Add the property 'myCustomProperty' to each product flavor and set the default value to 'customPropertyValue'
flavor.ext.set('myCustomProperty', 'customPropertyValue')
}
productFlavors {
flavor1 {
}
flavor2 {
myCustomProperty = 'alternateValue'
}
}
}
flavor1
имеет значение по умолчанию для настраиваемого свойства, а flavor2
имеет переопределенное значение.
Вот пример доступа к пользовательскому свойству:
applicationVariants.all { variant ->
// Get the 'myCustomProperty' property from the variant productFlavor (it a list, but there should only be one)
def customProp = variant.productFlavors*.myCustomProperty[0]
}
Я предполагаю, что то же самое можно было бы сделать для добавления настраиваемых свойств для создания типов, но я не тестировал это.