R8 234 starts from entry points: the activities, services and receivers in the merged manifest, views named in XML, and anything a keep rule names. It traces every class, method and field reachable from them (tree shaking), deletes the rest, inlines small methods, merges classes, removes dead branches, and renames what survives. BookNest's release build type turns it on:
buildTypes {
release {
isMinifyEnabled = true // 5.37 R8: shrink, optimize, obfuscate
isShrinkResources = true // and remove unused resources
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"))
signingConfig = signingConfigs.getByName("debug") // for testing; 5.38 signs properly
}
}AGP 9.3 added a shorter form, optimization { enable = true }, which also enables optimized resource shrinking and the default rules. BookNest tried it first and went back: with AGP 9.4.0 the baseline-profile plugin could not turn R8 off for its nonMinifiedRelease variant (Baseline Profiles). The results, measured with the SDK's apkanalyzer dex references:
| Debug APK | Release APK | |
|---|---|---|
| Size | 21,981,979 bytes | 4,371,556 bytes |
| Dex files | 18 | 1 |
| Method references | 228,024 | 33,849 |
Five of every six bytes were code and resources no screen reaches. R8 records its work in app/build/outputs/mapping/release/: mapping.txt (548,692 lines of old name to new name), usage.txt (what it removed), seeds.txt (what the keep rules held) and configuration.txt (every rule it applied, merged from AGP, libraries and you). Obfuscation shows up at run time too: the release build's Log.d(TAG, "loaded: ${load.value::class.simpleName}") printed loaded: hq2 instead of loaded: Success, so never build logic, analytics names or JSON keys on class names.