To make development faster, I want to do the following:
android {
defaultConfig {
resConfigs "en"
}
}
My app has a lot of languages, and doing this saves significant time while developing. However, I do NOT want to release a version with this set. Unfortunately, resConfigs is not available on product flavors or build types, so I can't set it in debug {}, for example.
How can I automatically exclude resConfigs from release variants? I do not want to have to remember comment out that line of code when I'm building for release.
Wouldn't this work?
Detect the debug build, reset the configurations and add your desired debug configuration.
applicationVariants.all { variant ->
if (variant.buildType.name == "debug") {
variant.mergedFlavor.resourceConfigurations.clear()
variant.mergedFlavor.resourceConfigurations.add("en")
}
}
My solution was inspired by this answer to a related question. Here's how you do it:
in app/build.gradle
// Reset `resConfigs` for release
afterEvaluate {
android.applicationVariants.all { variant ->
if (variant.buildType.name.equals('release')) {
variant.mergedFlavor.#mResourceConfiguration = null
}
}
}
This works because mResourceConfiguration is the backing field for resConfigs. Unfortunately, The Android Gradle DSL does not currently expose a method to reset resConfigs, so we're forced to access the field directly using the groovy #<fieldName> syntax. This works, even though mResourceConfiguration is private.
WARNING: this solution is a little fragile, as the Android Gradle build tools team could change the name of that field at any time, since it is not part of the public API.
Related
Been working on an Android Webview app and I've only just now started to use a node_modules folder in there, so naturally I did some research on how to exclude it and I ended up at this question here
Tried some of the answers and the one that actually worked the best for me was the one about aaptOptions
So of course naturally I'm playing around with it, trying to figure out what works, and I succeed at excluding a few folders from the debug apk.
aaptOptions {
ignoreAssetsPattern '!node_modules:!jsunmin:!.idea:!jade:!css-scss:'
}
And I can indeed confirm that those folders aren't included in the final APK in Android studio! Success!
So then I realize that I can do something a bit clever: when I'm running my app, testing it on my end, debugging it, I like to have certain credentials in certain places automatically put in - I do this with javascript - but obviously I don't want these credentials included in the APKs I might send out into the world -- even though I've already coded it to not input the credentials automatically unless I'm debugging, the credentials are still actually in the javascript files, and presumably someone could look in there and see them!
So my idea was to create a file, 'example-creds.js', and use aaptOptions to not include that file, ONLY on release builds, so I came up with something that looks approximately like this (extra details stripped out):
android {
buildTypes {
release {
aaptOptions {
ignoreAssetsPattern '!node_modules:!jsunmin:!.idea:!jade:!css-scss:!example-creds.js:'
}
}
debug {
aaptOptions {
ignoreAssetsPattern '!node_modules:!jsunmin:!.idea:!jade:!css-scss:'
}
}
}
}
BUT IT DOESN'T WORK! I've tested it and it seems to run whatever the last-defined aaptOptions is, regardless of the build type. If I put release after debug, I get no example-creds in either build. If I put debug after release, I get example-creds in both.
How can I get what I'm looking for?
Generally it should be possible to configure AaptOptions alike any other configuration block. Try to run that script afterEvaluate (which is after those aaptOptions had been evaluated):
task afterEvaluate {
doLast {
applicationVariants.all { variant ->
variant.outputs.all { output ->
def pattern = "!node_modules:!jsunmin:!.idea:!jade:!css-scss:"
if(variant.getBuildType().getName() == 'release') {
pattern = pattern + "!example-creds.js:"
}
aaptOptions.ignoreAssetsPattern = pattern
}
}
}
}
aaptOptions's ignoreAssetPattern cannot be set in afterEvaluate block. If you try, you will run into this error
com.android.build.gradle.internal.dsl.AgpDslLockedException: It is too late to set ignoreAssetsPattern
It has already been read to configure this project.
Consider either moving this call to be during evaluation,
or using the variant API.
The solution is to use the variant API during configuration (also note that aaptOptions is depricated and is renamed to androidResources AGP 7.1.3 onwards)
android {
buildTypes {
release {
androidResources {
ignoreAssetsPattern '!node_modules:!jsunmin:!.idea:!jade:!css-scss:'
}
}
debug {
androidResources {
ignoreAssetsPattern '!node_modules:!jsunmin:!.idea:!jade:!css-scss:'
}
}
}
androidComponents {
onVariants(selector().withName("release")) { variant ->
def pattern = variant.androidResources.ignoreAssetsPattern
pattern.add("!example-creds.js")
}
}
}
I got a project configured with multiple variants and flavors:
buildTypes {
debug {
}
release {
}
}
flavorDimensions "default"
productFlavors {
mock {
}
alpha {
}
beta {
}
prod {
}
}
Whenever I open the project from another one (so starting Android Studio), it selects the mockDebug variant by default. Often I end up build this one first, then realizing I'm on the wrong variant.
Is there a way to tell Android Studio to defaults to one variant, let's say betaDebug?
Technicals: Android Studio 3.1.4, Gradle wrapper 4.4, Android Gradle 3.1.4.
With Android Studio 3.5+ you can set default falvors:
android {
flavorDimensions "stage", "target"
productFlavors {
develop {
getIsDefault().set(true) // that does the magic
dimension "stage"
...
When using KTS it lookes like this:
android {
flavorDimensions("stage", "target")
productFlavors {
create("develop") {
isDefault = true
dimension("stage")
...
Change the order in which you define them in productFlavors. The IDE always loads the first flavor it finds there as the default.
What actually worked for me is enabling "Android Studio Preferences -> Experimental -> Only sync the active variant". It keeps the selected build variant when reopening AS or when re-syncing, basically solving the original problem.
AS/AGP v4.1.
I want to have a different versionCode for debug build type rather than the one in release build type. This used to work by using the configuration from below in Gradle Android plugin v2.3.2 (Gradle v3.3), but doesn't have any effect now in v3.0.0-alpha5 (Gradle v4.1-milestone-1). Any ideas as to what changed in the newest Gradle plugin that makes it ignore the variant.mergedFlavor.versionCode attribute?
buildTypes {
debug {
applicationIdSuffix ".debug"
versionNameSuffix "-" + buildTime()
android.applicationVariants.all { variant ->
if (variant.buildType.name != buildTypes.debug.name) return
variant.outputs.all {
outputFileName = "${archivesBaseName}-${variant.name}-v${variant.versionName}-signed.apk"
variant.mergedFlavor.versionCode = Integer.parseInt(buildTimeSmall())
}
}
}
}
As a workaround before the 3.0 release, if anybody is looking for a solution, you can use:
output.setVersionCodeOverride(Integer.parseInt(buildTimeSmall()))
Thanks to Jerome, reference: https://issuetracker.google.com/issues/63785806#comment6
From migration guide:
Using the Variant API to manipulate variant outputs is broken with the new plugin. It still works for simple tasks, such as changing the APK name during build time, as shown below:
// If you use each() to iterate through the variant objects,
// you need to start using all(). That's because each() iterates
// through only the objects that already exist during configuration time—
// but those object don't exist at configuration time with the new model.
// However, all() adapts to the new model by picking up object as they are
// added during execution.
android.applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = "${variant.name}-${variant.versionName}.apk"
}
}
However, more complicated tasks that involve accessing outputFile objects no longer work. That's because variant-specific tasks are no longer created during the configuration stage. This results in the plugin not knowing all of its outputs up front, but it also means faster configuration times. As an alternative, we will introduce new APIs to provide similar functionality.
I have been using gradle for creating different build variants for different companies for an Android app.
For example I have build flavors:
Company1
Company2
And then I have build types:
Production
Preview
Development
So this will create 6 build variants:
Company1Production
Company1Preview
Company1Development
Company2Production
Company2Preview
Company2Development
So the question is:
Actually I don't need the development build type for company 2, I only need it for company 1.
Is there a way I can specify only company 1 have the development build type?
I have a lot of companies in my projects, some of the build type just don't make sense for those companies, and it confuses people who want to build the app.
To answer my own question, I have found the documentation on the Gradle Plugin User Guide
Filtering Variants
When you add dimensions and flavors, you can end up with variants that don't make sense. For example you may define a flavor that uses your Web API and a flavor that uses hard-coded fake data, for faster testing. The second flavor is only useful for development, but not in release builds. You can remove this variant using the variantFilter closure, like this:
android {
productFlavors {
realData
fakeData
}
variantFilter { variant ->
def names = variant.flavors*.name
if (names.contains("fakeData") && variant.buildType.name == "release") {
variant.ignore = true
}
}
}
With the configuration above, your project will have only three variants:
realDataDebug
realDataRelease
fakeDataDebug
You can't stop the Android plugin from creating the matrix of all builds, but you can cause the build to fail if it's not valid. For example, if you don't want Flavor2 Debug builds to work, you can stop them like this:
afterEvaluate {
tasks['prepareFlavor2DebugDependencies'].doFirst {
throw new IllegalArgumentException("This project is not valid")
}
}
I am using Android Studio and Gradle to build Android applications. I would like to have different strings within the Java code based on which type of build it is (debug vs. release). What is the best way to do this?
For example - I want to have different URLs if I am in debug or release. Also, I want to specify different GUIDs and other keys / strings.
The obvious hacky way to do this is to do a search and replace of a string in AndroidManifest.xml or worse yet, in a Java file. This approach seems error prone and hacky to me - is there a better way to do this?
There are many ways you can do this, although I usually do
android {
buildTypes {
release {
buildConfigField("String", "URL", "your_url_on_release")
}
debug {
buildConfigField("String", "URL", "your_url_on_debug")
}
}
}
You then can access them on your java code by using:
BuildConfig.URL
You can test this using Android Studio Build Variants, by changing your application variant to debug or release ( e.g. http://prntscr.com/8waxkw)
You have many solutions to do this, here's a simple case:
buildTypes {
debug { ... }
release { ... }
}
productFlavors {
staging { ... }
production { ... }
}
build types are for build management proguarding, debugging, signing, etc.
productFlavors are for all app internal configuration.
If you want to add resources related to the flavours you can create and add to src/(flavor_name)/res/values/ folder your urls.xml config file.
With this, in android studio, you'll directly see, all the builds variants in the corresponding window and the right urls.xml file associated to the current context and leave the gradle config clean.
Of course, this method works also for any resource you would need in your app.
For more detail, you can read this : http://developer.android.com/tools/building/configuring-gradle.html#workBuildVariants
I would do it with product flavors as explained in this post.