We definitely have all heard from the Android community regarding the importance of using Proguard. Let's see why and how we should use Proguard while Android applications development. Many of the concerns are raised due to security aspects and performance optimizations of an Android application. An APK without proper proguard rules is susceptible to many security risks. Major risk being able to decompile and reverse engineer. After reverse engineering, many of the code resources can be accessed, hence, exposing the critical business logic and data. If appropriate proguard rules are implemented, then that makes reverse engineering really tough (but not impossible) as proguard obfuscates the code in order to decrease the readability of code. In this post, we will go through all the features and examples of proguard in detail.
Features of proguard are as follows
This step helps in reducing the size of APK. Proguard looks for all the classes and its variables, methods, etc. which are reachable. It recognizes which class members are being used and then discards all other code. Hence, removing unused code from the application. Unused code from libraries is also removed. You can use APK Analyzer tool bundled with Android Studio to check the size of the Android build before and after applying proguard rules. This will give you an idea about the proguard’s compression capabilities.
Proguard analyzes the generated bytecode and optimizes it for better performance. It removes unused instructions from the bytecode. It performs a number of peephole optimizations, removes duplicate code, Inlines short and constant methods, etc.
Preverification step doesn’t need entry points. It adds preverification information to classes which is required by certain Java versions in order to improve the startup time.
Once the unused code is removed, proguard starts obfuscating code in order to make it tough to read. During this step, all the classes, classes’ methods, variable names and other class members are renamed with random characters. That way, they can still be referenced internally but makes it tougher for a hacker to read and understand the business logic in unfortunate situations of code and resources being exposed.
Obfuscation step also leads to certain errors in the release build if not implemented properly. We will look at the potential issues and their solutions, before that let us start with its implementation.
Proguard is enabled by setting “minifyenabled” as “true” for the respective build type.
Above snippet demonstrates that proguard is enabled for development build. It is a common norm to skip proguard for development builds and use it in production, but we recommend it in the development phase as well to be sure of its implications before going production.
- “proguardFiles” attribute instructs system to look for proguard rules in these files.
- “Proguard-android.txt” is a default file provided by Android Studio which has rules for Android specific areas.
- “Proguard-rules.pro” is the file which you would generally edit. It contains custom rules for proguard to keep in mind while performing shrinking and obfuscation. It can be found at root of the module by the “build.gradle” file.
You can further shrink the code resources by incorporating “shrinkResources” as well. It removes unreferenced resources from “/res” directory after the code shrinking has been done. An updated build.gradle may look like the following:
Note: “shrinkResources” doesn’t removes files from “/values” directory
When you have applied proguard and make a clean build, following files are generated at every build:
Since the classes and its members are renamed in obfuscation step, this file provides the link between the original names and updated names. It contains translations of before and after names of classes, methods, variables, etc.
If you mention certain classes to be prevented from obfuscation, this file lists them. All the code that was skipped in obfuscation step can be found here. This file helps in checking whether the implemented rules in “proguard-rules.pro” have desired effect or not. It is considered good practice to check here rather than relying on proguard to protect important stuff.
All the unused and unreferenced code that has been removed in the shrinking step is listed here. It would make sense to check this file after implementing proguard rules to ensure that only intended parts were removed and not important. Wrong proguard configuration can lead to errors and crashes in release builds.
Explicitly keeping the coded from shrinking and obfuscation:
Generally Proguard’s default configuration is enough to judge which code to keep and which parts to discard. But, this may result in fewer errors if the code is manipulated at runtime with reflection (or introspection).
Adding a rule like following will instruct Proguard to skip the concerned part.
-keep public class MyImportantClass
If you are using an Annotation support library, then you can just annotate the class with “@Keep” and Proguard will know.
When including third party libraries in your project, you should check for “consumer-proguard-rules.pro” file. Most libraries expose their proguard rules, they are automatically read by Proguard and keeps the important parts intact while shrinking and obfuscation.
For certain libraries, you may have to explicitly mention proguard rules from keeping the build to fail. You can check following link for sample proguard configuration to be used with popular libraries.
Common configuration: https://github.com/krschultz/android-proguard-snippets/tree/master/libraries