resConfigs per build type - android

How can I override the resConfigs per build types? I read that flavors would allow that, but I don't use them. I just want for my debug build another set of supported languges.
Here is what I tried:
buildTypes {
debug {
resConfigs "de", "en" // allow also german in debug builds
}
release {
signingConfig signingConfigs.release
resConfigs "en" // english only releases
}
}
Any simple idea how I can achieve that?

For some reason the individual buildType configs doesn't support the resConfigs command as you point out, but defaultConfig does and then you can use this trick to manipulate it per build type even without flavors configured:
android {
defaultConfig {
resConfigs "en"
}
applicationVariants.all { variant ->
if (variant.buildType.name.equals("debug")) {
variant.mergedFlavor.resourceConfigurations.add("de")
}
}
}

The accepted answer did not work for me. de wasn't succesfully added. Doing everything inside the applicationVariants.all { ... } lambda works though:
android {
defaultConfig {
// No resConfigs here!
// resConfigs "en"
}
applicationVariants.all { variant ->
if (variant.buildType.name.equals("debug")) {
variant.mergedFlavor.resourceConfigurations.add("de")
} else {
variant.mergedFlavor.resourceConfigurations.add("en", "de")
}
}
}
or in Kotlinscript:
android {
defaultConfig {
// no resConfigs here!
}
android.applicationVariants.all {
val resConfigs = when {
name.equals("debug") -> listOf("en", "de")
else -> "en"
}
(mergedFlavor as DefaultProductFlavor).addResourceConfigurations(resConfigs)
}
}

Related

Android productFlavors in gradle-kotlin-dsl

I've experimented gradle-kotlin-dsl in an android project. I'm managed to make it work, but I'm stuck in how to define productFlavors
android {
compileSdkVersion(Config.Android.compileSdkVersion)
buildToolsVersion(Config.Android.buildToolsVersion)
defaultConfig {
minSdkVersion(Config.Android.minSdkVersion)
targetSdkVersion(Config.Android.targetSdkVersion)
versionCode = Config.Version.code
versionName = Config.Version.name
}
buildTypes {
getByName("release") {
isMinifyEnabled = false
}
}
flavorDimensions("dimension")
productFlavors {
//product flavors here
}
}
After some investigation I've got the solution, just use the create method:
productFlavors {
create("flavor1") {
//flavor configurations here
}
create("flavor2") {
//flavor configurations here
}
}
After some investigation I've got the solution, just use the create method, adding here in case someone need it:
productFlavors {
create("flavor1") {
//flavor configurations here
}
create("flavor2") {
//flavor configurations here
}
}

Selective combination of buildTypes and productFlavors

