Exclude specific build variants - android

I have the two default build types: debug / release and a couple of flavors: prod / dev.
Now I want to exclude the build variant dev-release, but keep all other possible combinations. Is there a way to achieve this?

Variant filter
Use the variantFilter of the gradle android plugin to mark certain combinations as ignored. Here is an example from the official documentation that works with flavor dimensions and shows how it can be used:
android {
...
buildTypes {...}
flavorDimensions "api", "mode"
productFlavors {
demo {...}
full {...}
minApi24 {...}
minApi23 {...}
minApi21 {...}
}
variantFilter { variant ->
def names = variant.flavors*.name
// To check for a certain build type, use variant.buildType.name == "<buildType>"
if (names.contains("minApi21") && names.contains("demo")) {
// Gradle ignores any variants that satisfy the conditions above.
setIgnore(true)
}
}
}
As the comment says, you can also check the buildType like so:
android {
variantFilter { variant ->
def names = variant.flavors*.name
if(variant.buildType.name == 'release' && names.contains("myforbiddenflavor")) {
setIgnore(true)
}
}
}

Using variant filters like others I found it was easiest to do this by comparing the variant name against a list of variants that I want to keep.
So in my app/build.gradle file I have something like:
android {
variantFilter { variant ->
def needed = variant.name in [
'stagingQuickDebug', // for development
'stagingFullDebug', // for debugging all configurations
'stagingFullCandidate', // for local builds before beta release
'stagingFullRelease', // for beta releases
'productionFullCandidate', // for local builds before going public
'productionFullRelease' // for public releases
]
variant.setIgnore(!needed)
}
buildTypes {
debug {
}
release {
}
candidate.initWith(release)
}
flavorDimensions "server", "build"
productFlavors {
staging {
dimension "server"
buildConfigField "String", "API_URL", '"https://example-preprod.com/"'
}
production {
dimension "server"
buildConfigField "String", "API_URL", '"https://example.com/"'
}
quick {
dimension "build"
minSdkVersion 21
resConfigs("en", "xxhdpi")
}
full {
dimension "build"
}
}
}

When working with flavor dimensions try this one
variantFilter { variant ->
def dim = variant.flavors.collectEntries {
[(it.productFlavor.dimension): it.productFlavor.name]
}
if (dim.dimensionOne == 'paid' && dim.dimensionSecond == 'someVal') {
variant.setIgnore(true);
}
}

If you use flavor dimensions do this:
flavorDimensions "device", "server"
productFlavors {
emulator {
dimension = "device"
}
phone {
dimension = "device"
}
staging {
dimension = "server"
}
production {
dimension = "server"
}
}
android.variantFilter { variant ->
def device = variant.getFlavors().get(0).name
def server = variant.getFlavors().get(1).name
def isRelease = variant.buildType.name.equals('release')
def isDebug = variant.buildType.name.equals('debug')
// Disable emulatorProductionRelease build variant
if (device.equals('emulator') && server.equals('production') && isRelease) {
variant.setIgnore(true)
}
}
It's easy to read and you can target specific build variants.

The solutions here didn't work for me - I run into this post and added this to build.gradle in my app and it solved the issue for me
gradle.taskGraph.whenReady { graph ->
graph.allTasks.findAll { it.name ==~ /.*MyVariant.*/ }*.enabled = false
}
This is what it does - waits for gradle to assemble the complete list of tasks to execute and then it marks all the tasks that match the name pattern as disabled
NOTE
The match is exact - the expression above lets you match any task that has "MyVariant" somewhere in it's name and it is case sensitive

One more simpler way
android.variantFilter { variant ->
if (variant.name == "qaDebug" || variant.name == "devRelease") {
setIgnore(true)
}
}
Or if you place this code inside android {} closure, android. can be omitted
android {
// Please always specify the reason for such filtering
variantFilter { variant ->
if (variant.name == "qaDebug" || variant.name == "devRelease") {
setIgnore(true)
}
}
}
Please always put a meaningful comment for things like this.
UPD: For Kotlin Gradle DSL there is another way:
android {
variantFilter {
ignore = listOf("qaDebug", "devRelease").contains(name)
}
}

