Gradle & Code Quality

minifyEnabled on Android: Test the Release Variant You Actually Ship

minifyEnabled enables code shrinking, optimization and obfuscation for an Android build type. The switch is not merely a file-size preference: it changes the code that will run, so release-only failures need release-build tests.

By , FounderUpdated 3 min read

Configure the intended build type

A Kotlin DSL example is:

KOTLIN · REFERENCE EXAMPLE
android {
    buildTypes {
        release {
            isMinifyEnabled = true
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
}

This is a module fragment, not a complete build file. Groovy DSL uses different assignment syntax. Follow the current R8 guide for your plugin version.

Check the selected variant

A product flavor combined with a build type creates the final variant. A test of debug says little about productionRelease when signing, endpoints, resources and optimization differ.

Record the exact task, artifact path, application ID and version code. The build-variant documentation helps trace which configuration produced an artifact.

Test code reached indirectly

Prioritize reflective construction, JSON serialization, dependency injection, JNI callbacks, WebView bridges and code loaded by class name. Static analysis may not infer those relationships without correct rules.

Do not solve every failure with -keep class ** { *; }. That effectively opts large parts of the program out of useful optimization and obscures the real contract.

Separate missing code from wrong configuration

Symptom First evidence to inspect
Class not found only in release Reflection path and consumer rules
Network fails only in release Variant endpoint and network configuration
Login fails only after Play installation Distributed signing certificate
Crash trace has renamed symbols Matching mapping file

Not every release-only bug is caused by R8. Temporarily toggling optimization can narrow the problem, but the final fix should address the actual cause.

Validate the shipped artifact

Install the optimized, correctly signed build on representative devices, exercise critical paths and verify a deobfuscated test crash. APKLint can help inspect the resulting package and obfuscation signals; it cannot prove that dynamically accessed features survived.

Choose the configuration syntax for the installed AGP

At this guide's 29 September 2026 review, the official optimizer setup distinguishes the legacy minify/shrink flags from the AGP 9.3-and-higher optimization block. The earlier example deliberately illustrates the legacy Kotlin DSL, which the documentation still supports. Check the project's pinned plugin version before adopting newer syntax; a documentation example is not a reason to upgrade the whole build during an unrelated release repair.

When using the newer setup, follow its documented keep-rule source-set placement. Do not move a rule file and assume the old file reference automatically reads its replacement. Verify the configuration actually consumed by the release build, especially when flavors carry different rules.

Use a controlled comparison to isolate a release-only failure

Suppose login succeeds in debug but fails in productionRelease. First compare the server endpoint, application ID, signing identity and OAuth configuration. If those match the intended release contract, create a diagnostic build differing only in optimization and exercise the same login. This narrows the investigation; it does not make disabling optimization the permanent solution.

If optimized login fails during reflective response parsing, preserve a redacted sample response and identify the missing constructor, annotation or field-name contract. Apply the SDK's supported consumer rules or a targeted application rule. If both diagnostic builds fail before parsing, investigate the common network or authentication setup instead of adding more keep rules.

Rebuild the final intended configuration and test an ordinary account, an expired session and an expected server rejection. Verify that error responses remain distinguishable from malformed payloads. Check that the mapping file belongs to this build and that a controlled crash can be reconstructed. Retain the diagnostic comparison as evidence of the cause, then discard temporary configuration changes from the release candidate. A release flag should be validated through the behavior it changes, not through the presence of a checkbox or the successful execution of an unrelated debug test.

Sources and further reading

  1. Android Developers: Enable optimization with R8
  2. Android Developers: Configure build variants

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.

APKLint

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