Sitemap
Jayant Kumar🇮🇳

Jayant Kumar🇮🇳

Jayant Kumar is a Lead Software Engineer, passionate about building modern Android applications. He shares his expertise in Kotlin, Android, and Compose.

Protect your APK. Optimize with confidence.

Write Proguard Rules For Your Android App

Learn how to write effective ProGuard rules, avoid crashes in release builds, and keep your Jetpack Compose + Hilt + Retrofit app secure, optimized, and lean.

5 min readJul 29, 2025

--

Press enter or click to view image in full size
Photo by Antoine PlĂĽss on Unsplash

Not a Medium Member?

When you build your app for (the version you upload to Play Store), Android tries to using a tool called (which includes ProGuard features).

So what does it do?

R8 (ProGuard) performs three main tasks:

1). Shrinking

It removes — classes, functions, and libraries that your app doesn’t use.

You include a library with 100 functions but only use 5.
R8 deletes the unused 95 functions to reduce APK size.

2). Obfuscation

It renames your class and method names to make them unreadable.

Example:
Your code:

class LoginManager {
fun authenticateUser() { ... }
}

After obfuscation:

class a {
fun b() { ... }
}

This makes it to reverse-engineer your app.

It only renames those classes and function which known at compile time

3). Optimization

It rewrites parts of your code to run faster and better.

When you open your , you will see

    release {
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}

This line (Gradle) to include when building your app’s :

1). getDefaultProguardFile(“proguard-android-optimize.txt”)

This is a (Google).
It contains a set of for Android apps.

  • Basic shrinking (removing unused code)
  • Safe obfuscation (renaming classes/methods)
  • Some performance optimizations

This is like a of rules. Google maintains this so you don’t have to write everything yourself.

2). "proguard-rules.pro"

This is — the one where .

Because the default file:

So, you use proguard-rules.pro to say things like:

# Don’t remove this model — it’s used with Gson
-keep class com.myapp.models.** { *; }

# Don’t obfuscate these methods
-keepclassmembers class * {
@com.google.gson.annotations.SerializedName <fields>;
}

By default this file (proguard-rules.pro) is empty.

When You NEED to write ProGuard rules :

Before writing for your code , you have to enable isMinifyEnable = true in file.

