R8 is the default code shrinker for Android. It runs automatically when you enable:
minifyEnabled true1️⃣ Shrinking → Removes unused classes, functions, resources 2️⃣ Obfuscation → Renames classes & methods → makes hacking harder 3️⃣ Optimization → Inlines code, removes dead code, improves performance
It replaces ProGuard completely since 2019 (Android Gradle Plugin 3.4+).
ProGuard is the old shrinker used before R8. Now it is only used for its rules file:
👉 proguard-rules.pro
Even though R8 replaced ProGuard, R8 understands and uses ProGuard rules syntax, so rules remain same.
| Feature | ProGuard | R8 |
|---|---|---|
| Shrinker | Yes | Yes |
| Optimizer | Yes | Yes (Better) |
| Obfuscator | Yes | Yes |
| Speed | ❌ Slow | ✔ Fast |
| APK Size | ❌ Larger | ✔ Much smaller |
| Default in Android? | ❌ No | ✔ Yes |
R8 = Faster, better, modern ProGuard replacement.
Your Kotlin/Java code
↓
D8 (converts to DEX)
↓
R8 (shrinks + obfuscates + optimizes)
↓
Final APK / AAB
R8 is already enabled by default. You only need to turn ON shrinking for release builds:
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}minifyEnabled true→ Turns on R8shrinkResources true→ Removes unused drawable/xmlproguardFiles→ Where you keep your keep rules
A file where you tell R8:
✔ What NOT to remove ✔ What NOT to rename ✔ What NOT to optimize
So your app won't crash.
Example location:
app/proguard-rules.pro
Because R8 removes or renames classes that reflection-based libraries need.
Example:
- Gson / Moshi
- Retrofit
- Room
- Hilt / Dagger
- WorkManager
- Firebase
- Glide / Coil
They all use reflection → R8 can’t “see” them → must protect them.
-keep class com.example.model.User { *; }-keepclassmembers class com.example.api.* {
public *;
}-keepnames class com.example.MyClass-keepclassmembers class * {
@com.google.gson.annotations.SerializedName <fields>;
}-keep class com.example.model.** { *; }
-keepclassmembers class com.example.model.** {
<fields>;
}-dontwarn okhttp3.**
-dontwarn okio.**
-dontwarn retrofit2.**
-keep class retrofit2.* { *; }
-keep class okhttp3.* { *; }-keepclassmembers class * {
@androidx.room.* <methods>;
}-keep class dagger.hilt.** { *; }
-dontwarn dagger.hilt.internal.**-keep class * extends androidx.lifecycle.ViewModel { *; }Run a release build:
Build → Generate Signed APK/AAB
Check app/build/outputs/mapping/release/mapping.txt
Inside mapping.txt:
✔ Original name → Obfuscated name ✔ You can use it to read crash logs
Your keep rules are wrong.
✔ Add rules for your models ✔ Add rules for libraries
Solution: Keep model fields
-keepclassmembers class com.example.model.** { <fields>; }Solution: Add keep rule to prevent deletion
-keep class missing.class.Name- ✔ Enable it from day 1 in your project (not at the end)
- ✔ Keep rules for each new library you add
- ✔ Always check
mapping.txton crashes - ✔ Use
shrinkResources trueto reduce APK size - ✔ Avoid over-using
dontwarn(dangerous)
-
R8 = Android’s code shrinker + obfuscator
-
Enable using →
minifyEnabled true -
Rules are written in →
proguard-rules.pro -
Used to protect:
- Models (Gson, Retrofit)
- Libraries (FCM, Hilt, Room)
- Reflection classes
-
Makes APK smaller, harder to reverse engineer, faster