Explain R8's shrinking, obfuscation, and optimization phases and how to influence optimization

Whether you understand R8 beyond a black box.
Separate dead code removal, renaming, and bytecode transformation; cite ProGuard keep rules and selective passes.
Thinking optimization is only the minifyEnabled toggle.
WHAT THIS TESTS: This question probes whether you treat R8 as a magical checkbox or as a compiler pipeline you can reason about and tune. Seniors are expected to know the three discrete phases, how they interact, and where developer intent overrides default behavior.
A GOOD ANSWER COVERS: First, define shrinking as tree shaking that removes unused classes, methods, and fields by analyzing entry points and reachability. Second, define obfuscation as identifier renaming that shortens package, class, and member names to reduce binary size and deter reverse engineering. Third, define optimization as structural bytecode transformation including method inlining, class merging, dead code elimination, and interface privatization. Fourth, explain influence levers beyond the minifyEnabled toggle: ProGuard keep rules with modifiers like allowobfuscation and allowoptimization, the dontoptimize and dontshrink directives, custom keep annotations in source, and the optimizationpasses directive in proguard rules. Fifth, mention that R8 respects these rules during the optimization phase to preserve reflection entry points or serialization contracts while still optimizing unrelated code.
COMMON WRONG ANSWERS: A major red flag is conflating obfuscation with optimization or claiming shrinking is just resource removal. Another is saying optimization is only controlled by the minifyEnabled Gradle property with no awareness of ProGuard rules. Candidates who say you cannot influence R8 optimization at all, or who confuse R8 with the older ProGuard standalone tool, signal a shallow build system understanding. Also, suggesting you simply disable optimization when a crash occurs rather than using targeted keep rules shows an inability to operate the toolchain surgically.
LIKELY FOLLOW UPS: An interviewer might ask how R8 handles reflection and why keep rules are necessary for libraries like Gson or Room. They might ask for the difference between keep and keepclassmembers, or how optimization interacts with stack traces and mapping files. Another angle is build time versus runtime cost: how many optimization passes are reasonable, or how R8 full mode differs from compatibility mode and when to switch between them.
ONE CONCRETE EXAMPLE: Suppose a library uses reflection to instantiate classes by simple name. R8 optimization could inline or remove those classes because they appear unused. Instead of turning off optimization entirely, you add a ProGuard rule like keep class com.example.model.** { *; } with allowoptimization. This tells R8 to retain the class and members for reflection but still apply every safe bytecode transformation to the rest of the code, preserving app size and performance wins without runtime crashes.
Read the original → developer.android.com
- #android
- #r8
- #build-system
- #proguard
- #bytecode-optimization
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.