buildTypes {
release {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}

Now you have to write for your code , there is no choice, otherwise release build can crash at run time.

1. You’re using Reflection (Gson, Moshi, Firebase, Retrofit, etc.)

Reflection means something in your code is being accessed by name — not directly through code.

Get Jayant Kumar🇮🇳’s stories in your inbox

Join Medium for free to get updates from this writer.

: Gson needs model class names and fields to be untouched so it can serialize/deserialize properly.

# Keep all models used with Gson
-keep class com.example.model.** { *; }
-keepclassmembers class * {
@com.google.gson.annotations.SerializedName <fields>;
}

2. You’re using Dependency Injection frameworks (like Hilt or Dagger)

These frameworks generate code and reference classes via annotations — so if ProGuard removes or renames them, it breaks.

# Keep Hilt-related classes
-keep class dagger.hilt.** { *; }
-keep class javax.inject.** { *; }
-keep class com.google.dagger.** { *; }
-dontwarn dagger.**

3. You’re using Jetpack Compose

Compose uses a lot of compiler-generated classes and annotations.

Jetpack Compose is mostly ProGuard-safe by default, but:

  • If you use reflection (e.g., with @Preview or libraries that inspect Compose code)
  • Or you’re using rememberSaveable with custom types

Then you may need to .

# Keep all Compose-related classes (mostly safe)
-keep class androidx.compose.** { *; }
-dontwarn androidx.compose.**

4. You’re using Room (or other annotation processors)

Room generates code based on annotations. You must keep entities and DAOs.

# Keep Room entities and DAOs
-keep class androidx.room.** { *; }
-keep @androidx.room.* class * {*;}
-dontwarn androidx.room.**

5. You’re using External SDKs or Libraries

Some SDKs (like Firebase, Facebook SDK, etc.) require you to add special rules. If you don’t, the app may crash or fail silently.

Always check the library’s documentation for required ProGuard rules.

6. You’re using reflection manually

If you’re calling things like:

val clazz = Class.forName("com.example.SomeClass")

You need to SomeClass or ProGuard will remove or rename it.

What Happens if You Don’t Write Any Rules?

When you enable isMinifyEnabled = true in file , ProGuard (or R8, more precisely) tries to:

It if a class is being used , annotations, or (like Hilt, Room, Compose, etc.).

So if it sees:

val user = User() // used normally

ProGuard says: “Cool, keep this.”

But if it doesn’t see direct usage (for example, User is accessed via reflection or annotation):

val user = Gson().fromJson(json, User::class.java)

ProGuard says: “Hmm… looks unused. Let me remove or rename it.”


Usually , which is very hard to debug.

proguard-rules.pro for Jetpack Compose + Hilt + Retrofit + Room + Gson

# ----------- KEEP ANNOTATIONS (Compose, Hilt, etc.) -----------
-keepattributes *Annotation*, InnerClasses, Signature, EnclosingMethod

# ----------- KEEP Jetpack Compose -----------
# Compose compiler generates synthetic methods that shouldn't be stripped
-keep class androidx.compose.** { *; }
-dontwarn androidx.compose.**

# ----------- KEEP Hilt / Dagger -----------
-keep class dagger.hilt.** { *; }
-keep class javax.inject.** { *; }
-keep class dagger.internal.** { *; }
-dontwarn dagger.hilt.**
-dontwarn javax.inject.**

# Keep generated Hilt classes
-keep class * extends dagger.hilt.internal.GeneratedComponent { *; }
-keep class * implements dagger.hilt.internal.GeneratedComponent { *; }

# Don't strip metadata used for dependency injection
-keepclassmembers class ** {
@dagger.** <fields>;
@dagger.** <methods>;
}

# ----------- KEEP Retrofit -----------
# Retrofit uses reflection to call APIs
-keep interface retrofit2.** { *; }
-keep class retrofit2.** { *; }
-dontwarn retrofit2.**

# Keep your Retrofit API interfaces
-keep class com.yourpackage.api.** { *; } # <-- Change to match your API package

# ----------- KEEP Gson Models -----------
# Gson uses reflection for serialization/deserialization
-keep class com.yourpackage.model.** { *; } # <-- Replace with your models package
-keepclassmembers class com.yourpackage.model.** {
<fields>;
}

# Optional: prevent Gson from removing field names
-keepattributes Signature
-keepattributes *Annotation*

# ----------- KEEP Room -----------
-keep class androidx.room.** { *; }
-dontwarn androidx.room.**

# Room uses annotations for entity/schema info
-keepclassmembers class * {
@androidx.room.* <methods>;
@androidx.room.* <fields>;
}

# ----------- AndroidX Core (Optional) -----------
-dontwarn androidx.**
-keep class androidx.** { *; }

# ----------- General Safe Settings -----------
-dontwarn kotlin.**
-dontwarn org.jetbrains.annotations.**
-keep class kotlin.Metadata { *; }

# ----------- Optional: Keep ViewModel / SavedState Handles -----------
-keep class com.yourpackage.viewmodel.** { *; } # <-- Replace with your ViewModel package
-keepclassmembers class * extends androidx.lifecycle.ViewModel {
<init>();
}

Conclusion

Test your release build after enabling minification. If anything crashes mysteriously, it’s likely a ProGuard/R8 issue — check logs for missing classes or methods and add rules accordingly.

--

--

Jayant Kumar🇮🇳
Jayant Kumar🇮🇳

Written by Jayant Kumar🇮🇳

Jayant Kumar is a Lead Software Engineer, passionate about building modern Android applications. He shares his expertise in Kotlin, Android, and Compose.