Config for specific gradle flavor combination - android

I am wondering if it is possible to supply files or configuration settings for a specific flavor group combination. For example, I have 2 flavor groups, with 2 different flavors each:
Flavor Group: Version
v2
v3
Flavor Group: Type
free
full
When ordered "Type", "Version" I am able to build 4 different flavors of my app:
FreeV2
FreeV3
FullV2
FullV3
And my source tree looks like this:
/src
/free
/res
/full
/res
/v2
/java
/res
AndroidManifest.xml (features and permissions for v2 flavors)
/v3
/java
/res
AndroidManifest.xml (features and permissions for v3 flavors)
This is exactly what I want, and works very well for my project. However, I wish I could provide files for a specific flavor group combination. For example, I want to provide different AndroidManifests for FullV3 and FullV2. I don't think this is possible, or? For example:
/src
/free
/res
/full
/res
/v2
/java
/res
AndroidManifest.xml (features and permissions for v2 flavors)
/v3
/java
/res
AndroidManifest.xml (features and permissions for v3 flavors)
/fullv3
AndroidManifest.xml (features and permissions for full v3 only!)
/fullv2
AndroidManifest.xml (features and permissions for full v2 only!)
I would be nice to be able to do this in the gradle build file as well:
productFlavors {
free {
packageName ...
flavorGroup "type"
}
full {
packageName ...
flavorGroup "type"
}
v2 {
packageName ...
flavorGroup "version"
}
v3 {
packageName ...
flavorGroup "version"
}
fullv2 {
... <-- specifically for the full-v2 combination
}
fullv3 {
... <-- specifically for the full-v3 combination
}
}
Note: one solution would be to only have 1 flavor group and define the 4 flavors explicitly:
freeV2
freeV3
fullV2
fullV3
However, this is not a viable solution for me since I would have to duplicate all the version specific code for the free and full flavors of each version.

This functionality was added in version 0.7.0 of the Android plugin for Gradle
http://tools.android.com/tech-docs/new-build-system <--As of 1/6/14, this link is active
You can now have a variant specific source folder if you have flavors.
Only for app (not library or test). Name is src/flavorDebug/... or src/flavor1Flavor2Debug/
Note the camelcase naming, with lower case for first letter.
Its components (res, manifest, etc...) have higher priority than components from build type or flavors.
There is also a "flavor combination" source folder available when more than one flavor dimension is used. For instance src/flavor1Flavor2/
Note that this is for all combinations of all dimensions.
Its priority is higher than single-flavor sourcesets, but lower than build-types.
Update 1/30/2014
IntelliJ IDEA v13.0.2 (Build 133.696) now supports Android Gradle Plugin changes made in 0.7.0

Files will be merged when the flavors come together. So if you have a manifest in full and in v3, they will be combined when fullV3 is generated. This way you can get the combo generated.

