Android Studio: варианты продукта Gradle: определение пользовательских свойств
Я создаю различные версии продуктов для 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"
}
}
}
Однако позже, когда я получаю доступ к определенному свойству проекта "customer" (значение которого задается во вкусе продукта, который я сейчас строю) в одной из моих задач по сборке, оно всегда имеет значение "c", даже если я собираю customerA (в этом случае клиент недвижимости должен быть "а", а не "с"). Например, позже я выполняю следующую задачу:
preBuild << {
println "Building customer: " + customer
}
и это всегда печатает:
Заказчик здания: c
Я предполагаю, что происходит перезапись? Возможно, связано с конфигурацией VS фазы выполнения? Не уверен, как / почему, хотя, поэтому любая помощь будет принята с благодарностью.
ОБНОВЛЕНИЕ: В качестве альтернативы, мне уже потребовалось бы дополнительно определить имя продукта (без имени типа сборки, к которому он привязан) и тип сборки (опять же: без имени продукта, добавленного к нему) во время фазы сборки Gradle.,
Учитывая вышеупомянутую конфигурацию, ожидаемые названия продукта будут следующими: customerA, customerB и customerC.
3 ответа
На этапе оценки Gradle выполняет весь код в вашем android
блок; он не просто выполняет код, относящийся к вариантам, которые вы хотите скомпилировать. На самом деле, на этапе оценки он даже не знает, каковы ваши вкусы; это должно оценить это, чтобы узнать.
Так что все три твои строки customer = "a"
, customer = "b"
, а также customer = "c"
будет казнен.
Это одна из тонких вещей в Gradle, которые немного затрудняют обучение.
Итак, я объяснил, почему ваш код работает не так, как вы ожидаете, но этот ответ неполон, потому что я не очень много говорил о том, что нужно сделать, чтобы он работал правильно, но сложно сказать, что делать, потому что я Я не уверен, что вы пытаетесь достичь. В целом, я могу сказать, что вам следует подумать о том, чтобы попытаться выполнить то, что вы хотите, с помощью пользовательских задач и настроить внутризадачные зависимости, чтобы убедиться, что все выполняется в правильном порядке. Принцип работы со сборками Android Gradle заключается в том, что даже эти задачи не определяются до фазы оценки (он не может знать, какие задачи ему нужны для сборки всех ваших вариантов, пока не оценит файл сборки и не узнает, что это за версии), поэтому немного ТАК, чтобы увидеть, как подключить вещи к задачам сборки Android Gradle - вы должны настроить свои задачи в конце фазы оценки после того, как плагин Android выполнил свою задачу.
Большое спасибо Скотту Барте за его предложения и за объяснение, почему мое решение не сработало (что также заставило меня пересмотреть несколько вещей). Я в основном придумал разные способы выполнить то, что мне было нужно.
Если то, что вам нужно сделать, не может быть достигнуто простой организацией дерева ресурсов Android на основе типов сборки и разновидностей (то есть с помощью соглашения), то я бы порекомендовал вариант 2. Хотя я сохранил вариант 1 для справочных целей, поскольку он охватывает Интересная тема расширения свойства productFlavor.
- Опция на основе пользовательских свойств: Product Flavors позволяет вам определять пользовательские свойства и, следовательно, расширять productFlavor. Пример приведен здесь Ксавье Дюкроэ: /questions/22251148/gradle-android-plugin-dobavit-sobstvennyij-atribut-aromata/22251152#22251152
Я предложу очень простой и похожий пример, как указано выше, хотя в моем случае мне нужно было свойство 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
}
}
}
Я понял, что все вышеперечисленное совершенно не нужно, потому что все, что мне нужно, - это имя моего аромата (без типа сборки в нем), и как только я нашел свойство, которое дает мне имя моего аромата, я смог изменить все приведенного выше кода следующим образом:
Просто используйте имя вашего аромата в качестве имени клиента, получив доступ к уже существующему свойству аромата продукта под названием "name".
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 названа в честь реальных версий.
Последнее также привело меня к окончательному решению исходного вопроса:
- Подход на основе каталога ресурсов
Намерение состояло в том, чтобы изменить файл в папке 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 будет выбран правильный файл, если вы создадите отладочную или выпускную версию.
Чтобы ответить на часть моего сообщения ОБНОВЛЕНИЕ:
Название продукта (без buildType):
flavor.Name (где аромат является productFlavor)
Следующее сработало для меня, чтобы добавить пользовательские свойства к вкусу продукта:
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's productFlavor (it's a list, but there should only be one)
def customProp = variant.productFlavors*.myCustomProperty[0]
}
Я предполагаю, что то же самое можно сделать, чтобы добавить пользовательские свойства для типов сборки, но я не проверял это.