para - configurar gradle android studio
Generación dinámica de productFlavors y sourceSets utilizando una lista de nombres(con propiedades) en un archivo CSV/TXT (2)
Esta pregunta en la continuación de mi otra pregunta , que quiero mejorar aún más.
Puedo agrupar sabores (que tienen una configuración común) en sourceSets
con el siguiente código:
(Lo obtuve de un genio en la pregunta vinculada más 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 extraerse de cualquiera de los siguientes:
- Un archivo XML sobre el cual puedo iterar para obtener todos los sabores (que pondré allí)
- Un archivo CSV sobre el cual puedo iterar y obtener valores.
- Una clase personalizada que puedo escribir en un archivo separado y obtener 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 (una de las anteriores):
- ID de la aplicación (que voy a
productFlavors
paraproductFlavors
) - Id. del bloque de anuncios (dos por sabor)
- algunos otros valores personalizados como categoría, etc.
PORPOSE: Quiero escribir una pieza genérica de código para iterar y crear dinámicamente los sourceSets
y los sourceSets
. He generalizado sourceSets
a casi 90% y un bloque ahora es suficiente para todos los sabores.
Se ve 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 con productFlavors
como se indicó anteriormente.
STUCK AT: obteniendo la lista [flavor2, flavor4]
en el código anterior de una fuente externa (junto con algunos campos adicionales por sabor, como se indica más arriba).
Veo métodos como
productFlavors.add()
productFlavors.addAll()
pero no estoy muy seguro de cómo usar estos. Como los métodos están disponibles, estoy seguro de que es posible hacer lo que intento.
¿Alguien ha hecho esto y tiene algunos consejos?
Finalmente lo hice funcionar de esta manera:
Creé una clase personalizada MyFlavor
dentro de build.gradle
y agregué cada sabor del archivo csv a una 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);
}
A continuación, se repitió sobre ArrayList
para crear dinámicamente los sourceSets
y los 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 deshacerme de miles de líneas de código (porque tengo muchos sabores) y reducirlo a estas 10 líneas que ves aquí.
Para leer archivos XML y CSV, tiene todo el poder de Groovy en sus manos. Todos los scripts Gradle están escritos en Groovy. .each { Type var ->
es parte de eso también. Primer resultado: https://.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 finalización del código, puede reemplazar cualquier tipo de variable con def
y aún así funcionará. Estos tipos son solo lo que se usa cuando estás haciendo la configuración regular de android { ... }
. Los tipos internos pueden cambiar en cualquier momento, de hecho, estoy trabajando con 1.5; es posible que ya hayan cambiado en 2.0.