Add keep rules

When you enable app optimization with the default settings, R8 performs extensive optimizations in order to maximize your performance benefits. R8 makes substantial modifications to the code including renaming, moving, and removing classes fields and methods. If this causes errors, you need to specify which parts of the code to leave alone by writing keep rules.

R8 might incorrectly remove or modify code in the following situations:

  • Reflection: code accessed using reflection, for example using Class.forName() or Method.invoke(). R8 usually can't tell which classes or methods will be accessed this way.
  • Serialization: classes or fields needed for serialization and deserialization might appear to be unused to R8 (this is another form of reflection).
  • Java Native Interface (JNI): Java methods called from native code. R8 doesn't analyze the native code to see what it might call back into Java.

This page covers how to limit the extent of R8's optimizations. To learn how to customize which resources are kept, see Add keep rules for resources.

Where to add keep rules

You should add your rules to a proguard-rules.pro file located in the module's root directory (the file might already be there, but if it isn't, create it). To apply the rules in the file, you must declare the file in your module-level build.gradle.kts (or build.gradle) file as shown in the following code:

Kotlin

android {
    buildTypes {
        release {
            isMinifyEnabled = true
            isShrinkResources = true

            proguardFiles(
                // Default file with default optimization rules.
                getDefaultProguardFile("proguard-android-optimize.txt"),

                // File with your custom rules.
                "proguard-rules.pro"
            )
            ...
        }
    }
    ...
}

Groovy

android {
    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true

            proguardFiles(
                // Default file with default optimization rules.
                getDefaultProguardFile('proguard-android-optimize.txt'),

                // File with your custom rules.
                'proguard-rules.pro'
            )
            ...
        }
    }
    // ...
}

By default, your build script also includes the proguard-android-optimize.txt file. This file includes rules that are required for most Android projects, so you should keep it in the build script.

How to write keep rules

During app compilation R8 detects which code needs to be kept in an app by analyzing your app's call graph, which starts at the manifest entries (such as your activities or services) and traces through every app and library function call. R8 removes code that isn't directly referenced in this way, which can cause issues if executed code isn't part of this graph, for example code invoked by reflection. By writing your own keep rules, you can inform R8 of code that needs to stay in the app.

To add a keep rule, add a -keep line in the proguard-rules.pro file.

Keep rule syntax

Keep rules generally follow this format:

-<KeepOption> [OptionalModifier,...] <ClassSpecification> [{ OptionalMemberSpecification }]

For example to preserve a specific class and all its members, use the following:

-keep class com.myapp.MyClass { *; }

For more examples, see the examples section.

Here's what the keep rule components do:

  • <KeepOption> lets you specify what aspects of a class to preserve:

    Keep option Description

    -keep

    Preserve the class and the members listed in [{ OptionalMemberSpecification }].

    -keepclassmembers

    Allow optimization of the class; if the class is preserved, preserve the members listed in [{ OptionalMemberSpecification }].

    -keepnames

    Allow removal of class and members, but don't obfuscate or modify in other ways.

    -keepclassmembernames

    Allow removal of class and members, but don't obfuscate or modify members in other ways.

    -keepclasseswithmembers

    No removal or obfuscation of classes if members match the specified pattern.

    We recommend mostly using -keepclassmembers, since it enables the most optimizations, and then -keepnames if needed. -keep doesn't allow for any optimizations, so try to use it sparingly.

  • [OptionalModifier],...] lets you list zero or more Java language modifiers of a class, for example public or final.

  • <ClassSpecification> lets you specify which class (or which superclass or implemented interface) the keep rule should apply to. In the simplest case this is one fully qualified class.

  • [{ OptionalMemberSpecification }] lets you filter the keep behavior to only classes and methods matching certain patterns. Generally this is recommended in most keep rules to prevent keeping more than intended.

Keep rule examples

Here are some examples of well designed keep rules.

Construct subclass

This keep rule is packaged inside of androidx.room:room-runtime to keep database constructors instantiated by reflection.

-keep class * extends androidx.room.RoomDatabase { void <init>(); }

Reflection from Android Framework ObjectAnimator

This keep rule is packaged inside of androidx.vectordrawable:vectordrawable-animated to enable ObjectAnimator to call into getters or setters from native code with JNI. Note that newer animation systems in Compose don't require keep rules like this, it's just an example of rule structure.

-keepclassmembers class androidx.vectordrawable.graphics.drawable.VectorDrawableCompat$* {
   void set*(***);
   *** get*();
}

JNI Registration

This keep rule is packaged inside of androidx.graphics:graphics-path, used to keep native methods. This might be necessary if your library manually registers native methods with env->RegisterNatives().

-keepclasseswithmembers class androidx.graphics.path.** {
    native <methods>;
}