Follow the best practices

While working with keep rules, it's important to reach the right amount of specificity to make sure you see benefits while maintaining your app's behaviour. See the following sections to learn about good patterns as well as things to avoid in keep rules.

Good patterns in keep rules

Well-defined keep rules are as specific as possible:

  • For the class specification, always specify a specific class, base class, or annotated class if possible, as shown in the following examples:

    -keepclassmembers class com.example.MyClass {
      void someSpecificMethod();
    }
    
    -keepclassmembers ** extends com.example.MyBaseClass {
      void someSpecificMethod();
    }
    
    -keepclassmembers @com.example.MyAnnotation class ** {
      void someSpecificMethod();
    }
    
  • Whenever possible, the member specification should be declared, and only reference the parts of the class that must be kept for the app to function. It's recommended to not apply a rule to an entire class by defining the optional member scope as { *; } unless strictly needed.

    -keepclassmembers com.example.MyClass {
      void someSpecificMethod();
      void @com.example.MyAnnotation *;
    }
    

If you can't adhere to these guidelines, you can temporarily isolate the code that needs to be kept in a dedicated package and apply your keep rule to the package. However, this isn't a solution for the long term. To learn more, see Adopt optimizations incrementally. To use a keep rule for a package define a keep rule as shown in the following example:

-keepclassmembers class com.example.pkg.** { *; }

Things to avoid

The keep rule syntax has many options, but for measurable sustainable performance benefits we recommend not using the following:

  • Avoid using the inversion operator ! in keep rules because you could unintentionally apply a rule to almost every class in your application.
  • Don't use package-wide keep rules such as -keep class com.example.pkg.** { *; } long-term. They can be used temporarily to work around issues when configuring R8. For more information, see Limit the optimization scope. In general, be careful with wildcards— make sure that you are keeping only the code that you need to.

If you're unable to follow these rules, you might be using a lot of open-ended reflection, and should either avoid the reflection or avoid the library using reflection (see the Gson case study).