Multi Flavor App Based on Multi Flavor Library in Android Gradle

Multi flavor app based on multi flavor library in Android Gradle

Finally I found out how to do this, I will explain it here for others facing same problem:

If App and Library have same Flavor name(s)

It's possible since Gradle Plugin 3.0.0 (and later) to do something like:

Library build.gradle:

apply plugin: 'com.android.library'

// Change below's relative-path
// (as the `../` part is based on my project structure,
// and may not work for your project).
apply from: '../my-flavors.gradle'

dependencies {
// ...
}

android {
// ...
}

Project build.gradle:

buildscript {
// ...
}

apply plugin: 'com.android.application'
// Note that below can be put after `dependencies`
// (I just like to have all apply beside each other).
apply from: './my-flavors.gradle'

dependencies {
api project(':lib')
}

android {
productFlavors {
// Optionally, configure each flavor.
market1 {
applicationIdSuffix '.my-market1-id'
}
market2 {
applicationIdSuffix '.my-market2-id'
}
}
}

My flavors .gradle:

android {
flavorDimensions 'my-dimension'
productFlavors {
market1 {
dimension 'my-dimension'
}
market2 {
dimension 'my-dimension'
}
}
}

If App or Library has different Flavor-name (old answer)

The key part is to set publishNonDefault to true in library build.gradle, Then you must define dependencies as suggested by user guide.

Update 2022; publishNonDefault is now by default true, and setting it to false is ignored, since said option is deprecated.

The whole project would be like this:

Library build.gradle:

apply plugin: 'com.android.library'

android {
....
publishNonDefault true
productFlavors {
market1 {}
market2 {}
market3 {}
}
}

project build.gradle:

apply plugin: 'com.android.application'

android {
....
productFlavors {
market1 {}
market2 {}
market3 {}
}
}

dependencies {
....
market1Compile project(path: ':lib', configuration: 'market1Release')
market2Compile project(path: ':lib', configuration: 'market2Release')

// Or with debug-build type support.
android.buildTypes.each { type ->
market3Compile project(path: ':lib', configuration: "market3${type.name}")
}

}

Now you can select the app flavor and Build Variants panel and the library will be selected accordingly and all build and run will be done based on the selected flavor.

If you have multiple app module based on the library Android Studio will complain about Variant selection conflict, It's ok, just ignore it.

Sample Image

Use different library module for each android flavor

If you have a library with multiple product flavors, in your lib/build.gradle you can define:

android {
...
//flavorDimensions is mandatory with flavors.
flavorDimensions "xxx"
productFlavors {
free{
dimension "xxx"
}
paid{
dimension "xxx"
}
}
...
}

In your app/build.gradle define:

android {
...

flavorDimensions "xxx"
productFlavors {
free{
dimension "xxx"

// App and library's flavor have the same name.
// MatchingFallbacks can be omitted
matchingFallbacks = ["free"]
}
paid{
dimension "xxx"

matchingFallbacks = ["paid"]
}
}
...
}
dependencies {
implementation project(':mylib')
}

Instead, if you have separate libraries you can simply use in your app/build.gradle something like:

dependencies {
freeImplementation project(':freeLib')
paidImplementation project(':paidLib')
}

Single flavor module based on multi flavor library in Gradle

My gradle version is 4.4.

In doc,
Android developer and Android Plugin DSL Reference
show that, should add follow code.

missingDimensionStrategy 'external'
missingDimensionStrategy 'target'

Android developer link image

Android Plugin DSL Reference image

but it not work for me. Finally I add follow code in feature.gradle.

flavorDimensions 'target'

productFlavors {
internal {
dimension "target"
}
}

No classes from main sources from multi flavor library

Finally I got the solution as defining missingDimensionStrategy in app's build.gradle.





// Specifies a sorted list of flavors that the plugin should try to use from

// a given dimension. The following tells the plugin that, when encountering

// a dependency that includes a "minApi" dimension, it should select the

// "minApi18" flavor. You can include additional flavor names to provide a

// sorted list of fallbacks for the dimension.

missingDimensionStrategy 'outerInner', 'internal'

Using different res values in a multi-flavor android library uses wrong values in compiled APK when using gradle caching

Apparently this was an issue with older 7.0 versions of AGP. It was addressed in 7.0.4. Can confirm the issue doesn't happen when using that version.

Issues relating to this:
https://issuetracker.google.com/issues/201930057
https://issuetracker.google.com/issues/196852190

How to generate multi flavor apk by selectively bundling the dependency library?

Use flavor-specific directives for your dependencies. Instead of implementation, for example, you would use demoImplementation and fullImplementation. The demo builds would include the demoImplementation dependencies, while full builds would include the fullImplementation dependencies.

The documentation page that you linked to shows an example, using a free flavor:

dependencies {
// Adds the local "mylibrary" module as a dependency to the "free" flavor.
freeImplementation project(":mylibrary")

// Adds a remote binary dependency only for local tests.
testImplementation 'junit:junit:4.12'

// Adds a remote binary dependency only for the instrumented test APK.
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

Include library with flavor android

The problem the app has is that it doesn't know which library's flavor to use.

The keyword matchingFallbacks will tell the app which library's flavor you want to select. But this keyword has to be use with a Flavor.

We have to add a flavor (+ dimension) on your app build.gradle:

android {
...
//flavorDimensions is mandatory with flavors. Use the same name on your 2 files to avoid other conflicts.
flavorDimensions "dim"
productFlavors {
nocustomer{
dimension "dim"

// App and library's flavor have the same name.
// MatchingFallbacks can be omitted
matchingFallbacks = ["nocustomer"]
}
customerNb{
dimension "dim"

// Here the app and library's flavor are different
// Matching fallbacks will select the library's flavor 'customer001'
matchingFallbacks = ["customer001"]
}
}
...
}
dependencies {
implementation project(':zblelib')
}

In this way, when you select the app's flavor nocustomer, the library's flavor will select automatically nocustomer, and when you select the app's flavor customerNb, the library's flavor will select automatically customer001

PS

I am using implementation instead of compile, because compile is deprecated (see here)



Related Topics



Leave a reply



Submit