Build app with multiple build variants of library in android - android

I have created a library called mylibrary with two product flavors like virtual and nonvirtual like below
flavorDimensions "dev"
productFlavors {
virtual {
dimension "dev"
}
nonvirtual {
dimension "dev"
}
}
and I have implemented the library in my project LibraryTesting like below
implementation project(path: ':mylibrary')
Now, when I trying to select different build variant its showing errors like "Module 'LibraryTesting.mylibrary' has variant 'nonvirtualDebug' selected, but the module 'LibraryTesting.app' depends on variant 'virtualDebug'"
please find the below image for more information
I want change the library build variant and build the app with that selected variant.
Please help me.

Your app module must decide what flavor to use.
For example, if you want app module to compile myLibrary module and virtual flavor, you need to add the following to android.defaultConfig block in build.gradle of app module:
missingDimensionStrategy 'dev', 'virtual'
Alternatively, if you want to be able to choose the variants from UI without errors, you can create 2 flavors in app module and each flavor will compile the corresponding flavor in myLibrary module:
flavorDimensions "app_dev"
productFlavors {
virtual {
dimension "app_dev"
missingDimensionStrategy 'dev', 'virtual'
}
nonvirtual {
dimension "app_dev"
missingDimensionStrategy 'dev', 'nonvirtual'
}
}
In any case, app module must declare missing dimension strategy

Related

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

My android app depends on multiple android library (say A,B,C,D). I would like to generate different apks out of them say apk1 needs to consume only on A,B and apk2 needs to consume B,C.
I've explored the option of Android's product flavor concept by doing something like this,
android {
...
defaultConfig {...}
buildTypes {
debug{...}
release{...}
}
// Specifies one flavor dimension.
flavorDimensions "version"
productFlavors {
demo {
// Assigns this product flavor to the "version" flavor dimension.
// If you are using only one dimension, this property is optional,
// and the plugin automatically assigns all the module's flavors to
// that dimension.
dimension "version"
applicationIdSuffix ".demo"
versionNameSuffix "-demo"
}
full {
dimension "version"
applicationIdSuffix ".full"
versionNameSuffix "-full"
}
}
}
Now it's generating apks with multiple products but it is including all libraries for each flavor. How can I avoid this?
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'
}

Exclude JNI libs based on flavor in a smart way

I have an Android project that uses some native libs that are quite big in size.
I have several flavors in this project and some of them don't make use of these libs so I would like to exclude them from the APK.
I know several ways to achieve this but I would like to use some nice code in the build.gradle file to reduce possible errors and learn groovy.
I have to mention that there is a boolean buildConfigField (called DO_IT in this example). If DO_IT is false then JNI libs are to be excluded.
This is the way I do it now:
defaultConfig {
buildConfigField "boolean", "DO_IT", "true"
}
productFlavors {
flavor1 {
// for this flavor JNI libs will be included
}
flavor2 {
// for this flavor JNI libs will NOT be included
buildConfigField "boolean", "DO_IT", "false"
ndk {
abiFilters ''
}
}
}
Remarks:
1 - Consider that I have many flavors with tons of properties and I don't want to replicate the block
ndk {
abiFilters ''
}
but I cannot manage to put this block it inside a method.
2 - The pefect solution would just exclude the libs based on the DO_IT buildConfigField in a routine outside the flavors' blocks EG in the defaultConfig.
android-soexcluder should be the way to go.
Steps are as below:
Modify build.gradle to add the dependencies.
buildscript {
repositories {
//...
}
dependencies {
classpath 'com.jween.gradle:android-soexcluder:1.1'
}
}
apply plugin: 'com.android.application'
apply plugin: 'android-soexcluder'
Exclude the .so from your build flavor
soexcluder {
// Remove all so files according to the flavor1
flavor1 {
exclude "lib/armeabi-v7a/foo.so", "lib/arm64-v8a/bar.so"
}
}
Other option is to add a gradle parameter for packagingOptions: Set doNotStrip packagingOptions to a specific buildType
I use this pattern.
Project build.config
buildscript {
ext.DO_IT = true;
}
Module(app) build.config
productFlavors {
flavor2 {
externalNativeBuild {
cmake {
if (DO_IT) {
targets "someTarget"
}
}
}
}
}
NB.1 ext is mentioned in Extra properties section, an
ExtraPropertiesExtension of Gradle.
NB.2 Per flavor settings like including libraries shoud be controled in project build.config, as Android Studio / Gradle tries to read all setting in all flavors once and causes conflicts or other problems.
NB.3 Please keep in mind that Android Studio does not delete library(.so) files which are already sent to the device. It coufuses test results. Check files in /data/app/(package)/lib/(cpu arch)/ on device and (project)/app/build/intermediates/cmake/(flavor)/obj/(cpu arch)/ in your pc. Clear them manually, especially on the device ones, if you feel the result is wrong.
Clear data from app/storage setting will not clear libraries. Uninstall will clear them, so manual deletion of files is easier I think.
NB.4 Synchronize menu of Device File Explorer of Android Studio does not sync properly for lib or (cpu arch) directories. To see correct results, select /data or /data/app and sync.

