4

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.

shizhen
  • 12,251
  • 9
  • 52
  • 88
qwlice
  • 556
  • 7
  • 23

2 Answers2

2

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

shizhen
  • 12,251
  • 9
  • 52
  • 88
  • 1
    that's bloody sweet! Thanks for this Pro Tip! – Someone Somewhere Apr 30 '19 at 20:54
  • Already broken as of February 2020 due to https://stackoverflow.com/questions/54206898/variantoutput-getpackageapplication-is-obsolete . Gradle feels like the Google version of the Apple developer experience: breaks everything at least once a year – oseiskar Feb 26 '20 at 13:58
1

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.

Toris
  • 2,348
  • 13
  • 16