A Study of R8 Modes and Their Impact on Android Applications
A Study of R8 Modes and Their Impact on Android Applications
R8 is the default code shrinker, optimizer, and obfuscator for Android applications. It plays a crucial role in reducing APK size and improving runtime performance. While R8 is designed to be a drop-in replacement for ProGuard, its more advanced optimizations can introduce subtle behavioral changes. To manage this, R8 operates in two distinct modes: compatibility mode and full mode.
This study will explore the differences between these two modes, with a particular focus on the aggressive optimizations of "full mode" and the necessary configuration adjustments developers must make, especially when working with reflection-heavy libraries like Gson and Retrofit.
R8 Compatibility Mode: The Safe Default
By default, the Android Gradle Plugin runs R8 in compatibility mode. This mode is designed to provide a seamless transition from ProGuard. It applies a conservative set of optimizations, intentionally disabling some of R8's more aggressive features to minimize the risk of breaking existing ProGuard configurations. The primary goal of this mode is to ensure that code that worked with ProGuard continues to work with R8 with minimal changes, providing immediate benefits like better performance and smaller code size without a steep learning curve.
R8 Full Mode: Aggressive Optimization
For developers seeking the maximum benefit from R8, full mode can be enabled by adding android.enableR8.fullMode=true to the gradle.properties file. This mode unlocks R8's most powerful optimizations, but it also makes fewer assumptions about how the code will be used at runtime. This can lead to smaller and faster apps, but it often requires more explicit and precise -keep rules because R8 will remove anything it cannot prove is being used.
This article continues for subscribers
Subscribe to Dove Letter for full access to 40+ deep-dive articles about Android and Kotlin development.
Become a Sponsor