How to choose module's flavour in Android Studio with 3.x.x Gradle plugin

I have project with this configuration:
App > ModuleA
ModuleA has two flavors: free and paid
App has
missingDimensionStrategy 'type', 'free'
to set default flavors.
But now in AS 3.2.1 (Gradle plugin 3.2.1) with new variant-aware system I can't choose build variant only for moduleA without changing App.
I have only two possibilities:
Update missingDimensionStrategy to set another default value
Add additional flavors to App which will be correspondent with flavors in ModuleA
Is there any possibility to do it without changing Gradle script?
Let me show you an example for you
moduleA's build.gradle file as follow:
...
productFlavors {
...
free{
...
}
paied{
...
}
...
}
...
Then you can add same productFlavors for you app's build.gradle file,
...
productFlavors {
...
free{
...
}
paied{
...
}
...
}
...
after setting then you can choose it in AS for moduleA and app, it will work fine.

Transitive dependencies for library build flavours on Android using api

I have a library that is built via Jitpack containing the following build flavors
productFlavors {
play {
dimension "default"
versionName versionString + "-play"
}
nonplay {
dimension "default"
versionName versionString + "-nonplay"
}
}
In the libraries dependencies section, I include a different dependency based on flavour like so
playApi "com.google.android.gms:play-services-location:$playServicesVersion"
nonplayApi "com.mapzen.android:lost:$lostVersion"
When I include this library in a new apps build.gradle, with, for example, nonplay
implementation ("com.xxx:someproject:1.0.0:nonplay#aar") {
transitive = true
}
I expect to see "com.mapzen.android:lost:$lostVersion" transitively included in my apps dependences list.
However I only see dependencies transitively included that do not use a flavour specific include i.e. api instead of nonplayApi. To avoid runtime crashes, I need to also add the nonplayApi dependencies in my app module.
How do I get my flavour specific nonplayApi or playApi dependencies to include transitively in my app module?

How to compile with gradle different dependency module's dependencies based on build variants?

I have an Android app which has a module dependency. This module itself has a jar library as a dependency that comes in two variants, each relative to a build variant of the main app. When I switch build variant in the main app, I managed to automatically select the module's build variant which picks the correct jar, but this is not reflected in the code, where the specific classes from the jar are not found in the build variant specific code.
Here's the related code from the build.gradle files of the main app and the dependency module:
main app - build.gradle
buildTypes {
type1 {initWith(debug)}
type2 {initWith(debug)}
}
productFlavors {
live{}
test{}
}
dependencies {
type1Compile project(path: ':module', configuration: 'one')
type2Compile project(path: ':module', configuration: 'two')
}
module - build.gradle
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
useLibrary 'org.apache.http.legacy'
publishNonDefault true
defaultConfig {
minSdkVersion 14
targetSdkVersion 22
}
buildTypes {
release {
minifyEnabled = false
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
one {initWith(release)}
two {initWith(release)}
}
}
dependencies {
oneCompile files('libs/versionOne/mylib.jar')
twoCompile files('libs/versionTwo/mylib.jar')
}
So, when I build testType1 variant, Android Studio automatically selects one variant, and with a clean build it all goes fine. But if I switch to testType2, although module's two variant is selected, the editor will highlight missing classes and methods.
How can I make gradle pick the right jar when I switch between the app's build variants?
Some considerations:
The module needs the library, since it uses a few classes that are common between the 2 versions.
I know this may look like bad project design, but it's an app that has been built by different people in different times, and I now have to develop it "as is".
After some tinkering, I found some clues. First of all, my two jars where the same name, in different folders. After renaming the jars to have also different names, gradle manages to pick the correct one after the build variant switch, provided that an additional "Sync project with gradle files" is done. So now it's not immediate, but eventually it's working.

Categories

Resources