Very basics of proguard (for android)

I very rarely need to touch pro guard rules so when I do I always struggle with the most basics. Here’s my reference guide to quickly get back up to speed.

Proguard

Proguard is a tool used to shrink and obfuscate code. The two most basic ways it achieves this are removing unused code and renaming classes and methods.

Note: modern android actually uses a tool called R8 under the hood to do the shrinking/obfuscation but R8 still relies on and is configured by the same proguard files which is why we still have files like proguard-rules.pro in our android projects.

Enabling Proguard

To enable code shrinking and obfuscation (and other R8 code optimisations) we set the minifyEnabled flag to true in you app modules build.gradle file.

android {
    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            ...
        }
    }
    ...
}Code language: JavaScript (javascript)

In most cases when you see minifyEnabled true you will also see shrinkResources true. When shrink resources is set the build process will remove all unused resources from the project (eg images or strings) which also helps reduce the app size.

The proguardFiles line tells proguard/R8 where to find the configuration settings.
The first part, getDefaultProguardFile'proguard-android-optimize.txt') is the default android configuration that contains rules every android project needs such as ensuring no activity or classes referenced from xml get removed.
The second part, 'proguard-rules.pro' is the configuration file specific to our project and is where you would add any custom rules you require for your project. Note that you can change the file name to anything you want so long as it matches what you specify here.

Proguard -keep rules

Proguard removes classes and members that aren’t used in order to shrink the app size but it doesn’t understand every scenario so sometimes we have to specify rules to ensure proguard doesn’t remove or obfuscate classes and members we need. For example when using gson to serialise json we need to keep the field names of our models because gson is using those names for the field names in json.

Here are the basic keep rules you’re likely to see and use in your proguard-rules.pro files.
First the most basic keep rule

-keep class com.example.MyClassCode language: Gradle (gradle)

Keeps (doesn’t remove or rename) the class MyClass.


-keep class com.example.MyClass {*;}Code language: Gradle (gradle)

Keeps the class and all members (fields/methods etc).


-keep com.example.* {*;}Code language: Gradle (gradle)

Keeps all classes and their members that are in the com.example directory. I.e. will keep com.example.MyClass but will not keep com.example.models.MyModelClass because that is in a sub directory.


-keep com.example.** {*;}Code language: Gradle (gradle)

Keeps all classes and their members in the com.example package and all sub directories. So in this case both com.example.MyClass and com.example.models.MyModelClass will be kept.

Note: Be careful using such a broad rule as this because you loose the whole advantage of using proguard.


There is a lot more you can do with proguard, e.g. -keepClassMembers, -keepNames or keeping classes that contain a particular method signature. See the references at the bottom of the page for some good places to get started with understanding these more advanced features.

Proguard with modules

When you create a separate module (android library) in your project you should place your pro guard rules in the consumer pro guard file, by default called consumer-rules.pro. These consumer rules get automatically applied when the consuming application performs the proguard step during build, the consuming application being your app module and potentially multiple different apps. By using proguard in this way it will be able to remove any classes in the module that aren’t used by the app being built (whereas if we used the normal proguard file we would have to keep all classes because we don’t know which ones are used by the app).

To use this file you need to add consumerProguardFiles "consumer-rules.pro" to your separate modules build.gradle file. consumer-rules.pro is the default filename but you can specify any name so long as the file matches what’s set for consumerProguardFiles.
You should also disable the standard proguard rules by ensuring minifyEnabled = false in the separate modules build.gradle file. These setup steps are already done for you when creating a separate android library module in android studio.

Proguard with libraries

When including a new dependency in your project you should check if they specify any proguard rules that you need to add. Often this won’t be necessary but when it is the required proguard rules are usually included in the setup steps in their readme, e.g. for retrofit

Debugging Proguard issues

Using proguard takes a long time in the build process so in a standard android project it is used for production builds only and not applied to debug builds. In order to test and debug with the full proguard rules applied it is useful to setup a new debug build variant that matches what is applied to the production variant. e.g. in build.gradle of your app module:

buildTypes {
  debugMinified {
    initWith debug
    minifyEnabled true
    shrinkResources true
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    matchingFallbacks = ['debug']
  }
}Code language: Gradle (gradle)

De-obfuscation files

If you start seeing crazy stack traces in crash reports such as lc.f$c.i(MyClass.kt:797) and your MyClass file only has 132 lines it’s because proguard has obfuscated your files. In order to get a readable stack trace you need to upload the proguard mapping file to google play. These files tell the play store how to decode the crazy names in the stack trace back to their original names so you can track down that pesky crash.
To learn how to upload mapping files see https://support.google.com/googleplay/android-developer/answer/9848633?hl=en


References

Proguard tips and examples: https://medium.com/androiddevelopers/practical-proguard-rules-examples-5640a3907dc9

Different keep options: https://jebware.com/blog/?p=418

Consumer-rules: https://medium.com/android-news/proguard-r8-in-the-world-of-modularity-f599650b4553

Android code shrinking documentation: https://developer.android.com/studio/build/shrink-code


I don’t use comments on my site but you can reply on Mastodon: https://fosstodon.org/@MonkeyMatt/109397496304875562