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.
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
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.
There are two recommended configuration files for Android project from Google. They are located in tools/proguard under Android SDK directory. I would pick the one without optimization becasue I am not so sure about what kind of optimization ProGuard will do. Full usage of ProGuard can be found here. Here are several rules I used.
- 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
-dontwarnto turn off those warnings because during Android build process, it will automatically feed you all referenced jars.
-dontobfuscate: Obfuscation will make debug harder. Even using ProGuard just for release builds, if Crashlytics is enabled, the stack trace you get from crash report is obfuscated as well. If your app is really security sensitive, i mean, obfuscation is truely a necessity, there are some workarounds to solve the problem, like using retrace tools, Crashlytics Maven plugins.
- Automated Instrumentation Testing: If the Android project has some instrumentation tests,
-keep public class * extends android.app.Applicationis a must. There will be an class generated extends
android.app.Applicationclass 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.
So what is Android 65k problem exactly? Davlik is the rumtime of Android. Its instruction set has a variable called
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.
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.