I have implemented Flavors in Android Studio and am now trying to place each Flavor in it's own directory, with its own unique name - sadly with a name different, in some cases, than the flavor name. :(
We have tools depending on it being the same, so if I can pull that off in gradle, all the better.
I have a sample that is using the version name suffix value as the directory name and that works. But what I would like to do is specify a value somewhere in the flavor config that would be used, however I find that when you set a property with the same name the last one wins - rather than each being used as specified in the config.
So, for example, lets say I have two Flavors : Jimbo and Randolph. However I want to place the Jimbo.apk in the "jimmy" folder and the Randolph.apk in the "randy" folder. How can I specify a value (directory) for each that will be picked up and used to store the generated APK? To add to the complexity I am renaming the APK current in the applicationVariants.all
.
In the code below I am looking to somehow replace the versionNameSuffix
with a variable I can somehow specify.
Here is what I have:
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion '25.0.2'
defaultConfig {
applicationId "com.mycompany.default"
minSdkVersion 14
targetSdkVersion 23
versionCode 11
versionName "1.0.11"
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
signingConfig signingConfigs.config
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
productFlavors {
Randolph {
applicationId 'com.mycompany.randy'
versionNameSuffix 'randy'
}
Jimbo {
applicationId 'com.mycompany.jimmy'
versionNameSuffix 'jimmy'
}
}
applicationVariants.all { variant ->
variant.outputs.each { output ->
def path = "C:/AndroidBuilds/MyCompany.Build/" + variant.productFlavors[0].versionNameSuffix + "/"
logger.error("Path = " + path)
def SEP = "-"
def flavor = variant.productFlavors[0].name
def version = variant.versionCode
def newApkName = path + version + SEP + flavor
logger.error("newApkName = " + newApkName)
output.outputFile = new File(newApkName + ".apk")
}
}
}
dependencies {
}
}
UPDATE
Per the question of using a task, I tried this approach but the problem of setting the directory remains - using a property (archivesBaseName
) the last one set is used so all the files are copied to that directory. Here is a sample of that. Since I have upwards of 100 flavors to create I want each sent to it's own directory and config driven. Here is what I tried:
productFlavors {
Randolph {
applicationId 'com.mycompany.randy'
setProperty("archivesBaseName", "randy")
}
Jimbo {
applicationId 'com.mycompany.jimmy'
setProperty("archivesBaseName", "jimmy")
}
}
applicationVariants.all { variant ->
variant.outputs.each { output ->
def path = "C:/AndroidBuilds/MyCompany.Build/" + archivesBaseName + "/"
logger.error("Path = " + path)
def SEP = "-"
def flavor = variant.productFlavors[0].name
def version = variant.versionCode
def newApkName = path + version + SEP + flavor
logger.error("newApkName = " + newApkName)
output.outputFile = new File(newApkName + ".apk")
def copyApkTask = tasks.create(name: "copy" + variant.name + "Apk") {
copy {
def newName = newApkName + ".apk"
logger.error("from = " + newName)
logger.error("into = " + path)
logger.error("old name = " + version + SEP + flavor + ".apk")
logger.error("new name = " + flavor + ".apk")
from newName
into path
rename (version + SEP + flavor + ".apk", flavor + ".apk")
}
}
copyApkTask.mustRunAfter variant.assemble
}
}
In the example above I added a task to additionally copy the APK with different name to a flavor specific directory. All the APKs end up copied to the last specified `archivesBaseName, which is "jimmy". So last one wins. I was hoping it would act like a variable. I would prefer not to have to have 100+ if statements to do this and would prefer to do this in Gradle. I am starting to wonder if I will need to make an external Ant call to make this all work.
Ok, in the end this specific link REALLY helped on the variable assignment which is what I needed:
Android Studio: Gradle Product Flavors: Define custom properties
Basically you can assign variables within the flavor. Here is what I ended up doing, which actually went a bit further than when I started, since now I can use the Flavor as the APK name or specify one (I know, it is messed up, but history can be that way!):
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion '25.0.2'
defaultConfig {
applicationId "com.mycompany.default"
minSdkVersion 14
targetSdkVersion 23
versionCode 11
versionName "1.0.11"
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
signingConfig signingConfigs.config
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
productFlavors.whenObjectAdded { flavor ->
// Add the property 'myCustomProperty' to each product flavor and set the default value to 'customPropertyValue'
flavor.ext.set('directoryPath', '')
flavor.ext.set('apkName', '')
}
productFlavors {
Randolph {
applicationId 'com.mycompany.randy'
directoryPath = 'randy'
apkName = 'RandyBoy' // If you want the APK name be different than the flavor
}
Jimbo {
applicationId 'com.mycompany.jimmy'
directoryPath = 'jimmy'
}
}
applicationVariants.all { variant ->
variant.outputs.each { output ->
def path = "C:/AndroidBuilds/MyCompany.Build/" + variant.productFlavors[0].directoryPath + "/"
def SEP = "-"
def apkName = variant.productFlavors[0].apkName
def flavor = variant.productFlavors[0].name
if (apkName != '')
flavor = apkName;
def version = variant.versionCode
def newApkName = path + version + SEP + flavor
logger.error("newApkName = " + newApkName)
output.outputFile = new File(newApkName + ".apk")
}
}
}
dependencies {
}
}
So productFlavors.whenObjectAdded
sets the default values for each flavor, which are then overridden by each flavor. In the applicationVariants.all
a check is made to see if the apkName
has been overridden, if so it uses it, otherwise it uses the flavor name (and the version code is tacked in front of it). The directory is set directly by the flavor.
Big thanks to @lionscribe. He got me thinking this thru more clearly.