Работая с правилами Keep, важно достичь необходимого уровня специфичности, чтобы получить преимущества, сохраняя при этом функциональность приложения. В следующих разделах вы найдете информацию о хороших шаблонах и о том, чего следует избегать при использовании правил Keep.
Хорошие образцы в правилах хранения
Четко определенные правила хранения максимально конкретны и соответствуют следующим шаблонам:
Для спецификации класса всегда указывайте конкретный класс, базовый класс или аннотированный класс, если это возможно, как показано в следующих примерах:
-keepclassmembers class com.example.MyClass { void someSpecificMethod(); }-keepclassmembers ** extends com.example.MyBaseClass { void someSpecificMethod(); }-keepclassmembers @com.example.MyAnnotation class ** { void someSpecificMethod(); }По возможности используйте аннотации в исходном коде, а затем укажите их непосредственно в правилах сохранения. Это создаст чёткую и явную связь между вашим кодом и правилами, которые его сохраняют, делая конфигурацию более надёжной, понятной и менее подверженной сбоям при изменении кода.
Например, следующий фрагмент демонстрирует, как можно сохранить класс MyClass, а также другие классы, аннотированные
@com.example.DisplayComponent:// In the source code @com.example.DisplayComponent class MyClass { /* ... */ } // In the keep rules -keep @com.example.DisplayComponent class * {*;}Мы рекомендуем называть аннотации так, чтобы они содержали содержательное описание того, почему сохраняются части кода. Например, используйте
@DisplayComponentдля приложения, в котором компоненты отображения требуют сохранения некоторых частей.По возможности следует объявлять спецификацию члена и ссылаться только на те части класса, которые необходимо сохранить для функционирования приложения. Рекомендуется не применять правило ко всему классу, определяя необязательную область действия члена как
{ *; }за исключением случаев крайней необходимости.-keepclassmembers com.example.MyClass { void someSpecificMethod(); void @com.example.MyAnnotation *; }При использовании глобальной опции
repackageclassesне указывайте необязательное имя пакета. Это приводит к уменьшению размера DEX-файлов, поскольку префикс пакета опускается в именах переупакованных классов.Поддерживайте правила хранения для всех элементов, к которым осуществляется доступ через рефлексию. Даже если R8 сохраняет такие элементы без явных правил хранения, соблюдение этих правил критически важно, поскольку будущие изменения кода могут привести к тому, что R8 перестанет сохранять эти элементы.
Если вы не можете следовать этим рекомендациям, вы можете временно изолировать код, который необходимо сохранить, в отдельном пакете и применить к нему правило сохранения. Однако это не является долгосрочным решением. Подробнее см. в разделе «Постепенное внедрение оптимизаций» . Чтобы использовать правило сохранения для пакета, определите его, как показано в следующем примере:
-keepclassmembers class com.example.pkg.** { *; }
Чего следует избегать
Синтаксис правила сохранения имеет много вариантов, но для достижения ощутимых преимуществ в плане устойчивой производительности мы рекомендуем не использовать следующие варианты:
- Не используйте правила сохранения для всего пакета, такие как
-keep class com.example.pkg.** { *; }в долгосрочной перспективе. Их можно использовать временно для обхода проблем при настройке R8. Подробнее см. в разделе Ограничение области оптимизации . В целом, будьте осторожны с подстановочными знаками — убедитесь, что вы сохраняете только необходимый код. - По возможности избегайте библиотек, которые предлагают копировать и вставлять правила Keep при их использовании, особенно правил Keep для всего пакета. Библиотеки, разработанные для эффективной работы на Android, должны по возможности избегать рефлексии и при необходимости встраивать пользовательские правила Keep .
- Избегайте использования оператора инверсии
!в правилах keep, поскольку вы можете непреднамеренно применить правило практически к каждому классу в вашем приложении.
Если вы не можете следовать этим правилам, возможно, вы слишком много используете открытую рефлексию, и вам следует либо избегать рефлексии, либо избегать библиотеки, использующей рефлексию (см. пример Gson ).