Fixing ClassNotFoundException in Android Release Builds (R8 & ProGuard)

intermediate📱 Android2026-06-15| Android Studio, Gradle, R8/ProGuard, Release builds with isMinifyEnabled true

Error Message

java.lang.ClassNotFoundException: Didn't find class "com.example.MyClass" on path: DexPathList
#r8#proguard#android-sdk#minification#debugging

The Quick FixYour release build likely crashed because R8 stripped away code it thought was "dead," even though your app needs it at runtime for reflection or JSON parsing. To stop this, add a keep rule to your proguard-rules.pro file:

-keep class com.example.MyClass { *; }

If you have an entire package of data models (like for GSON or Moshi), keep the whole directory:

-keep class com.example.models.** { *; }

Wipe your build cache with Clean Project before building your next APK or App Bundle to ensure the rules apply.

Why R8 Breaks Working CodeWhen you toggle isMinifyEnabled = true, R8 (the successor to ProGuard) tries to shrink your APK—often reducing its size by 30% to 50%. It starts at your "entry points," like Activities listed in the Manifest, and follows the code path to see what is actually used.

Problems start with Reflection. If you reference a class by a String (e.g., Class.forName("MyClass")), R8 can't "see" that connection. It assumes the class is unused and deletes it. In other cases, R8 might rename MyClass to a.b to save space, but your JSON library is still searching for the original name, leading to the ClassNotFoundException.

Where This Usually Happens- JSON Serialization: GSON and Moshi use reflection to map JSON keys to your Kotlin/Java fields.- JNI & Native Code: C++ code often calls Java methods using hardcoded class strings that R8 doesn't track.- WebView Interfaces: Any Java class exposed to JavaScript via @JavascriptInterface.- Dependency Injection: Libraries like Dagger or Hilt usually handle this, but custom setups can lose generated code.## How to Fix It### 1. Use the @Keep AnnotationInstead of editing text files, you can use the @Keep annotation from the AndroidX library. It's the most readable way to protect a single class or method.

@Keep
class UserProfile(
    val username: String,
    val email: String
)

2. Update proguard-rules.proFor third-party libraries where you can't add annotations, use app/proguard-rules.pro. Here are three common patterns:

Protect a specific bridge class:

-keep class com.example.app.NativeBridge { *; }

Keep all models (essential for API responses):

-keep class com.example.app.models.** { *; }

Keep any class implementing an interface:

-keep class * implements com.example.app.MyPlugin { *; }

3. Decode the Obfuscated Stack TraceIf your crash log shows a cryptic name like ClassNotFoundException: a.b.c, you need the mapping file to translate it back to a human-readable class. This file is generated every time you build.

Check: app/build/outputs/mapping/release/mapping.txt Search for a.b.c in that text file. Once you find the original name, add it to your keep rules.

VerificationNever assume a fix worked just because the app compiles. Release builds behave differently than debug ones.

Use the APK Analyzer- In Android Studio, go to Build > Analyze APK...- Select your .apk or .aab.- Open classes.dex and search for your class. If it appears with its original name and all its methods intact, your keep rule is working.### Check Logcat on a Real DeviceTest the release APK on a physical phone. Filter Logcat by "Error" and trigger the feature that crashed. If the ClassNotFoundException is gone, you're ready for production.

References- Android Developers: Shrink, obfuscate, and optimize your app- ProGuard Manual: Keep Options

Related Error Notes