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()
orMethod.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 examplepublic
orfinal
.<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>;
}