The answer of #ade.se didn't work for me. But I've struggled a little, and written this, that works great:
android {
compileSdkVersion 22
buildToolsVersion '20.0.0'
variantFilter { variant ->
if (variant.buildType.name.equals('debug') || variant.buildType.name.equals('release')) {
variant.setIgnore(true);
}
}
defaultConfig {
applicationId "com.fewlaps.quitnow"
minSdkVersion 15
targetSdkVersion 22
versionCode 35
versionName "1.35"
}
The code you have to add is the variantFilter one, but I've pasted a little of the context to make it easy to understand.

See Variant filter answer above.
Old Answer:
It's not possible at the moment, but it's something we want to add. Probably soon.
In the meantime you could disable the assemble task I think. Something like this:
android.applicationVariants.all { variant ->
if ("devRelease".equals(variant.name)) {
variant.assembleTask.enabled = false
}
}

In Gradle's Kotlin DSL (i.e. build.gradle.kts), that would be:
variantFilter {
ignore = buildType.name == "release" &&
flavors.map { it.name }.contains("dev")
}

Related

Set noCompress for only one productFlavor

I'm trying to set androidResources.noCompress for only one product flavor
When I try this
flavorDimensions "ring"
productFlavors {
innerRing {
dimension "ring"
}
outerRing {
dimension "ring"
androidResources {
noCompress 'so'
}
}
}
Both innerRing and outerRing end up with .so files uncompressed. I believe this is due to gradle configuring all the product flavors statically. (see here)
But when I try to change noCompress afterEvaluate
afterEvaluate {
android.applicationVariants.all { variant ->
def ring = variant.getProductFlavors().get(0).name
if (ring == "outerRing") {
println("Don't compress .so files for outer ring build")
android.androidResources.noCompress = ['so']
}
}
}
I get this error
com.android.build.gradle.internal.dsl.AgpDslLockedException:
It is too late to modify internalNoCompressList
It has already been read to configure this project.
Consider either moving this call to be during evaluation,
or using the variant API.
How can I use the variant API to fix this?
Any help is appreciated!
If you are on AGP 7.2
android {
...
androidComponents {
onVariants(selector().all()) { variant ->
if(variant.name.startsWith("outerRing")) {
variant.androidResources.noCompress.add('so')
}
}
}
...
}
If AGP is below 7.2 then from the documentation theoretically the following code should work, but I've had no success with it
android {
...
androidComponents {
onVariants(selector().all()) { variant ->
if(variant.name.startsWith("outerRing")) {
def aaptParams = variant.androidResources.aaptAdditionalParameters
aaptParams.add("-0")
aaptParams.add("so")
}
}
}
...
}

Android Gradle how to set variable depending on current buildType

How to set variable depending on current buildType, I have tried this
String url = "https://dev.myurl.com"
tasks.whenTaskAdded { task ->
if (task.name == 'generateReleaseBuildConfig' || task.name == 'generateDebugBuildConfig') {
if (task.name == 'generateReleaseBuildConfig') {
url = "https://prod.myurl.com"
}
}
}
But no matter if the current buildType is Release or Debug, the tasks generateReleaseBuildConfig and generateDebugBuildConfig are both executed, so I never get the value depending on the current buildType. I specify that this variable is used later in build script and not in Java code.
I have tried several solutions found in SO but none worked for me
This example is from my own application. It's working fine
Put follow code on your app\build.gradle
buildTypes {
debug {
...
buildConfigField "String", "SERVER_URL", '"http://..."'
}
release {
...
buildConfigField "String", "SERVER_URL", '"http://..."'
}
}
IMPORTANT: sync your gradle
And then put follow call on your class
String URL = BuildConfig.SERVER_URL
You can use buildConfigField. It looks like this:
buildConfigField('String', 'API_URL', "\"URL\"")
Place it in gradle, under different buildType. And to get it use this:
BuildConfig.API_URL
That will return this value depends of buildType
UPDATE
Are sure you placed it correctly?
buildTypes {
debug {
//...
buildConfigField('String', 'API_TEST', "\"URL\"")
}
release {
//...
buildConfigField('String', 'API_TEST', "\"URL\"")
}
}

Disable DexGuard only for certain product flavors

I use DexGuard and have 4 product flavors (prod, qa, dev, mock) for 2 build types (release and debug) and I don't enable DexGuard for debug builds and hence I get 4 variants (dexguardProdRelease...dexguardMockRelease) however, I don't want to enable DexGuard for dev and mock flavors.
I learnt about variantFilter that Gradle provides however, I don't know how to use that command in relation to a plugin, DexGuard, in this case.
I was able to solve like so:
//added to filter dexguard for these flavors
variantFilter { variant ->
def names = variant.flavors*.name
if(names.contains("mock") && variant.buildType.name == "release") {
variant.ignore = true
} else if (names.contains("dev") && variant.buildType.name == "release") {
variant.ignore = true
}
}
And now, Gradle doesn't show tasks like dexguardMockRelease or dexguardDevRelease.
I was approaching this problem incorrectly by looking at filtering out DexGuard instead I should be looking at removing certain flavors. Here are the relevant parts of my build.gradle:
apply plugin: 'dexguard'
...
android {
buildTypes {
release {
proguardFile getDefaultDexGuardFile('dexguard-release-aggressive.pro')
proguardFile 'dexguard-project.pro'
}
debug {
//dontshrink, dontoptimize and dontobfuscate are turned off
}
}
productFlavors {
prod {
...
}
qa {
...
}
dev {
...
}
mock {
...
}
}
//added to filter dexguard for these flavors
variantFilter { variant ->
def names = variant.flavors*.name
if(names.contains("mock") && variant.buildType.name == "release") {
variant.ignore = true
} else if (names.contains("dev") && variant.buildType.name ==
"release") {
variant.ignore = true
}
}
}

Is it possible to exclude specific build variant when using flavor Dimensions?

When using Gradle flavorDimensions, is it possible to exclude specific variants?
For example -
android {
...
flavorDimensions "abi", "version"
productFlavors {
freeapp {
flavorDimension "version"
...
}
x86 {
flavorDimension "abi"
...
}
}
the following build variants will be created:
x86-freeapp-debug
x86-freeapp-release
arm-freeapp-debug
arm-freeapp-release
mips-freeapp-debug
mips-freeapp-release
x86-paidapp-debug
x86-paidapp-release
arm-paidapp-debug
arm-paidapp-release
mips-paidapp-debug
mips-paidapp-release
Can "mips-paidapp-release" be manually removed?
Since Gradle 0.9 you can apply a variant filter and iterate over them:
productFlavors {
freeapp {
dimension "version"
}
x86 {
dimension "abi"
}
paidapp {
dimension "mips"
}
}
// Loop variants
android.variantFilter { variant ->
// Loop flavors
variant.getFlavors().each { flavor ->
println variant.buildType.name + " " + flavor.name + " " + flavor.dimension
if (variant.buildType.name.equals('release') &&
flavor.name.equals('paidapp') &&
flavor.dimension.equals('mips')) {
variant.setIgnore(true)
}
}
}
Note: that I changed flavorDimension to dimension because the latter is now the preferred way specify it.
Note2: the above note requires you to use the newer gradle version:
Project/build.gradle should have the following:
dependencies {
classpath 'com.android.tools.build:gradle:1.2.3'
}
while Project/app/build.gradle should have this:
android {
buildToolsVersion "22.0.1"
...
}
This is how I do it:
flavorDimensions "device", "server"
productFlavors {
emulator {
dimension = "device"
}
phone {
dimension = "device"
}
staging {
dimension = "server"
}
production {
dimension = "server"
}
}
android.variantFilter { variant ->
def device = variant.getFlavors().get(0).name
def server = variant.getFlavors().get(1).name
def isRelease = variant.buildType.name.equals('release')
def isDebug = variant.buildType.name.equals('debug')
// Disable emulatorProductionRelease build variant
if (device.equals('emulator') && server.equals('production') && isRelease) {
variant.setIgnore(true)
}
}
I like it because it's easy to read and you can target specific build variants.

Gradle: android.variantFilter cause build fail after upgrade to Gradle 2.2.1

I am working in an Android project which has many flavors, I used this code in build.gradle to set the package name for each flavor:
flavorDimensions "type", "feature"
productFlavors {
abc { flavorDimension "type" }
def { flavorDimension "type" }
ABC { flavorDimension "feature" }
DEF { flavorDimension "feature" }
}
android.variantFilter { variant ->
def flavorString = ""
def flavors = variant.getFlavors()
for (int i = 0; i < flavors.size(); i++) {
flavorString += flavors[i].name;
}
if(flavorString.equalsIgnoreCase("abcABC")) {
variant.getDefaultConfig().applicationId "com.my.app.abc.abc"
}
if(flavorString.equalsIgnoreCase("abcDEF")) {
variant.getDefaultConfig().applicationId "com.my.app.abc.def"
}
if(flavorString.equalsIgnoreCase("defABC")) {
variant.getDefaultConfig().applicationId "com.my.app.def.abc"
}
if(flavorString.equalsIgnoreCase("defDEF")) {
variant.getDefaultConfig().applicationId "com.my.app.def.def"
}
}
Everything was fine until I updated my gradle from 1.10.0 to 2.2.1, the build is failed and I get this error message:
Error:(63, 0) No signature of method: com.android.build.gradle.internal.api.ReadOnlyProductFlavor.applicationId() is applicable for argument types: (java.lang.String) values: [com.hac.apps.megahd.acc]
Possible solutions: getApplicationId()
It seems like the variant.getDefaultConfig().applicationId is working different now. I searched the internet for the document for android.variantFilter but it seems not to be exist.
Anyone can tell me how do I get this code work in gradle 2.2.1? Thanks a lot.
The variantFilter is meant to be used only to allow or disallow builds of certain combinations. The defaultConfig object is shared and read-only. If you want to assign applicationId's to variants, I think you should something more similar to this:
buildTypes {
applicationVariants.all { variant ->
def projectFlavorNames = []
variant.productFlavors.each() { flavor ->
projectFlavorNames.add(flavor.name)
}
project.logger.debug('Application variant ' + variant.name + '. Flavor names list: ' + projectFlavorNames)
if (projectFlavorNames.contains('customer1') && projectFlavorNames.contains('variant1')) {
variant.mergedFlavor.applicationId = 'com.customer1.variant1'
} else if (projectFlavorNames.contains('customer2') && projectFlavorNames.contains('variant2')) {
variant.mergedFlavor.applicationId = 'com.customer2.variant2'
} // else use standard package name
project.logger.debug('Using project name: ' + variant.packageName)
}
// ...
}
From Dynamically generate package name for multi-flavors configuration

Categories

Resources