By Balwinder Singh
ProGuard is a tool to help minify, obfuscate, and optimize your code. It is not only especially useful for reducing the overall size of your Android application as well as removing unused classes and methods that contribute towards the intrinsic 64k method limit of Android applications. Because of the latter issue, ProGuard is often recommended to be used both in development and production especially for larger applications.
ProGuard can be enabled by using the minifyEnabled
option for any build type. If you intend to use it for production, it is highly recommended you also enable it on your development. Without fully testing ProGuard on your development builds, you may encounter unexpected crashes or situations where the app does not function as expected.
android {
buildTypes {
dev {
minifyEnabled true // enables ProGuard
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
The Android SDK comes with ProGuard included as well as default settings file, which are specified as proguard-android.txt. It is important to include this file since it explicitly includes configuration settings such as explicitly stating that all View getter and setter methods should not be removed. The proguard-rules.pro
file is the file that you will use to configure.
Proguard can add a few minutes to your build cycle. If you can avoid using ProGuard in development, you should try to do so. Once you begin to include enough libraries that causes the 64K method limit to be reached, you either need to remove extraneous dependencies or need to consider following the instructions for supporting a higher limit by using the multidex mode. Multidex compilation also takes additional time and requires extra work to support pre-Lollipop Android versions, so the recommendation is often to use ProGuard before using Multidex.
If you wish to check how close you are to the 64k limit, use the new APK Analyzer by going to Build
=>Analyze APK...
. Click on the respective APK file and you can see a breakdown of the methods by package.
When using in development/debug testing, you may wish to turn on a few settings that may add to compile time as well as make it harder to troubleshoot. For instance, to ensure that no code optimizations or obfuscation is done, the following options should be declared in your ProGuard config:
# Workaround for ProGuard not recognizing dontobfuscate
# https://speakerdeck.com/chalup/proguard
-dontobfuscate
-dontoptimize
-optimizations !code/allocation/variable
An alternative is to request only to remove unwanted code (shrink) but not obfuscate. Details here.
buildTypes {
debug {
minifyEnabled true // shrink
useProguard false // don't obfuscate
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
release {
minifyEnabled true // shrink
useProguard true // obfuscate
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
Before you start adding any ProGuard rules, you should also check whether any of the libraries you use already come packaged with a consumer-proguard-rules.pro
file. This file gets added to the ProGuard definition list automatically. For instance, for the LeakCanary project, the definition listings are located here and added whenever you use this library with ProGuard enabled.
In addition, you can either check the GitHub source to see if this file exists, or you can navigate through Android Studio by clicking on the Project
tab and navigating to app
-> build
-> intermediates
-> exploded-aar
and looking for the proguard.txt
definition.
One limitation in ProGuard is that dynamically generated classes such as those used in Butterknife, Otto, or Dagger 2 need to be explicitly declared. In many cases, compilation will not continue until these issues are resolved. In other cases, if you do not specify it, ProGuard will often strip these methods from being used and your app will often crash at run-time.
See this link for the standard set of library configs. It's important to check the documentation of each third-party library to see the most updated settings. You can often try to experiment too by incrementally adding the necessary lines to best understand the impact of each line configuration.
Here is an example of some of the ProGuard definitions for various popular libraries.
Note: The following ProGuard lines apply to ButterKnife v7.0. If you are using an older version of ButterKnife, the Proguard rules may be slightly different.
-keep class butterknife.** { *; }
-dontwarn butterknife.internal.**
-keep class **$$ViewBinder { *; }
-keepclasseswithmembernames class * {
@butterknife.* <fields>;
}
-keepclasseswithmembernames class * {
@butterknife.* <methods>;
}
-dontwarn retrofit.**
-keep class retrofit.** { *; }
-keepattributes Signature
-keepattributes Exceptions
-keepattributes Signature
-keepattributes *Annotation*
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okhttp3.**
-dontnote okhttp3.**
# Okio
-keep class sun.misc.Unsafe { *; }
-dontwarn java.nio.file.*
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }
-keep interface org.parceler.Parcel
-keep @org.parceler.Parcel class * { *; }
-keep class **$$Parcelable { *; }
-dontwarn java.lang.invoke.*
If you plan on enabling code obfuscation by removing the dontobfuscate
line, make sure to check for any third-party libraries that may be performing reflection such as RxJava 1 and Gson. The classes that depend on reflection cannot be renamed because of the intrinsic need to inspect the classes. See this link for the rules that should be used for RxJava.
If you are planning to enable code obfuscation for Gson, make sure to avoid obfuscating the field names:
-keepclassmembers class com.codepath.models** { <fields>; }
If you wish to confirm whether ProGuard is preserving certain annotations or classes, you can review the .apk
package that gets created to check. The first step is to download the dex2jar program and use it to decompile the Dalvik code (.dex
file) to a Java archive file (.jar
file).
wget http://sourceforge.net/projects/dex2jar/files/dex2jar-2.0.zip/download -O dex2jar-2.0.zip
unzip dex2jar-2.0.zip
chmod u+x dex2jar-2.0/*.sh
./d2j-dex2jar.sh <.apk file>
You can also use d2j-dex2jar.bat
if using a Windows machine:
d2j-dex2jar.bat <.apk file>
Running the dex2jar
file directly on an APK file should convert it to a .jar
file. You can download JD-GUI and open this newly created file to review the Java class files. The UI allows you to double-check whether certain annotations were removed and whether certain classes were kept in the final compilation.
Since Android Studio 3.0 release there is an APK Analyzer tool which can view dex files and also helps to debug Proguard related changes. See here for more details https://developer.android.com/studio/build/apk-analyzer.html