Skip to content
advanced Phase 12 · Security

ProGuard / R8

Obfuscate and optimize code with R8. Write ProGuard rules for libraries and reflection.

40m
0 problems
Topic Progress 0%

ProGuard vs R8

What Is Code Shrinking?

When you build a release APK, the build tool processes your code to:

  1. Shrink — Remove unused classes, methods, and fields from dependencies
  2. Obfuscate — Rename classes and methods to meaningless short names
  3. Optimize — Apply bytecode optimizations like inlining and dead code elimination

This reduces your app's final size and makes reverse engineering harder.

ProGuard vs R8

Feature ProGuard R8
Maintained by Guardsquare (open source) Google (built into AGP)
Speed Slower Faster (15-20% build speedup)
Default since N/A AGP 3.4+
Optimization Good Improved (better inlining)

Since Android Gradle Plugin 3.4, R8 is the default. Your proguard-rules.pro file works with R8 without changes.

Build Configuration

// app/build.gradle.kts
android {
    buildTypes {
        release {
            isMinifyEnabled = true
            isShrinkResources = true
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
}
  • isMinifyEnabled — Enables shrinking, obfuscation, and optimization
  • isShrinkResources — Removes unused resources
  • proguard-android-optimize.txt — Google's default rules with optimizations

The Mapping File

R8 generates mapping.txt in app/build/outputs/mapping/release/. Upload it to the Google Play Console or your crash reporting tool to deobfuscate stack traces.

com.example.app.User -> a.b.c:
    java.lang.String name -> a
    java.lang.String email -> b
    void login() -> c

Keep Rules and Library Configuration

Understanding Keep Rules

By default, R8 removes anything it doesn't detect as reachable from your code. If a class is accessed via reflection, serialization, or native code, R8 won't know about it and may strip or rename it. Keep rules tell R8 what to preserve.

Common Rule Syntax

# Keep a specific class and all its members
-keep class com.example.MyClass { *; }

# Keep all classes in a package
-keep class com.example.api.** { *; }

# Keep classes with a specific annotation
-keep @com.example.SerializedName class * { *; }

# Don't obfuscate (but still allow shrinking)
-dontobfuscate

Rules for Common Libraries

Retrofit:

-keepattributes Signature
-keepattributes *Annotation*
-keep class retrofit2.** { *; }
-keepclasseswithmembers class * {
    @retrofit2.http.* <methods>;
}

Gson:

-keepattributes Signature
-keepattributes *Annotation*
-keep class com.google.gson.** { *; }
-keepclassmembers class * {
    @com.google.gson.annotations.SerializedName <fields>;
}

Room:

-keep class * extends androidx.room.RoomDatabase
-keep @androidx.room.Entity class *
-keep @androidx.room.Dao class *

Debugging R8 Issues

When your app crashes in release but works in debug:

  1. Check the stack trace — Use the mapping file to deobfuscate
  2. Add the missing keep rule — Find the stripped class in build warnings
  3. Enable verbose logging — Add -verbose to proguard-rules.pro
  4. Temporary fix — Use -keep class ** { *; } to identify the problematic class

Obfuscation as a Security Layer

What Obfuscation Protects Against

Obfuscation renames classes and methods to short, meaningless names. It makes reverse engineering harder but not impossible. It protects against:

  • Casual inspection — Most attackers won't bother reading obfuscated code
  • Automated tools — Generic decompilers produce unreadable output
  • IP theft — Proprietary algorithms and business logic are harder to extract

What Obfuscation Does NOT Protect Against

  • Determined attackers with time and motivation
  • Runtime analysis and dynamic instrumentation
  • Network traffic interception (use certificate pinning instead)
  • Data stored in plaintext (use encryption instead)

Additional Security Measures

# Remove logging in release builds
-assumenosideeffects class android.util.Log {
    public static int v(...);
    public static int d(...);
    public static int i(...);
}

This strips Log statements from your release APK, preventing information leakage.

Best Practices

  1. Always enable minification for release builds — No exceptions
  2. Upload the mapping file to your crash reporting tool
  3. Test release builds regularly — Don't wait until launch to discover R8 issues
  4. Keep rules are additive — Library dependencies contribute their own rules automatically
  5. Use -keep sparingly — Over-keeping defeats the purpose of shrinking

Quiz

1. Since which Android Gradle Plugin version is R8 the default code shrinker?

Question 1 options

2. Why does a class accessed via reflection crash in release builds but not debug?

Question 2 options

3. What does -assumenosideeffects do in a ProGuard/R8 rules file?

Question 3 options

4. Where does R8 generate the mapping file for deobfuscation?

Question 4 options

Flashcards

Question

What are the three main tasks R8 performs on your code?

Answer

Shrinking (removing unused code), obfuscation (renaming to short names), and optimization (inlining, dead code elimination).

Question

Why do libraries like Gson and Retrofit need keep rules?

Answer

They use reflection, annotations, and dynamic proxies at runtime. R8 static analysis cannot detect these accesses, so keep rules are needed to prevent stripping or renaming.

Question

What is the mapping file used for?

Answer

It maps obfuscated class and method names back to their original names, enabling deobfuscation of stack traces from crash reports in release builds.

Question

What does isShrinkResources do in build.gradle?

Answer

Removes unused resources (images, strings, layouts) from the final APK, further reducing app size beyond code shrinking alone.

Revision Notes

Key Takeaways

  • 1. R8 is the default code shrinker since AGP 3.4, fully compatible with ProGuard rules
  • 2. Always enable isMinifyEnabled for release builds to shrink and obfuscate code
  • 3. Libraries using reflection (Gson, Retrofit, Room) need keep rules to survive R8
  • 4. Upload the mapping file to deobfuscate crash reports from release builds
  • 5. Strip logging statements in release builds to prevent information leakage

Interview Tips

  • Explain the difference between shrinking, obfuscation, and optimization
  • Know why reflection-based libraries need keep rules
  • Be ready to debug R8 crashes using the mapping file
  • Discuss why obfuscation is a defense layer, not a security solution

Cheat Sheet

ProGuard / R8 Cheat Sheet

R8 is default since AGP 3.4 — Drop-in replacement for ProGuard.

Build Config:

  • isMinifyEnabled = true (shrinking + obfuscation)
  • isShrinkResources = true (unused resource removal)
  • proguard-android-optimize.txt (default rules)

Keep Rules:

  • -keep class X { *; } — preserve class and members
  • -keep class X.** — preserve package recursively
  • -keep @Annotation class * — keep annotated classes
  • -dontobfuscate — disable renaming only

Common Library Rules:

  • Retrofit: keep @retrofit2.http methods + Signature
  • Gson: keep @SerializedName fields + Signature
  • Room: keep Entity, Dao, RoomDatabase subclasses

Debugging:

  • mapping.txt in build/outputs/mapping/release/
  • Upload to crash reporter and Play Console
  • Strip logs with -assumenosideeffects

Security:

  • Strip Log.v/d/i in release builds
  • Obfuscation is not encryption — layer with encryption