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:
- Error running react-native run-android --variant = release (La tarea 'installReleaseDebug' no se encuentra en el proyecto raíz 'gnosisapp'.)
- Emitir firmando Android Release Build "No se pudo leer la clave del almacén de claves"
- Gradle falla con "Sobrecarga de método ambiguo para el método java.io.File # <init>"
- Android Gradle - cargar la configuración de firma desde un archivo externo
- No se puede encontrar el módulo con la ruta Gradle. Vinculación a la biblioteca -no especificado en su lugar
(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?
- Android gradle build: ejecutando assembleDebug hace que las tareas de lanzamiento de las dependencias del proyecto sean llamadas
- Cómo generar javadoc para la biblioteca de Android cuando tiene dependencias que también son bibliotecas aar?
- Error de compilación de Gradle después de actualizar Android Studio a 2.2 Vista previa 3
- Android Instant App: ¿Cómo crear módulos direccionables por URL?
- Proceso 'comando' F: \ android-sdk \ build-tools \ 21.1.2 \ aapt.exe terminado con valor de salida no nulo 1
- Diminuir el tiempo de construcción del android studio 2.1
- El módulo de prueba de Android (Gradle Plugin 1.3) no funciona: "debug-classes not found"
- Determine el ABI de la construcción actual en build.gradle
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.
- ¿Es posible ejecutar con seguridad múltiples emuladores de Android en la misma máquina y comunicar con sockets?
- OpenCV Android – No se puede resolver la función JNI correspondiente