Identify what the build actually runs
In a current Android Gradle Plugin project, enabling code optimization invokes R8. A file named proguard-rules.pro does not prove that the ProGuard executable ran: R8 consumes compatible rules from that file.
Use the Android optimization documentation for Android configuration and the ProGuard manual for a standalone ProGuard pipeline. Mixing commands from the two can create misleading diagnostics.
Compare the responsibilities
| Question | R8 in an Android build | Standalone ProGuard |
|---|---|---|
| Typical integration | Android Gradle Plugin | Java build or explicit integration |
| Output context | Android deployment pipeline | Processed Java bytecode |
| Rules | ProGuard-compatible rules with documented differences | ProGuard configuration |
| Debugging evidence | R8 diagnostics and matching mapping | ProGuard diagnostics and matching mapping |
Both can remove unused code and rename symbols. Neither turns an embedded API secret into a safe secret.
Migrate rules, not assumptions
Start with the rules actually required by reflection, serialization, native interfaces and libraries. Remove obsolete broad keeps only with release tests. The keep-rule guide explains why retaining every class defeats much of the optimizer's value.
A third-party library may already supply consumer rules. Check those before adding a second app-wide rule that keeps an entire package. A rule that once worked around an old optimizer bug may no longer be necessary, but deleting it without reproducing its original case is also risky.
Compare release outcomes
Measure the same variant, resources, ABI configuration and dependency set. Compare artifact size, startup and critical flows after shrinking. A smaller APK with broken reflective deserialization is not an improvement.
Archive mapping files for each distributed release. Debug builds do not exercise the same optimization behavior and cannot establish release compatibility.
Use inspection as a supporting signal
APKLint's ProGuard / R8 checker can highlight likely obfuscation characteristics. It cannot identify every transformation or certify that your rules are correct. The decisive evidence is a successful optimized build, representative runtime tests and usable crash deobfuscation.
Do not select an optimizer from a filename
A repository may contain proguard-rules.pro, an old README mentioning ProGuard and an Android release task that actually invokes R8. Determine the current path from the Android Gradle Plugin configuration and build output. Renaming the rule file does not switch the executable. Likewise, placing a standalone ProGuard command before packaging creates another transformation stage rather than automatically replacing the integrated pipeline.
Use the ProGuard manual for an explicit Java processing pipeline and the Android optimization setup for the integrated Android path. Their overlapping configuration syntax does not make every option, output format or diagnostic interchangeable.
Compare a release outcome with fixed inputs
If evaluating a historical migration, preserve the original tool versions and rules, then define what success means: equivalent user behavior, usable crash traces, supported platform compatibility and a measurable size or performance result. Use the same application revision and representative workload. Changing the image assets, SDK versions and optimizer simultaneously makes a size difference difficult to attribute.
Prioritize integration boundaries likely to be affected by transformation: reflective model construction, Java-to-native callbacks and names stored in configuration. Use a synthetic record that exercises each boundary, including its expected failure path. Test the actual processed release, because ordinary source-level tests may bypass transformation entirely.
Keep an inventory of rules carried forward and classify why each exists. A library's consumer rule, an application's dynamic name contract and a workaround for an old tool defect have different owners and retirement conditions. Remove obsolete rules only after reproducing their original scenario. Retain mappings for the distributed artifact regardless of which supported pipeline produced it. If diagnostics pass through multiple transformations, establish the mapping chain before shipping. A useful comparison concludes with a supported, understandable release process and measured behavior; it does not declare one tool universally superior based on symbol length or an APK inspector's obfuscation label.
Sources and further reading
- Android Developers: Enable optimization with R8
- Android Developers: Add keep rules
- ProGuard manual — Guardsquare
Reference review: 29 September 2026. Examples illustrate the workflow; check your installed versions, release artifact and account-specific Console requirements before applying them. This guide is not a claim that APKLint executed your project or verified your private account.


