ProGuard / R8 (Java)
R8 is the code shrinker and obfuscator built into the modern Android Gradle Plugin. It replaced the older, standalone ProGuard tool as the default, but the configuration file format ProGuard popularized — .pro rules files with -keep directives — lives on, because R8 reads the same syntax. When people say "add a ProGuard rule," they mean writing a rule that R8 will apply.
What R8 Actually Does
| Step | What it does | Why it matters for RecipeBox |
|---|---|---|
| Shrinking | Removes unused classes, methods, fields, and resources | Smaller APK — unused library code (say, half of a networking SDK RecipeBox never calls) gets dropped |
| Obfuscation | Renames classes/methods/fields to short, meaningless names (a, b, c...) | Makes decompiled output much harder to read and reverse-engineer |
| Optimization | Rewrites and simplifies bytecode (inlining, removing dead branches) | Slightly faster, slightly smaller release builds |
Enabling R8 for Release Builds
R8 runs whenever minifyEnabled is turned on for a build type — in practice, always for release and never for debug, since obfuscated stack traces make debugging painful. This is the same app/build.gradle (Groovy DSL) file from the previous lessons:
// app/build.gradle (Groovy DSL)
android {
buildTypes {
release {
minifyEnabled true
shrinkResources true
signingConfig signingConfigs.release
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
minifyEnabled false
}
}
}
- minifyEnabled true turns on R8 code shrinking + obfuscation.
- shrinkResources true additionally drops unused resources (layouts, drawables, strings) — it only has an effect alongside minifyEnabled.
- getDefaultProguardFile('proguard-android-optimize.txt') pulls in Android's own baseline rules; 'proguard-rules.pro' is where your project's custom rules live.
Writing Keep Rules in proguard-rules.pro
R8 is aggressive: if nothing in your visible code path calls a class directly, it may rename or strip it. That's a problem for classes accessed only through reflection — and RecipeBox's own Recipe class is a perfect example. The JSON Parsing lesson uses Gson to serialize/deserialize Recipe objects, and Gson reads field names like title, ingredients, and prepMinutes via reflection at runtime — obfuscating those field names would silently break JSON parsing.
// proguard-rules.pro
-keep class com.recipebox.model.Recipe { *; }
-keepclassmembers class com.recipebox.model.Recipe {
<fields>;
}
Testing a Release Build Before Publishing
Because shrinking and obfuscation only run on release builds, bugs they cause never show up while developing against debug builds. Always generate and manually exercise a signed release build — install it on a real device and click through RecipeBox's main flows (viewing a recipe, saving a new one, syncing) — before uploading to the Play Store.
Libraries Usually Bring Their Own Rules
Most popular libraries (Retrofit, Gson, Room, Glide) ship a set of default keep rules bundled inside their own .aar file, so R8 automatically applies them without any action from you. Custom keep rules like the one above are typically only needed for your own classes that are accessed reflectively — your model classes, classes referenced from XML (like custom Views), or classes matched by name in a configuration string.