Can I do that?
I have following setup:
buildTypes {
debug {
// ...
}
release {
// ...
}
productFlavors {
flavorDimensions "buildType", "versionType"
fastBuild {
minSdkVersion 21
dimension "buildType"
}
regular {
minSdkVersion setup.minSdk
dimension "buildType"
}
free {
dimension "versionType"
}
pro {
applicationIdSuffix ".premium"
dimension "versionType"
}
}
This combines to 8 build variants. Actually I only need following 3:
fastBuildDebugPro (my test build)
regularBuildFreeRelease
regularBuildProRelease
Can I somehow exclude the other 5 auto generated build variants?

How to set signingConfig for different flavor dimensions?

I'm trying to figure out how can I specify a signingConfig for the individual flavor dimensions generated. I have seen how to do it when using different flavor but not flavor dimensions.
I'm currently applying a different package name for the different flavor dimensions successfully and thought maybe something similar could be done with signingConfig?
> android.applicationVariants.all { variant ->
> def flavorString = variant.getVariantData().getVariantConfiguration().getFlavorName()
> def mergedFlavour = variant.getVariantData().getVariantConfiguration().getMergedFlavor();
>
> if(flavorString.equalsIgnoreCase("amazonFree")) {
> mergedFlavour.setApplicationId("com.test.amazon.free")
> }
> if(flavorString.equalsIgnoreCase("amazonPro")) {
> mergedFlavour.setApplicationId("com.test.amazon.pro")
> }
> if(flavorString.equalsIgnoreCase("googleFree")) {
> mergedFlavour.setApplicationId("com.test.google.free")
> }
> if(flavorString.equalsIgnoreCase("googlePro")) {
> mergedFlavour.setApplicationId("com.test.google.pro")
> } }
My flavor setup
// Special flavor dimensions for different markets and
// versions paid and free.
flavorDimensions 'market', 'version'
productFlavors {
amazon {
flavorDimension 'market'
}
google {
flavorDimension 'market'
}
// Base free version
free {
flavorDimension 'version'
// Need this cause of all the ad libraries we are using :/
defaultConfig.multiDexEnabled true
// For now we sign all free versions with this config
// cause we have no idea how to sign the individual flavor dimensions.
signingConfig signingConfigs.googleFree
}
// Base pro version
pro {
flavorDimension 'version'
// For now we sign all free versions with this config
// cause we have no idea how to sign the individual flavor dimensions.
signingConfig signingConfigs.googlePro
}
}
First of all applicationId can be applied in productFlavors block itself:
productFlavors {
amazonFree {
applicationId 'com.test.amazon.free'
}
amazonPro {
applicationId 'com.test.amazon.pro'
}
googleFree {
applicationId 'com.test.google.free'
}
googlePro {
applicationId 'com.test.google.pro'
}
}
Signing config can be configured per flavor the same way:
productFlavors {
amazonFree {
applicationId 'com.test.amazon.free'
signingConfig signingConfigs.amazonFree
}
amazonPro {
applicationId 'com.test.amazon.pro'
signingConfig signingConfigs.amazonPro
}
googleFree {
applicationId 'com.test.google.free'
signingConfig signingConfigs.googleFree
}
googlePro {
applicationId 'com.test.google.pro'
signingConfig signingConfigs.googlePro
}
}
When you start using flavorDimensions the best solution to set signingConfig for different variants is to use androidComponents block. For example:
androidComponents {
onVariants(selector().all(), { variant ->
if (variant.name == "xxyyzzGmsRelease") {
variant.signingConfig?.setConfig(signingConfigs.play_store)
} else if (variant.name == "xxyyzzHmsRelease") {
variant.signingConfig?.setConfig(signingConfigs.huawei_store)
}
})
}
Tested on Gradle 7.4 and AGP 7.3.1.

Use different VersionCode for Debug/Release android gradle build

I'd like to apply different VersionCode to make apk file.
For debug only fix it to 1, and for release whatever number specified in defaultConfig.
Below code gives mypackage-release-1.apk file as assembleRelease artifact, which is not expected. I expected mypackage-release-10111.apk for that.
why the line debug { defaultConfig.versionCode=1 } affects assembleRelease artifact?
defaultConfig {
versionCode 10111
versionName '2.5.4'
minSdkVersion 10
targetSdkVersion 21
}
signingConfigs {
debug {
project.ext.loadSign = false
defaultConfig.versionCode = 1 // Why this value applied to assembleRelease?
}
release {
project.ext.loadSign = true
applicationVariants.all { variant ->
variant.outputs.each { output ->
def file = output.outputFile
output.outputFile = new File(file.parent, file.name.replace(".apk", "-" + defaultConfig.versionCode + ".apk"))
}
}
}
}
buildTypes {
debug {
signingConfig signingConfigs.debug
}
release {
signingConfig signingConfigs.release
}
}
Here's an updated version:
android {
defaultConfig { ... }
applicationVariants.all { variant ->
if (variant.name == 'debug') {
variant.outputs.each { output ->
output.versionCodeOverride = 1
}
}
}
}
Late on the party...
The entire gradle file evaluated before any task execution, so you are basically changing the default versionCode while declaring debug configs. There is no direct way to reset versionCode from buildType, but the link on the other answer do the trick by declaring a task on build variants.
android {
...
defaultConfig {
...
}
buildTypes {
...
}
applicationVariants.all { variant ->
def flavor = variant.mergedFlavor
def versionCode = flavor.versionCode
if (variant.buildType.isDebuggable()) {
versionCode += 1
}
flavor.versionCode = versionCode
}
}
The easiest solution is moving versionCode and versionName variables from defaultConfig to debug and release respectively.
android {
...
defaultConfig {
// without versionCode and versionName
...
}
buildTypes {
debug {
defaultConfig.versionCode X
defaultConfig.versionName 'X.Y.Z'
}
release {
defaultConfig.versionCode A
defaultConfig.versionName 'A.B.C'
}
}
...
}
Me too, but I think defaultConfig.versionCode was set when build.gradle be compiling. It's global static variable, and assigned at compiletime, not runtime.
I think we can intercept gradle task execution, and modify defaultConfig.versionCode at runtime.
After goooooooogle, I found this one works for me: https://gist.github.com/keyboardsurfer/a6a5bcf2b62f9aa41ae2
To use with Flavors:
applicationVariants.all { variant ->
def flavor = variant.mergedFlavor
def name = flavor.getVersionName()
def code = flavor.getVersionCode()
if (variant.buildType.isDebuggable()) {
name += '-d'
code = 1
}
variant.outputs.each { output ->
output.versionNameOverride = name
output.versionCodeOverride = code
}
}
applicationVariants.all { variant ->
variant.outputs.each { output ->
if (variant.buildType.isDebuggable()) {
output.versionCodeOverride = 26
output.versionNameOverride = "2.2.6"
}
}
}
put it in android{}
So recently I had to deal with the same scenario and all the examples I could find use the applicationVariants property which is ill-documented imo.
So after some digging through the source code a bit, I realized that in the end versionCode and versionName properties from ProductFlavor get merged into the AndroidManifest which got me thinking: couldn't we just inject them by ourselves, cause we have manifestPlaceholders property on ProductFlavor AND on BuildType DSL objects, so I came up with this -- don't hesitate to give feedback and tell me why it's wrong
In build.gradle(app)
android {
...
buildTypes {
debug {
manifestPlaceholder = [versionCode: X, versionName: "X.Y.Z"]
}
release {
manifestPlaceholder = [versionCode: A, versionName: "A.B.C"]
}
}
...
}
In AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="..."
android:versionCode="${versionCode}"
android:versionName="${versionName}">
...
</manifest>

Exclude specific build variants

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")
}

Categories

Resources