Exclude JNI libs based on flavor in a smart way

Viewed 1294

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.

2 Answers

android-soexcluder should be the way to go.

Steps are as below:

  1. 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'
    
  2. 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.

Related