Gradle & Code Quality

Write Narrow R8 Keep Rules for Reflection and Serialization

A good R8 keep rule preserves the contract that static analysis cannot see without disabling optimization for an entire application. Start from the failing reflective or native call, not from a package-wide wildcard copied from a forum.

By Updated 2 min read

Identify what must remain stable

Ask whether the runtime needs a class to exist, a member to exist, its original name, annotations, or a particular constructor. Those are separate requirements.

The keep-rule reference explains the options and modifiers. -keepnames does not necessarily prevent removal; preserving a name is different from preserving an otherwise unused class.

Prefer a narrow example

For an illustrative class loaded by its exact name:

TEXT · REFERENCE EXAMPLE
-keep,allowoptimization class com.example.plugins.ReportPlugin {
    public <init>();
}

This is appropriate only when that named class and constructor are the actual contract. It is not a universal plugin or serialization rule.

For members accessed reflectively on a class otherwise retained, a member-specific rule may be more appropriate. Verify how the object is constructed before choosing keepclassmembers.

Account for Kotlin's compiled shape

Rules match compiled classes and members, not Kotlin source syntax directly. Visibility, generated methods, suspend functions and companion objects can have bytecode forms that differ from an intuitive source-level rule.

Inspect the compiled representation or use the library's supported consumer rules. Broadly retaining every Kotlin class is not a substitute for understanding the generated API.

Let libraries own their requirements

Check whether the library already ships consumer rules. Add app-specific rules for app-specific dynamic behavior; avoid duplicating old recommendations from an unrelated library version.

Verify both correctness and remaining optimization

Build an optimized release, exercise the exact failing feature and inspect the result. A fix that retains the entire dependency graph may restore behavior while silently discarding most size and performance benefits.

Document each rule's reason and a regression test. APKLint can identify possible obfuscation and packaging clues, but only the build and runtime evidence can show that the narrow rule preserved the required contract.

Sources and further reading

  1. Android Developers: Add keep rules
  2. Android Developers: Enable optimization with R8

Reference review: 22 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.

APKLint

Android inspection tools and practical release guides. About APKLint · Report a correction