Generación dinámica de productFlavors y sourceSets usando una lista de nombres (con propiedades) en un archivo CSV / TXT

Esta pregunta en la continuación de mi otra pregunta , que quiero mejorar aún más.

Puedo agrupar los sabores (que tienen configuración común) bajo sourceSets con el código siguiente:

(lo consiguió de un genio en la pregunta relacionada arriba)

 import com.android.build.gradle.api.AndroidSourceSet android { sourceSets { [flavor2, flavor4].each { AndroidSourceSet ss -> ss.assets.srcDirs = ['repo-assets/flavor2'] ss.res.srcDirs = ['repo-res/flavor2'] } } } 

Ahora, me preguntaba si la lista [flavor2, flavor4] podría ser sacada de cualquiera de los siguientes:

  • Un archivo XML sobre el que puedo iterar para obtener todos los sabores (que voy a poner allí)
  • Un archivo CSV sobre el que puedo iterar y recuperar valores.
  • Una clase personalizada que puedo escribir en un archivo independiente y buscar datos de miembros estáticos en la clase.

Además del nombre del sabor, tengo la intención de almacenar lo siguiente en la fuente externa (uno de los anteriores):

  • identificación de la aplicación (que voy a tirar a productFlavors )
  • ID de unidad de anuncio (dos por sabor)
  • algunos otros valores personalizados como categoría etc.

PORPOSE: Quiero escribir un código genérico para iterar y crear dinámicamente los sourceSets y los sourceSets . Tengo generalizado sourceSets a casi el 90% y un bloque es ahora suficiente para todos los sabores.

Parece algo como esto ahora:

 sourceSets { [flavor1, flavor2, flavor3 ...].each { AndroidSourceSet ss -> ss.assets.srcDirs = ['repo-assets/' + ss.name.split('_')[0]] ss.res.srcDirs = ['repo-mipmap/' + ss.name.split('_')[0] , 'repo-strings/' + ss.name] } } 

También quiero hacer lo mismo para productFlavors como se sugirió anteriormente.

STUCK AT: obtener la lista [flavor2, flavor4] en el código anterior de una fuente externa (junto con algunos campos adicionales por sabor como se menciona anteriormente).

Veo métodos como

 productFlavors.add() productFlavors.addAll() 

pero no estoy muy seguro acerca de cómo ir sobre el uso de estos. Como los métodos están disponibles, estoy seguro de que es posible hacer lo que estoy tratando de hacer.

¿Alguien ha hecho esto y tiene algunas indicaciones?

Finalmente conseguí que funcionara de esta manera:

Creó una clase personalizada MyFlavor dentro de build.gradle y agregó cada sabor del archivo csv a un ArrayList de MyFlavor

 class MyFlavor { public String flavorname; public String basename; public String appid; public String bannerid; public String interstitialid; public String category; } def ArrayList<MyFlavor> myFlavors = new ArrayList<>(); new File('app/flavors.csv').eachLine { String[] values = "$it".split(','); MyFlavor f = new MyFlavor(); f.flavorname = values[0]; f.basename = values[0].split('_')[0]; f.appid = values[1]; f.bannerid = values[2]; f.interstitialid = values[3]; if(values[0].contains('_')) f.category= "state" else f.category = "country"; myFlavors.add(f); } 

Luego iteró sobre el ArrayList para crear dinámicamente el sourceSets y el sourceSets siguiente manera:

 productFlavors { myFlavors.each { MyFlavor f -> "$f.flavorname" { applicationId = "$f.appid" buildConfigField 'String', 'BANNER_ID', "\"" + "$f.bannerid" + "\"" buildConfigField 'String', 'INTERSTITIAL_ID', "\"" + "$f.interstitialid" + "\"" buildConfigField 'String', 'CATEGORY', "\"" + "$f.category" + "\"" } } } sourceSets { myFlavors.each { MyFlavor f -> "$f.flavorname" { assets.srcDirs = ['repo-assets/' + "$f.basename"] res.srcDirs = ['repo-mipmap/' + "$f.basename" , 'repo-strings/' + "$f.flavorname"] } } } 

Espero que esto ayude a alguien. Tuve éxito en deshacerse de miles de líneas de código (porque tengo un montón de sabores) y llevarlo a estos 10s de líneas que ves aquí.

Para leer archivos XML y CSV tiene toda la potencia de Groovy en su mano. Todos los scripts de Gradle están destinados a ser escritos en Groovy. .each { Type var -> es parte de eso también. Primer resultado: https://stackoverflow.com/a/2622965/253468 :

Dado un archivo CSV como este:

 #name,appId,ad1,ad2,category flavor1,app.id.flavor1,adunit1324523,adunit2234234,messenger flavor2,app.id.flavor2,adunit42346451,adunit4562,editor flavor3,app.id.flavor2.gpe,adunit345351,adunit3545342,messenger 

Groovy puede cargarlo así:

 import com.android.build.gradle.BaseExtension import com.android.build.gradle.api.AndroidSourceSet import com.android.build.gradle.internal.dsl.ProductFlavor // TODO get a real CSV parser, this is hacky new File("flavors.csv").splitEachLine(",") { fields -> if (fields[0].charAt(0) == '#' as char) return; // skip comments def flavorName = fields[0]; def baseName = flavorName.split('_')[0]; def appId = fields[1]; BaseExtension android = project.android // project.getExtensions().getByName('android'); // productFlavors is declared as Collection, but it is a NamedDomainObjectContainer // if [flavorName] doesn't work, try .maybeCreate(flavorName) or .create(flavorName) ProductFlavor flavor = android.productFlavors[flavorName]; AndroidSourceSet sourceSet = android.sourceSets[flavorName]; flavor.applicationId = appId; sourceSet.res.srcDirs = [] // clear sourceSet.res.srcDir 'repo-mipmap/' + baseName sourceSet.res.srcDir 'repo-strings/' + flavorName } 

Los tipos se importan para la legibilidad y la terminación del código, puede reemplazar cualquier tipo de variable con def y seguirá funcionando. Estos tipos son exactamente lo que se utiliza cuando se está realizando la configuración normal de android { ... } . Los tipos internos pueden cambiar en cualquier momento, de hecho estoy trabajando con 1.5 que ya pueden haber cambiado en 2.0.

  • La ejecución falló para la tarea ': app: transformClassesWithDexForDebug' al implementar Google inicie sesión en Android
  • Android Studio obtiene una advertencia obsoleta incluso con @SuppressWarnings ("deprecation")
  • Acelerar gradle build en la aplicación multidex
  • Heredar JavaDoc desde Android SDK con Gradle
  • ¿Es posible utilizar Java 8 para el desarrollo de Android?
  • AndroidStudio (0.8.9 Mac) No se pudo sincronizar el nuevo proyecto Gradle
  • Define LOCAL_SRC_FILES en ndk {} DSL
  • Error: Se requiere que Jack admita características de lenguaje java 8
  • Cómo cambiar / cambiar testInstrumentationRunner dinámicamente con gradle
  • Error al instalar apk - analizar el paquete
  • BuildConfigField VS campo de clase? Recurso resValue VS
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.