Mastering R8 Optimization: Beyond the Defaults in AGP 8.8
With the introduction of the Android Gradle Plugin (AGP) 8.8 and modern R8 releases, shrinking and optimizing Android apps has reached a new level of precision. R8 is no longer just a ProGuard replacement that renames classes to a, b, and c. It is an advanced compiler optimization toolchain that does dead-code elimination, member inlining, outline sharing, and devirtualization.
However, standard out-of-the-box configurations only scratch the surface. To truly minimize your APK size and maximize runtime execution speed, you must configure R8’s advanced parameters.
In this guide, we dive deep into advanced Keep Rules, optimization controls, and how to verify R8 output using compile tools.
1. Unleashing R8 Full Mode
R8 is run by default in a compatibility mode that preserves historical (and often bloated) ProGuard behaviors. To enable the aggressive optimizations, configure your project for R8 Full Mode in gradle.properties:
# Force R8 Full Mode for maximum size reduction
android.enableR8.fullMode=true
In Full Mode, R8 removes unused interface parameters, simplifies class hierarchies, and aggressively inlines methods that are only called once. This can shrink your app size by an additional 10–20% compared to compatibility mode.
2. Refining Keep Rules to Prevent Bloat
The most common mistake developers make is writing wildcard keep rules like -keep class com.portfolio.network.** { *; }. This disables optimization for the entire package.
Instead, use target-specific qualifiers:
# Keep ONLY classes implementing serialization but allow renaming of unused methods
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
}
If you use libraries like Moshi, Gson, or KotlinX Serialization, use their compiler plugins which automatically generate optimal Keep Rules under the hood, instead of relying on broad manual rules.
3. Demystifying Outline Sharing
One of R8’s most advanced optimizations is Outline Sharing. When R8 finds identical instruction sequences across different methods in your app, it extracts those instructions into a single helper method and replaces the original sequences with calls to that helper.
This optimization is enabled automatically, but you can control it or disable it for debug builds to speed up compilation:
# Enable outline sharing for release builds only
android.enableR8.outlineSharing=true
4. Analyzing R8 Output with APK Analyzer
After compiling a release build, never upload it blindly. Use Android Studio’s built-in APK Analyzer to inspect the classes.dex files. Check for:
- Classes that should have been removed: Verify if legacy libraries or test packages are still packaged.
- Method counts: Ensure method counts are under the 64k limit to prevent multi-dex overhead where possible.
- Resource Shrinking: Ensure
shrinkResources trueis configured in your build configuration to remove unused assets (like unreferenced layout files and images).
android {
buildTypes {
release {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
}
By fine-tuning R8, you don’t just ship a smaller APK; you improve CPU cache efficiency and speed up app execution on low-end devices.