As per the question asked you want different AndroidManifest file for Full version of both v2 and v3. So instead of going with flavors for full and free, you can use combination of flavors and buildTypes as per your convenience.
For example
I know full and free should be product flavors not build types but your requirement says that full and free are your buildTypes and v2 and v3 are your app flavors
buildTypes {
debug {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
full{
runProguard false/true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
signingConfig signingConfigs.prodSigning // write your signingConfig
}
free{
runProguard false/true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
signingConfig signingConfigs.prodSigning // write your signingConfig
}
}
productFlavors{
v2 {
//required configuration for full version
}
v3 {
//required configuration for full version
}
}
Now your project structure should look like this .
--src
---main
----java
----res
----Manifest
---full
----java
----res
----Manifest(Manifest you want for Full Version)
---free
----java
----res
----Manifest (Manifest you want for Free Version)
---v2
----java
----res
----Manifest
---v3
----java
----res
----Manifest
After Sync with Gradle this will give combinations of build types in build variant tab in left pane in AS and will create different tasks for the same.
Go to Build Variant and generate the build from drop down according to your choice.
It will give you Build Variants like this

To set configuration for each flavor combination in your build file you could use the solution I proposed here: https://stackoverflow.com/a/26585241
You can then use and variantFilter to iterate through all flavor combinations and match on the name of each combination (just like the name used when creating "flavor combination" source folders where you can place specific resources as mentioned in the answer from #abest):
android.variantFilter { variant ->
def flavorString = ""
def flavors = variant.getFlavors()
for (int i = 0; i < flavors.size(); i++) {
flavorString += flavors[i].name;
}
if(flavorString.equalsIgnoreCase("fullv2")) {
variant.getDefaultConfig().applicationId "com.example.fullv2"
}

Related

Conditional AndroidManifest attribute based on build profile?

I'd like to release a demo and a full version of my app.
How can I:
define different build profiles so that if I build the apk I get two apps, one full and one for demo?
Change the <application android:label="#string/app_name">? Eg for full version I want to use #String/app_name, but for demo build profile use app_name_demo? The app names are also localized!
Do I somehow have to work with the gradle productFlavors part?
Like:
productFlavors {
demo {
applicationIdSuffix ".demo"
versionNameSuffix "-demo"
}
}
But I could not find how to achieve my points above.
Edit
go with productFlavors
productFlavors {
demo {
applicationIdSuffix ".demo"
versionNameSuffix "-Demo"
}
release {
minifyEnabled true
shrinkResources true
debuggable false
}
}
Create two folder under /app/src
1. demo
2. release
place constant.xml file and put your application label there accordingly. Based on your build type your application name would be picked up.
also inside each product flavour folder you can create the same directory structure as you would do with app main folder.
So your final structure would go like
/demo/res/values/constant.xml
/demo/res/values-fr/constant.xml
something like this.

Create build types for product flavors

I'm looking for how can I create build types directory for flavors.
Right now I have 2 flavors called dev and prod and I want to create debug and release directories in app/src folder.
My app/src folder looks like this:
main
androidTest
test
release
debug
About what I'm trying to achive:
I'm trying to add a sufix to my package in debug mode. So I achived that in build types block. in addition I have set minSdkVersion 21 in one of my flavors so that android gradle builds faster.
You can create directory that are the combination between build types and flavors naming them with this convention: buildtypeFlavor
For what you want to achieve you have to insert in your build.gradle file both build types configurations and flavors configurations.
android {
buildTypes {
debug {
applicationIdSuffix '.debug'
}
release {
}
}
productFlavors {
dev {
minSdkVersion 21
}
prod {
}
}
}
Now you can create dirs under src to have the combination of both, in this case: devDebug, devRelease, prodDebug, prodRelease
root
|___module
|___src
|__devDebug
|__devRelease
|__prodDebug
|__prodRelease

Application name as gradle parameter

I want to do something like that: gradle build DemoApp, and have DemoApp.apk with application name "DemoApp" as output.
Also, can I change application icon if with the same flow?
And some inner parameters?
Product flavors - not a secret for me. I do not need different configurations, I need to change application name at the build time. For example, I have some Rest API, that allows to pass parameter and return apk with application named as that parameter. The same with icon and other.
Checkout Manifest Merger specifically placeholders. Below is an example of setting the app name in gradle file.
// AndroidManifest.xml
<application
android:label="${applicationName}"
// build.gradle
buildTypes {
release {
minifyEnabled false
manifestPlaceholders = [applicationName: "MobileWorkforce"]
}
The other option is to use #string/app_name and define different string.xml files based upon buildType/flavor.
Given that you don't know how to use flavours properly, a mix of other solutions.
AndroidManifest.xml
<application
android:label="${applicationName}"
MyHttpThing.java
callserver(BuildConfig.ENDPOINT + "/api/v3/", "stuff")
build.gradle
buildTypes {
release {
minifyEnabled false
manifestPlaceholders = [applicationName: myappname]
buildConfigField "String", "ENDPOINT", myendpoint
}
and call with
gradle -Pmyappname=namy_name_name -Pmyendpoint="http://google.com" build DemoApp
Looks like you're looking for Product Flavors, they're exactly for having multiple customized versions of the app with shared codebase. You can customize the icon, as long as any other resource. And yes, the .apk will be named according to the name of the flavor.

Exclude assets for release build type

I'm importing an android library in an application built with gradle, like that:
dependencies {
compile 'com.example:great-lib:0.1-SNAPSHOT'
}
This library contains only assets, js, css and images to be used in a webview, with a layout like that:
assets/
|-> great.css
|-> great.min.js
|-> great.min.js.map
|-> js/
| |-> plop.js
| |-> foo.js
| ...
|-> img/
| ...
The js folder contains source files (to be used with source maps). I would like to include it and the .map file for the debug builds, and have only the minified js in release builds, but I can't find a way to do that.
So far I've tried : 
android {
// this doesn't exclude anything
packageOptions {
exclude 'assets/js'
}
buildTypes {
release {
// this does exclude the js folder, but in both release and debug
aaptOptions {
ignoreAssetsPattern "!js"
}
}
}
}
Any idea if what I want is possible to achieve, and if so how?
(I've also thought of publishing two versions of the library (great-lib and great-lib-debug), and have the dependency in debugCompile and releaseCompile, but I'd prefer avoiding that and publishing a single version)
I had success with this approach (updated 2019-5-13 for TaskProvider support; see edit history for older versions):
android {
⋮
applicationVariants.all { variant ->
if (variant.buildType.name == 'release') {
variant.mergeAssetsProvider.configure {
doLast {
delete(fileTree(dir: outputDir, includes: ['**/js', '**/*.js.map']))
}
}
}
}
⋮
}
This should address the issues with #Xavier's answer:
The deletion is done as part of the variant's mergeAssets task so the deletion is reflected in the task's output and up-to-date checking should be unaffected.
The paths are calculated without magic strings. You may need to adjust the include patterns in case my example is too permissive.
The variant is being selected by the buildType name, which is less problematic than matching the entire variant name (though it is still stringly typed).
Note that this approach also works for res files rather than assets: just replace mergeAssets with mergeResources.
Other answers mentioning packagingOptions and aaptOptions are barking up the wrong tree, as these are scoped to all variants (they are defined in the android scope, not buildType or productFlavor).
I ended up doing the following:
android.applicationVariants.all { variant ->
if (variant.name.contains('Release')) {
// exclude source and sourcemap from release builds
def noJsSourceTask = task("delete${variant.name}JsSource", type: Delete) {
delete "${buildDir}/intermediates/assets/${variant.dirName}/js"
delete "${buildDir}/intermediates/assets/${variant.dirName}/great.min.js.map"
}
variant.mergeAssets.finalizedBy noCeJsSourceTask
}
}
It works ok, but there are a few things I don't really like:
I'm touching at the files produced by a task after it is done (the finalizedBy), so it doesn't work well with "up-to-date" checking. But it's only for release builds, I'm doing debug ones more often
the path of the files to delete is manually built. I'm not sure if it's generic enough to be reused in other projects as-is
I'm selecting the variants based on their name. I would have liked something more structured.
Gradle provides "aaptOptions, ignoreAssetsPattern" to filter/exclude assets folders and files from release or debug build.
Example for debug build (js folder and great.css files):
debug {
aaptOptions {
ignoreAssetsPattern '!js:!great.css:'
}
}
Example for release build (js folder and great.css files):
release {
aaptOptions {
ignoreAssetsPattern '!js:!great.css:'
}
}
I think you can use proguard. Proguard is include with android studio,obfuscate code, and remove not used classes, and if you want remove all resources that app not used. Only put in your build.gradle this:
release {
minifyEnabled true //remove classes, obfuscate code and zipalign
shrinkResources true //remove resources
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'//autogenerated files
}
This is link information about that:
http://developer.android.com/tools/help/proguard.html
You can personalize, exclude particular files or ignore particular files
It's not possible through a filter.
You could have 2 assets folders though. a main one (src/main/assets) used for both debug and release and one (src/debug/assets) used only for the debug build.
source

Overriding resources in a multi flavor setup in Gradle

I am facing an issue where I am not able to generate the desired resource files. In my project setup I have defined certain values in resource files(keys.xml) that are different between flavors(amazon, googlePlay). The problem mainly occurs because the keys are also different between the live/qa builds.
So the final keys I would like to have are:
amazonPaidQa -> keys from 'src/amazon/res/values/keys.xml'
amazonPaidLive -> keys from 'src/amazonPaid/res/values/keys.xml' (not working as this requires me to define the keys file in 'src/amazonPaidLive')
My question is if it is possible to define resources in 'interim' build variants like the above mentioned 'amazonPaid' so that I would not have to duplicate that file between all possible live build variants(amazonPaidLive, amazonFreeLive). Or maybe someone has a better suggestion how to approach this problem?
build.gradle definitions
buildTypes {
qa {
//config
}
live {
//config
}
}
flavorGroups "market", "client"
productFlavors {
//define the market flavors
amazon {
flavorGroup "market"
}
googlePlay {
flavorGroup "market"
}
//define the client flavors
free {
flavorGroup "client"
packageName "com.example.free"
}
paid {
flavorGroup "client"
packageName "com.example.paid"
}
}
The folder structure is the following:
- src/main
-- AndroidManifest.xml
-- res/values/keys.xml
- src/live
- src/qa
- src/amazon
-- res/values/keys.xml
- src/googlePlay
-- res/values/keys.xml
- src/paid
- src/free
Android Manifest snippet
<application>
...
<meta-data android:name="app_id" value="#string/app_id" />
</application>

Categories

Resources