Следуйте лучшим практикам

Работая с правилами Keep, важно достичь необходимого уровня специфичности, чтобы получить преимущества, сохраняя при этом функциональность приложения. В следующих разделах вы найдете информацию о хороших шаблонах и о том, чего следует избегать при использовании правил Keep.

Хорошие образцы в правилах хранения

Четко определенные правила хранения максимально конкретны:

  • Для спецификации класса всегда указывайте конкретный класс, базовый класс или аннотированный класс, если это возможно, как показано в следующих примерах:

    -keepclassmembers class com.example.MyClass {
      void someSpecificMethod();
    }
    
    -keepclassmembers ** extends com.example.MyBaseClass {
      void someSpecificMethod();
    }
    
    -keepclassmembers @com.example.MyAnnotation class ** {
      void someSpecificMethod();
    }
    
  • По возможности используйте аннотации в исходном коде (например, аннотацию @Keep ), а затем укажите эти аннотации непосредственно в правилах Keep. Это создаст чёткую и явную связь между вашим кодом и правилами, которые его сохраняют, делая конфигурацию более надёжной, понятной и менее подверженной сбоям при изменении кода.

    Например, библиотеки типа androidx.annotation используют этот шаблон:

    // In your source code
    @Keep
    class MyDataClass { /* ... */ }
    
    // In your R8 rules
    -keep @androidx.annotation.DisplayComponent class * {*;}
    

    Мы рекомендуем называть аннотации так, чтобы они содержали содержательное описание того, почему сохраняются части кода. Например, используйте @DisplayComponent для приложения, в котором компоненты отображения требуют сохранения некоторых частей.

  • По возможности следует объявлять спецификацию члена и ссылаться только на те части класса, которые необходимо сохранить для функционирования приложения. Рекомендуется не применять правило ко всему классу, определяя необязательную область действия члена как { *; } за исключением случаев крайней необходимости.

    -keepclassmembers com.example.MyClass {
      void someSpecificMethod();
      void @com.example.MyAnnotation *;
    }
    
  • При использовании глобальной опции repackageclasses не указывайте необязательное имя пакета. Это приводит к уменьшению размера DEX-файлов, поскольку префикс пакета опускается в именах переупакованных классов.

Если вы не можете следовать этим рекомендациям, вы можете временно изолировать код, который необходимо сохранить, в отдельном пакете и применить к нему правило сохранения. Однако это не является долгосрочным решением. Подробнее см. в разделе «Постепенное внедрение оптимизаций» . Чтобы использовать правило сохранения для пакета, определите его, как показано в следующем примере:

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

Чего следует избегать

Синтаксис правила сохранения имеет много вариантов, но для достижения ощутимых преимуществ в плане устойчивой производительности мы рекомендуем не использовать следующие варианты:

  • Избегайте использования оператора инверсии ! в правилах keep, поскольку вы можете непреднамеренно применить правило практически к каждому классу в вашем приложении.
  • Не используйте правила сохранения для всего пакета, такие как -keep class com.example.pkg.** { *; } в долгосрочной перспективе. Их можно использовать временно для обхода проблем при настройке R8. Подробнее см. в разделе Ограничение области оптимизации . В целом, будьте осторожны с подстановочными знаками — убедитесь, что вы сохраняете только необходимый код.

Если вы не можете следовать этим правилам, возможно, вы слишком много используете открытую рефлексию, и вам следует либо избегать рефлексии, либо избегать библиотеки, использующей рефлексию (см. пример Gson ).