Key Thing to remember while working with R8 & Proguard

Abhishek Mishra
4 min readSep 10, 2022

--

Hey 👋🏻, This article will explain how to compress your Android app (using R8) and the unique issue caused while using it.

Here’s why you should shrink your app:

Each application is made for a target user. One factor that stands out for an application is how quickly can we download the application (including how better is the User Interface and how smooth the user interactions, also known as UI and UX).

It’s also mentioned by google play in their documentation.

The snippet is taken from Google Play documentation

There are a number of factors that contribute to an application’s apk size.
Like assets, the lines of code in the application. In order to decrease the apk size, there are a number of things that need to be optimised.

More details can be found in the official documentation.

Why is R8 important?

For every android project, there are two build Types by default — Debug & Release.

Debug as the name suggest is used on staging (local environment) to develop and test features/code.

In the case of Release, this is the app that’s created after providing a signing config to android studio. (We generally create this build when we are planning to release the application on the play store or any other similar options. More Details )

By default, there’s a key minifyEnabled present under the release BuildType in build.gradle. (Learn more about minifyEnabled and shrinkResources — Reference)

This key is responsible for enabling the R8 in your android project to compress the size of the build generated, in many already written projects this is enabled to decrease the app size.

The Unique bug I encountered while working on a project with R8 enabled.

Reason for the bug — I was working on a project that already had R8 enabled since I had no context/knowledge about R8 at that time I had no clue about this bug occurring in production.

The task I was given — Converting a JSON String (which was a list of JSON Objects) into a data class and displaying the result into a recycler view using an adapter.

I followed this path to complete the same —

  • Created the data class. (didn’t add the “@keep annotation”. More details are below)
  • Created the adapter
  • Wrote the code snippet to convert the JSON string into a data class.

Unique issue — “Since the class object was not null in any of the objects in the list, the adapter was expecting a not null class object. Surprisingly the adapter crashed and gave a NullPointerException while testing in the production environment.”

A small example demonstrating the same —

Code for MainActivity

Case 1 — Not adding “@keep” notation on data class

Data Class
Output

Case 2 — Adding “@keep” notation on data class

Data Class with @keep
Logcat output after using @keep

After enabling debugging in the release build (Reference), I came across the use case of android studio telling that the class object won’t be null and the stack trace displaying it as null.

Data Class’s Nature

The reason is:

R8 uses the following process that it follows under the hood to reduce the size of your application. (More Details)

Details of methods performed by R8

How R8 Decides which piece of code is useful?

  • It detects all the entry points in your application (Activities, Services, Content provider, Broadcast Receivers).
  • From these points, builds a graph that links all the code that is reachable during runtime, if any piece of code isn’t a part of this graph it’s removed
  • Due to this graph, a number of times useful code for the application are also removed, To control which part of code we want to save. We have ProGuard. It enables us to specify a configuration to R8.
  • “proguard-rules.pro” in your project directory is the file that tells R8 about what part of the code needs to be kept while performing the above steps.

Here’s how to fix it:

To make R8 retain your class object while decreasing the size, there are these alternatives —

  • Add “@Keep” notation to the class.
  • Add the keep class rule in proguard-rules.pro.
  • In case you want to save all the classes add the package name in proguard-rules.pro

Key Takeaway:

Remember to add your newly added class in proguard-rules.pro to avoid unexpected NullPointerExceptions in the production environment.

This was my learning from using Proguard, and how understanding it’s working reduces the chances of encountering unexpected code crashes in release builds.

If you liked this blog, hit the đź‘Ź . Stay tuned for the next one!

--

--

Abhishek Mishra
Abhishek Mishra

Responses (1)