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.

  1. Опция на основе пользовательских свойств: 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

            }
        }
    }

Я понял, что все вышеперечисленное совершенно не нужно, потому что все, что мне нужно, - это имя моего аромата (без типа сборки в нем), и как только я нашел свойство, которое дает мне имя моего аромата, я смог изменить все приведенного выше кода следующим образом:

  1. Просто используйте имя вашего аромата в качестве имени клиента, получив доступ к уже существующему свойству аромата продукта под названием "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 названа в честь реальных версий.

Последнее также привело меня к окончательному решению исходного вопроса:

  1. Подход на основе каталога ресурсов

Намерение состояло в том, чтобы изменить файл в папке 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]
}

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

Другие вопросы по тегам