What is a good strategy when working with Proguard, MultiDex, Testing, and Product Flavors?

I have an application that references methods ~ 100K, with min Sdk = 16

Here are 2 options to build:

  • Proguard reduces this piece of methods to only 44 thousand methods
  • Use Multi Dex

Now I have a few common cases:

  • Starting and debugging emulator and devices
    • Required as fast as possible
  • Perform tests (integration and user interface)
    • It needs to be started (I have a problem with starting Espresso with MultiDex)
  • Make Prod APK
    • It should be as reliable and concise as possible.

Do you have any build strategy recommendations?

3 / Prod

  • Use Proguard to reduce APK size
  • Use Proguard for Obfuscation
  • Do not use Multidex as much as possible (this may be unsuccessful)

2 / Test

  • Use minSdkVersion 21 (I read that starting with 21 enable pre-deletion, which saves time)
  • ???

1 / Debugging

  • Use minSdkVersion 21 (I read that starting with 21 enable pre-deletion, which saves time)
  • ???

Here is the Gradle file:

productFlavors { dev { minSdkVersion 21 multiDexEnabled ??? testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } prod { // The actual minSdkVersion for the application. minSdkVersion ANDROID_BUILD_MIN_SDK_VERSION multiDexEnabled false } } defaultConfig { applicationId "xxxx" targetSdkVersion ANDROID_BUILD_TARGET_SDK_VERSION minSdkVersion ANDROID_BUILD_MIN_SDK_VERSION versionCode ANDROID_BUILD_VERSION_CODE versionName ANDROID_BUILD_APP_VERSION_NAME } buildTypes { release { debuggable false ext.enableCrashlytics = true renderscriptOptimLevel 3 signingConfig android.signingConfigs.release zipAlignEnabled true minifyEnabled true // shrinkResources true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } debug { debuggable true renderscriptOptimLevel 3 applicationIdSuffix ".debug" versionNameSuffix "debug" minifyEnabled false } } 
+6
source share
2 answers

Based on @Muzikant’s suggestion that I basically agree, I summarized my current vision

  • Do not use MultiDex if you can.
    • It may happen that it reaches number 65K with the method overhead with test libraries (so use MutliDex)
    • It may happen that MultiDex is faster than the Proguard process (for verification), so it may be interesting for debugging
  • Try using the APK for testing, which is closest to the APK version

My recommendations:

  • since there are 3 build cases, just create 3 buildTypes:

    • release
    • debugging
    • verification (test is a reserved word)
  • use 2 flavors:

    • one for release with minSdkVersion your application
    • and one for development that uses the more modern minSdkVersion (faster build, more testing options, easier to use espresso ...)
  • don't get confused for debugging

  • To use Proguard in the testing phase, you need a specific DSL keyword testProguardFile('proguard-rules-test.pro')

  • specify the assembly that will be used for debugging with testBuildType = "validation"

  • do obfuscation for testing (at least for the user interface system and functional tests in your CI system)

  • use Proguard optimization rules only for the release of getDefaultProguardFile('proguard-android-optimize.txt') , for testing and debugging just use getDefaultProguardFile('proguard-android.txt')

The architecture of my Proguard files is as follows:

  • one main file for release proguard-rules-release.pro , which includes a set of dedicated Proguard files with -include proguard-rules-fabric.pro

  • one second file for debugging proguard-rules-debug.pro , which includes proguard-rules-release.pro

  • one third file for debugging proguard-rules-dontobfuscate.pro that disable obfuscation

  • one fourth file for testing proguard-rules-test.pro , which includes proguard-rules-debug.pro and the rules necessary for testing

Here is the Gradle file:

 android { ... compileSdkVersion ANDROID_BUILD_SDK_VERSION buildToolsVersion ANDROID_BUILD_TOOLS_VERSION productFlavors { // Define separate dev and prod product flavors. dev { // dev utilizes minSDKVersion = 21 to allow the Android gradle plugin // to pre-dex each module and produce an APK that can be tested on // Android Lollipop without time consuming dex merging processes. minSdkVersion 21 multiDexEnabled false } prod { // The actual minSdkVersion for the application. minSdkVersion ANDROID_BUILD_MIN_SDK_VERSION multiDexEnabled false } } defaultConfig { applicationId "xyapp.z" targetSdkVersion ANDROID_BUILD_TARGET_SDK_VERSION minSdkVersion ANDROID_BUILD_MIN_SDK_VERSION versionCode ANDROID_BUILD_VERSION_CODE versionName ANDROID_BUILD_APP_VERSION_NAME testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } // point thge build for testing testBuildType = "validation" buildTypes { release { debuggable false ext.enableCrashlytics = true renderscriptOptimLevel 3 signingConfig android.signingConfigs.release zipAlignEnabled true minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules-release.pro' } debug { debuggable true renderscriptOptimLevel 3 applicationIdSuffix ".debug" versionNameSuffix "debug" minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules-debug.pro', `proguard-rules-dontobfuscate.pro` } validation.initWith(debug) validation { signingConfig android.signingConfigs.release debuggable false renderscriptOptimLevel 3 applicationIdSuffix ".test" versionNameSuffix "test" minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules-debug.pro' testProguardFile('proguard-rules-test.pro') } } ... } 

I still have some open points to solve:

  • How to use auto-signature to debug Android Studio to build validation? (but I'm not sure about that).

  • I still need to add the proguardFiles attribute to the Validation BuildType, while I have testProguardFile('proguard-rules-test.pro') that includes debugging!

+2
source

I use proguard for both versions of debugging and release to avoid multidex.

My build.gradle file is as follows:

 debug { minifyEnabled true proguardFiles 'proguard_debug.pro' signingConfig signingConfigs.debug debuggable true } release { minifyEnabled true proguardFiles 'proguard_release.pro' signingConfig signingConfigs.release debuggable false } 

To minimize the differences between debugging and release, as well as to properly debug the debug build, the proguard_debug.pro file contains the following security instructions:

 -include proguard_release.pro -dontobfuscate -dontoptimize -keep class my.package.name.** {*; } 

Thus, I support only one proguard configuration (in proguard_release.pro ), and the debug version is built using the same configuration, but without obfuscating the code.

This configuration solves all of these issues:

  • There is no need for multidex (so there is no dilemma whether to use it with API 21+ and you can use Espresso)
  • Debug and release builds are the same, except that the debug build does not obfuscate your code
+1
source

All Articles