Automating Android R8 Optimization with AI Agents
Testing how AI agents handle R8 shrinking, obfuscation, and reflection-based crashes in Android.
1The R8 Optimization Challenge
Many Android projects leave R8 optimization disabled due to past, undocumented build failures. This flag, often set to false in build.gradle.kts, persists as a legacy precaution. Enabling R8 is a critical task for reducing DEX size and improving performance, yet teams frequently postpone it, fearing unpredictable runtime crashes during release.
2R8 Core Functionalities
R8 performs three primary tasks: shrinking, optimization, and obfuscation. It removes unreachable code starting from manifest entry points, inlines methods to optimize execution, and renames classes to shorten names. Since AGP 8.0, R8 operates in full mode by default, which is more aggressive and requires precise keep rules for reflection.
3Reflection and Runtime Crashes
Reflection hides code references from R8, leading to potential runtime crashes. In the test app, Gson parsed JSON into data classes without explicit constructor calls. R8 incorrectly identified these as unused, stripped the constructors, and caused instantiation errors. This demonstrates why automated optimization requires careful configuration to maintain app stability.
4Testing AI Agent Capabilities
The experiment used Claude Opus 5.5 to enable R8 on a Pixel 7 device. Three distinct runs were conducted: a blind prompt, a prompt with visible skills, and one with specific context about Gson. The goal was to reach a production-ready state where the release build functions correctly on hardware.
5Agent Performance and Success
All three AI runs successfully identified the Gson reflection issue and generated appropriate keep rules. They avoided keeping entire packages, opting for granular rules instead. Two agents correctly identified that the build was signed with a debug key, highlighting a potential issue for Play Store deployment, though they focused on R8.
6Inference Versus Verified Evidence
While the agents correctly inferred the need for keep rules, they often failed to verify their work through actual testing. One agent claimed a task detail screen opened without crashes, but could not provide evidence. These unchecked assertions mirror the human tendency to document assumptions as facts in internal wikis.
7The Danger of Unverified Claims
Agents frequently included incorrect technical justifications in their documentation, such as claims about constructor stripping that were disproven by testing. These plausible but false statements can pollute a repository's documentation. It is essential to treat any agent-generated summary without concrete evidence as a TODO item rather than a verified fact.
8Driving Hardware for Validation
Automated testing on physical devices proved difficult due to missing accessibility metadata. Agents struggled with UI interactions, sometimes resorting to raw coordinate taps. One agent accidentally triggered Google Voice Search after a failed back press. This highlights the necessity of robust UI testing frameworks when delegating build tasks to AI.
9Optimizing Keep Rule Strategy
The most effective solution involved using @SerializedName annotations and default constructor values instead of manual keep rules. This approach ensures that rules remain valid even if classes are moved between packages. By leveraging Kotlin's default parameters, developers can satisfy R8 requirements without relying on fragile, hard-coded configuration files in the repository.
10Limitations of Code Inference
The experiment succeeded because the reflection was contained within the app's own code. In real-world scenarios, reflection often hides within third-party dependencies that are difficult to analyze. In such cases, agents cannot rely on inference alone; they must run the release build and observe actual failures to identify necessary rules.
11Long-term Architectural Solutions
The ultimate solution for R8-related reflection issues is moving away from reflection-based libraries like Gson. Libraries that generate code at compile-time, such as Moshi or kotlinx.serialization, avoid these R8 surprises entirely. Migrating to these tools is a superior long-term strategy compared to maintaining complex, manual keep rules for legacy reflection-based code.
12The Golden Rule for R8
The most important takeaway is to make the build fail first. Reproduce the crash in a release build before applying any fixes. A rule created without observing a failure is merely a guess. Always separate verified evidence from agent inferences to ensure that your production build remains stable and reliable.
Original article: ProAndroidDev - Medium — Automating Android R8 Optimization with AI Agents