Enable ProGuard for Android Project
Lately we have to deal with Android 65k method limit, so enabling ProGuard to remove some unreferenced methods might be a good way to temporarily solve this problem.
Enable ProGuard
It's really easy to enable ProGuard. If using Maven, just add the following code in your pom file under Android Maven Plugin's configuration:
<proguard>
<skip>false<skip>
<config>proguard-project.txt</config>
</proguard>
proguard-project.txt
is the configuration file for ProGuard. I'll explain it later. If using Gradle as your build system, just add following code in buildTypes
1:
runProguard true
proguardFiles file('proguard-project.txt')
After enabling ProGuard, whenever the project is built, ProGuard will generate several text files: dumpt.txt, mapping.txt, seeds.txt and usage.txt.
- dump.txt: Internal structure of all the classes in the final .apk.
- mapping.txt: If obfuscation is enabled( by default it is), this file will list the mapping between original classes/methods/fields name and obfuscated one.
- seeds.txt: Lists classes and members are not obfuscated.
- usage.txt: Lists all the code removed from the final .apk.
- Warning: can’t find superclass/interface/referenced class: Generally, this might be the first or the only warnings you would encounter. The reason why this warning happens is really simple: some jars are missing, so you need to specify the locations of those jars. But for an Android project, in most cases just use
-dontwarn
to turn off those warnings because during Android build process, it will automatically feed you all referenced jars. -dontobfuscate
: I just don't feel the need for code obfuscation yet. And it will make debug a little bit harder. ProGuard will generate a mapping file between original class names and obfuscated ones. By using retrace tools, it will make life easire. I am sure there's an automated way to do that. For Crashlytics, it supports reading the mapping file, so you don't need the extra step to using the retace tool.- Automated Instrumentation Testing: If the Android project has some instrumentation tests,
-keep public class * extends android.app.Application
is a must. There will be an class generated extendsandroid.app.Application
class for each test project but only referenced in AndroidManifest.xml, so ProGuard just thinks that Application class is unreferenced. Lost a whole day of productivity because of this. :-( - Play Services: This gigantic library contains about 20k-30k methods. Even though it's generally considered a must-have in Android development, lots of classes/methods might just sit there doing nothing. Google has its own recommended configuration for this library. Just include those rules. Good news is, the next release of Play Services, v6.5, will be modularized.
- Reflection: Anything using reflection should be kept.
method reference index
. It defines the maximum methods you can invoke. Unfortunately, the size of that variable has never changed since the birth of Android, and it's a 16 bit integer, 65536. Except using ProGuard to get around this problem, another popular solution is using multi-dex.
Multi-dex
Mobile app is really a thing now, there still might be a chance your project references more than 65536 methods even after ProGuard is enabled. Some guys come up with an idea: compile code to multiple dex files, one of those is the primary, custom loading dex files when needed. Well, before ART is released, the new runtime for Android, this is very cumbersome, inefficient and error prone. As ART is released alone with Lollipop, multi-dex gets native support. Multiple dex files will be compiled to one .oat file, executable for ART. For pre-ART Android, Google also has a support library for that. More details for setting it up could be found here: Configuring Your App for Multidex with Gradle. It seems solved the problem a bit nicer, but still there are several limitations, like doesn't work well for pre-4.0 devices, adds compiling overhead, etc.
The real problem for 65k looks very simple though. It might just be a really hard bug for Google to fix. On the other hand, mobile apps are doing more and more things, there should be a perfect solution for this.
- There are other ways to configure ProGuard for Gradle.
getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'
looks neat. First find the default configuration file from Android SDK then merge it with your project specific config. This is something Android Maven Plugin cannot do yet.