Application of shrinking and renaming is configured by using the -keep*
rules. These rules are configured by proving a class specification and optional modifiers.
Rule (and Arguments) | Description |
---|---|
-keep[,<modifier>[...]] <class-spec> |
Exclude matching classes, and matching members if specified, from shrinking, optimization, and renaming. Shrinking exclusion on the class means that members will not be removed but does not prevent members from being renamed. Specifying members will prevent them from being renamed if present. (ProGuard docs) |
-keepclassmembers[,<modifier>[...]] <class-spec> |
Exclude matching members in matching classes from shrinking, optimization, and renaming. (ProGuard docs) |
-keepclasseswithmembers[,<modifier>[...]] <class-spec> |
Exclude matching classes and matching members from shrinking, optimization, and renaming if the corresponding class has all of the specified members. (ProGuard docs) |
-keepnames[,<modifier>[...]] <class-spec> |
Prevent matching classes, and matching members if specified, from being renamed. (ProGuard docs) |
-keepclassmembernames[,<modifier>[...]] <class-spec> |
Prevent any matching members from being renamed in matching classes. (ProGuard docs) |
-keepclasseswithmembernames[,<modifier>[...]] <class-spec> |
Prevent matching classes and matching members from being renamed if the corresponding class contains all of the specified members. This does not prevent matching members from being removed by shrinking (ProGuard would also prevent the specified members from being removed). (ProGuard docs) |
-whyareyoukeeping <class-spec> |
Log details about why particular classes and members were maintained in the output. (ProGuard docs) |
-if <class-spec> <one-keep-rule> |
Conditionally apply one keep rule. If class members are specified, the class and all specified members must match. Otherwise, only the class need match. Class specification in the keep rule can contain back references to wildcards in the -if class specification. (ProGuard docs) |
Modifier | Effect |
---|---|
allowshrinking |
Allow the target(s) of the rule to be removed by shrinking. (ProGuard docs) |
allowoptimization |
Allow the target(s) of the rule to be optimized. (ProGuard docs) |
allowobfuscation |
Allow the target(s) of the rule to be renamed. Adding this modifier to one of the -keep*names rules causes that rule to have no effect. (ProGuard docs) |
includedescriptorclasses |
Prevent specified field types, method return types, and method parameter types from being renamed. This preserves field and method signatures (post type-erasure, e.g. this does not preserve generic types). (ProGuard docs) |
Note: It is not clear what optimization R8 does, or how much control over that process is provided through the
-keep*
rules and theallowoptimization
modifier.
Class Specification
Several of the rules accept a class specification (class-spec
) which is a specification of classes and members that has a Java-like syntax. For example:
-keepclassmembernames public class some.path.to.MyClass {
int intField;
android.content.Context getApplicationContext();
public static String *;
}
The syntax has strong support for filtering classes, methods, and fields. The syntax supports class
(classes), interface
(interfaces), enum
(enumerations), and @interface
(annotations). The special symbol <init>
is used to represent the name of a class’s constructor.
Wildcards and Special Characters
The syntax also supports wildcards and negation using special characters:
-
!
negates the condition described by the subsequent specification. Can be used with modifiers and with theclass
,interface
,enum
, and@interface
keywords. -
*
a sequence of zero or more characters, other than package separators (.
), when used with other symbols in a pattern. Matches any reference type when used alone (this is not supported in all contexts in ProGuard). -
**
a sequence of zero or more characters, including package separators (.
), when used with other symbols in a pattern. Matches any reference type when used alone (does not match primitive types orvoid
). -
***
a sequence of zero or more characters, including package separators (.
), when used with other symbols in a pattern. Matches any reference type, primitive type, orvoid
when used alone. -
%
matches any primitive type (does not matchvoid
) when used alone. -
?
matches any one character. -
<integer>
integer (starting at 1) referencing the value that matched a wildcard used earlier in the specification. For-if
-predicated-keep*
rules, the index can reference any earlier wildcard match in the specification for either part. Neither R8 nor ProGuard seem to handle back references in the presence of wildcards in both the class name and class member names. R8 does not appear to handle back references within member specifications. -
...
matches any number of arguments when used within parentheses ((
and)
) of a method specification.
For example:
-keepclassmembernames class * { long *UUID; } # don't rename long-valued fields ending with UUID in classes
Several other useful constructs are recognized in the class specification:
-
<fields>;
is a special string representing all fields -
<methods>;
is a special string representing all methods
Note: There are some differences between how the filter syntax is interpreted by R8 and ProGuard. For example,
*;
represents all fields and methods in both, but only R8 recognizes* *;
(all fields) and* *(...);
(all methods).
Modifiers
You can use the following modifier keywords to narrow down wildcards used in class specifications:
Name | Class | Method | Field |
---|---|---|---|
abstract |
✓ | ✓ | |
final |
✓ | ✓ | ✓ |
native |
✓ | ||
private |
✓ | ✓ | |
protected |
✓ | ✓ | |
public |
✓ | ✓ | ✓ |
static |
✓ | ✓ | |
strictfp |
✓ | ||
synchronized |
✓ | ||
transient |
✓ | ||
volatile |
✓ |
If multiple modifiers are used together on a single expression, then in most cases only classes, methods, or fields that match all of the applied modifiers will be matched. However, if mutually exclusive modifiers are applied (e.g., private
and protected
), classes, method, and fields that match either of the mutually exclusive modifiers may be matched.
For example:
-keep public class * { # All public classes
public static *; # All public static fields in those classes
public protected abstract *(...); # All public or protected abstract methods in those classes
}
Subtype Matching and Annotated Matching
There are two powerful constructs that can be used with class filtering: subtype matching and annotated matching.
Specify either extends <type-name>
or implements <interface-name>
to match types that either extend or implement another type. For example, -keep class * implements some.particular.SpecialInterface
will match all classes that implement SpecialInterface
. Note that extends
and implements
can be used interchangeably.
Specify an annotation on the type filter to indicate that only types that are annotated with that annotation should match the filter. For example, -keep @some.package.SomeAnnotation interface *
will match all interfaces that are annotated with @SomeAnnotation
.