Reducing APK size using R8 and ProGuard

  • Implementation of R8 and ProGuard for dead code removal and class obfuscation.
  • Using Android App Bundles to optimize resource delivery based on the user's device.
  • Replacing heavyweight assets with efficient formats such as WebP and Vector Drawables.
  • Configuration of dynamic modules to download functionalities on demand.

Reducing APK size using R8 and ProGuard

As our apps add features and become more complex, it's quite common for the final file size to increase significantly. This is a serious problem because if an app is too large, many users think twice before clicking the install button or, even worse, abandon the download halfway through. Furthermore, a large app consumes more storage space on the phone and can ultimately affect the system's responsiveness.

To prevent your project from becoming a digital behemoth, there are several strategies, ranging from code cleanup to image optimization. In this article, we'll delve into how to use tools like R8 and ProGuard , as well as the magic of App Bundles, to make your app as lightweight and fast as possible, ensuring it runs flawlessly even on low-end devices.

Understanding what really matters in your app

Before we get started, we need to know where the bulk of the data is. An application's size is typically divided into four main blocks. First, there's the Java or Kotlin bytecode and its libraries, which usually account for 30% to 40%. Then there are resources like layouts and animations , with a similar size. We also have the native libraries (C/C++) compiled for different architectures (15-25%), and finally, the assets or raw files (5-15%).

To avoid guesswork, it's best to use Android Studio's APK Analyzer (by going to Build > Analyze APK). This tool lets you see exactly how much DEX classes, the resource folder, and native libraries weigh, allowing you to compare current versions with previous ones to pinpoint what changes caused the file size increase. To delve deeper into this topic, it's helpful to understand the file hierarchy in Android and how files are organized.

Code cleanup: The leap from ProGuard to R8

Code reduction is undoubtedly the most effective way to cut bytes. This is where ProGuard and its modern successor, R8, come in. ProGuard was the standard for years, taking care of removing unused classes, fields, and methods , optimizing bytecode, and obfuscating names to make them shorter (and harder for anyone trying to hack your code to read).

APK, AAB and APKM
Related article:
Advanced Guide to the Differences Between APK, AAB, and APKM Formats on Android: Everything You Need to Know to Install Apps Like a Pro

Today, R8 is the default compiler and does everything ProGuard did, but much better and faster. R8 implements more aggressive tree shaking , merges classes with similar functions, and optimizes enumerations by converting them to integers. Furthermore, it allows desugaring to use modern Java 8 functions in older versions of Android.

Technical configuration in build.gradle

To activate these optimizations in the release version, you must configure the build file by setting minifyEnabled as true and linking the rule files. It is essential to use proguard-android-optimize.txt to take full advantage of the optimizations. A basic configuration example would include maintain application classes or those noted with @Keep to prevent R8 from accidentally deleting them.

Rule management for external libraries

Sometimes, R8 is too efficient and deletes code used through reflection, causing errors such as ClassNotFoundExceptionThat's why bookstores like Retrofit, OkHttp, or Gson require specific rules.For example, with Gson it's vital to preserve the field names in the data models so that JSON deserialization doesn't fail. If you encounter errors after obfuscation, the file mapping.txt It is your best ally for translating stack traces and knowing where the failure occurred.

Is it possible to create an APK without being a programmer?
Related article:
Differences between APKM, APKS, and XAPK: Complete guide to Android installation formats

Intelligent resource optimization

Resources are often where the most space is wasted. A simple but powerful technique is to activate shrinkResources in the build.gradle file. This removes files that have no reference in the code, although it's important to know that if you call a resource dynamically using getIdentifierYou will need to declare it in a file keep.xml so that it doesn't disappear.

Images and Graphics: Less is More

The PNG format is responsible for many unnecessary megabytes. The current recommendation is to migrate everything to WebP format , which offers far superior compression while maintaining quality. You can perform this conversion directly in Android Studio by right-clicking on the image. For icons and simple shapes, Vector Drawables are ideal ; a single XML file replaces five versions of varying densities, simplifying maintenance and reducing file size.

Cutting down languages ​​and densities

Many external libraries come with translations into 50 languages ​​that your app probably doesn't support. To clean this up, use the property resConfigs in defaultConfigspecifying only the languages ​​you actually use (for example, "es", "en"Similarly, you can limit the included screen densities if you know your target audience uses modern devices, by removing resources ldpi or mdpi that nobody uses anymore.

Extract APK from applications
Related article:
Complete Guide to Extracting APK from Any Android App: Options, Security, and Tutorials

Advanced Distribution Strategies

If you want to definitively reduce APK size, you should stop using universal APKs and switch to Android App Bundles (.aab) . Instead of sending one giant file with everything possible, Google Play generates an optimized APK for each device. This way, a user with an ARM64 phone and an xxhdpi screen downloads only what their hardware needs , reducing the download size by up to 40%.

Dynamic Function Modules and Instant Apps

Not all the code needs to be available from the start. With Dynamic Feature Modules , you can separate parts of the app (like an advanced photo editor or offline mode) so they're downloaded only when the user accesses that feature. On the other hand, Instant Apps let people try your app without installing it, by loading an extremely lightweight base module via URL or Google Play button.

Audit of dependencies and final details

Sometimes the problem isn't your code, but what you're bringing in from outside. Libraries like Guava or Jackson can be very large; consider replacing them with lighter alternatives like kotlinx.serialization or Gson . It's also advisable to use downloadable fonts from Google Fonts instead of bundling large TTF files in your assets, which can save you several megabytes if you use multiple variations of a font.

To complete the optimization cycle, remember that Android Go is a growing market. If you want your app to shine on devices with less than 1GB of RAM, try to keep its size below 40MB. Using Android Lint to detect orphaned resources and maintaining a consistent cleanup routine will allow your app to be efficient, install quickly, and offer a smooth user experience, regardless of the device's power.

Android security updates
Related article:
How to speed up and optimize Android to the max: complete guide, tips, and essential recommendations

Add as preferred source in Google