Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


Android Studio: Gradle Product Flavors: Definir propiedades personalizadas

Estoy construyendo diferentes sabores de productos de una aplicación para Android en Gradle (Android Studio).

Por lo tanto definí los siguientes sabores de producto:

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" } } } 

Sin embargo, más adelante, cuando accedo a la propiedad de proyecto definida "cliente" (cuyo valor se establece en el sabor del producto que estoy construyendo actualmente) en una de mis tareas de compilación, siempre tiene el valor "c" En cuyo caso el cliente de la propiedad debe ser "a" en lugar de "c"). Por ejemplo, ejecuto la siguiente tarea más adelante:

 preBuild << { println "Building customer: " + customer } 

Y siempre se imprime:

Edificio cliente: c

Así que estoy adivinando hay algo de sobrescribir sucediendo? Posiblemente relacionado con la fase de ejecución de la configuración VS? No sure cómo / porqué sin embargo, así que cualquier ayuda es apreciada grandemente.

ACTUALIZACIÓN : Alternativamente, ya me llevaría más lejos determinar el nombre del sabor del producto (sin el nombre del tipo de construcción adjunto) y el tipo de construcción (de nuevo: sin el nombre del sabor del producto adjunto a él) durante la fase de ejecución de la compilación gradle .

Teniendo en cuenta la configuración anterior, los nombres de sabor del producto esperado serían: customerA, customerB y customerC.

  • No se puede iniciar la aplicación en Android Studio 2.0 Vista previa
  • Gradle omite la tarea X ya que no tiene archivos de origen
  • Android Studio 3.0 Error. Migrar configuraciones de dependencia para módulos locales
  • Proguard Nota para la clase desconocida 'Objeto' con Android Studio y Gradle
  • Android Studio no puede iniciar la aplicación después de la compilación cuando se utiliza una marca de tiempo en el nombre
  • Cómo excluir el módulo de todas las dependencias, pero dejar la declaración explícita Gradle
  • Gradle - equivalente de test {} bloque de configuración para android
  • Los archivos Jar en la carpeta libs no se utilizan en la compilación de Android Gradle
  • 3 Solutions collect form web for “Android Studio: Gradle Product Flavors: Definir propiedades personalizadas”

    Durante la fase de evaluación, Gradle ejecuta todo el código en su bloque android ; No sólo ejecuta el código relevante para los sabores que desea compilar. De hecho, durante la fase de evaluación, ni siquiera sabe realmente cuáles son sus sabores; Tiene que evaluar eso para averiguarlo.

    Así que las tres de sus líneas customer = "a" , customer = "b" , y customer = "c" se ejecutarán.

    Esta es una de las cosas sutiles acerca de Gradle que hacen que sea un poco difícil de aprender.

    Así que he explicado por qué su código no funciona de la manera que usted espera, pero esta respuesta es incompleta porque no he dicho mucho acerca de qué hacer para que funcione bien, pero es difícil decir qué hacer porque No estoy seguro de lo que estás tratando de lograr. En general, puedo decir que deberías pensar en intentar lograr lo que quieres usando tareas definidas por el usuario y configurar dependencias dentro de la tarea para asegurarte de que las cosas se ejecuten en el orden correcto. Un gotcha con Android Gradle construye es que incluso esas tareas no se definen hasta la fase de evaluación (no puede saber qué tareas que necesita para construir todos sus sabores hasta que se evalúa el archivo de construcción y sabe lo que esos sabores son), por lo que Algunos SO sleuthing para ver cómo conectar las cosas a las tareas de compilación de Android Gradle – usted tiene que configurar sus tareas al final de la fase de evaluación después de que el complemento de Android ha hecho su cosa.

    Muchas gracias a Scott Barta, por sus sugerencias y por explicar, por qué mi solución no funcionó (lo que también me hizo reconsiderar algunas cosas). Básicamente, surgió diferentes maneras de lograr lo que necesitaba.

    A menos que lo que necesita hacer no se puede lograr simplemente organizando su árbol de recursos de Android basado en tipos de construcción y sabores (es decir, a través de la convención), entonces yo recomendaría la opción 2. Aunque mantuve la opción 1 para fines de referencia ya que cubre la Tema interesante de la extensión de la propiedad productFlavor.

    1. Opción basada en propiedades personalizadas: Flavors del producto le permite definir propiedades personalizadas y extender así un productFlavor. Un ejemplo es proporcionado aquí por Xavier Ducrohet: https://stackoverflow.com/a/17708357/1041533

    Voy a ofrecer un ejemplo muy simple y similar como se proporcionó anteriormente, aunque en mi caso, necesitaba una propiedad String, en lugar de un booleano.

      // 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 } } } 

    Me di cuenta, que lo anterior era totalmente innecesario, porque todo lo que quería era el nombre de mi sabor (sin el tipo de construcción en él) y una vez que encontré la propiedad que me da el nombre de mi sabor, pude cambiar todo Del código anterior como sigue:

    1. Simplemente utilice el nombre de su sabor como nombre del cliente accediendo a la propiedad de sabor ya existente denominada "nombre".

       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 } } } 

    Lo anterior tiene mucho más sentido también, porque mi estructura de directorios para Recursos de Android lleva el nombre de los sabores reales.

    Este último también me llevó a mi solución final para la pregunta original:

    1. Enfoque basado en directorio de recursos

    La intención era modificar un archivo en la carpeta xml de cada cliente basado en si se trata de una versión o una compilación de depuración. Esto se puede lograr mediante una estructura de carpetas correspondiente. Sobre la base de la pregunta original tenemos 3 clientes, y cada cliente tiene una depuración y una versión de liberación. Los archivos xml mencionados anteriormente son diferentes para cada cliente y tipo de compilación. De ahí la siguiente estructura de directorios:

     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 

    Así que el contenido principal de cada sabor del producto estaba en la carpeta con el mismo nombre que el sabor (customerA, customerB etc. vea la primera parte del fragmento anterior). Ahora este archivo, que diferente basado en si se trataba de una compilación de depuración o liberación para cada cliente se pone en las carpetas apropiadas, tales como customerADebug -> contiene el archivo con la configuración del servidor para el modo de depuración, etc

    Y cuando usted construye customerA por ejemplo el archivo correcto será elegido si usted construye una compilación de la depuración o de la lanzadera.

    Para responder a la parte de UPDATE de mi publicación:

    Nombre del sabor del producto (sin buildType):

    Flavor.name (donde el sabor es un productFlavor)

    Lo siguiente funcionó para mí para agregar propiedades personalizadas a los sabores del producto:

     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 tiene el valor predeterminado para la propiedad personalizada, mientras que flavor2 tiene el valor anulado.

    A continuación, se muestra un ejemplo de cómo acceder a la propiedad personalizada:

     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] } 

    Supongo que lo mismo podría hacerse para agregar propiedades personalizadas a los tipos de construcción, pero no he probado esto.

    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.