При работе с правилами сохранения важно достичь нужного уровня детализации, чтобы получить преимущества и сохранить поведение приложения. В следующих разделах рассказывается о том, как правильно составлять правила хранения, а также о том, чего следует избегать.
Рекомендации по созданию правил хранения
Правила хранения должны быть максимально конкретными и соответствовать следующим шаблонам:
В спецификации класса всегда указывайте конкретный класс, базовый класс или аннотированный класс, если это возможно, как показано в следующих примерах:
-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 перестанет сохранять эти элементы.
Для рефлексии в собственном коде можно использовать Jetpack Keep, чтобы генерировать правила сохранения, которые проще поддерживать. Каждая аннотация находится в коде, который выполняет рефлексию, поэтому при изменении этого кода вы обновляете или удаляете его аннотацию в том же месте. Это позволит избежать сохранения кода, который больше не используется в приложении. Lint также помечает вызовы рефлексии, которые не аннотированы.
По возможности используйте
-assumenosideeffectsили-convertchecknotnull, чтобы оптимизировать проверки на null. Это может значительно уменьшить размер DEX-файла приложения. Подробнее о дополнительных типах правил…
Если вы не можете следовать этим рекомендациям, временно изолируйте код, который нужно сохранить, в отдельном пакете и примените правило сохранения к этому пакету. Однако это не долгосрочное решение. Подробнее о том, как постепенно внедрять оптимизацию… Чтобы использовать правило хранения для пакета, определите его, как показано в следующем примере:
-keepclassmembers class com.example.pkg.** { *; }
Чего следует избегать
Синтаксис правил сохранения имеет множество вариантов, но для достижения ощутимых преимуществ в производительности мы рекомендуем не использовать следующие:
- Не используйте правила хранения на уровне пакета, например
-keep class com.example.pkg.** { *; }long-term. Их можно временно использовать, чтобы обойти проблемы при настройке R8. Подробнее о том, как ограничить область оптимизации… В целом будьте осторожны с подстановочными знаками и следите за тем, чтобы в коде не было ничего лишнего. - По возможности избегайте библиотек, которые предлагают скопировать и вставить правила сохранения при их использовании, особенно правила сохранения на уровне пакета. Библиотеки, предназначенные для эффективной работы на устройствах Android, должны по возможности избегать рефлексии и встраивать правила сохранения потребителя, когда это необходимо.
- Не используйте оператор инверсии
!в правилах сохранения, поскольку это может привести к тому, что правило будет применено почти ко всем классам в вашем приложении.
Если вы не можете следовать этим правилам, возможно, вы используете много открытых рефлексий. В таком случае вам следует избегать рефлексий или библиотек, которые их используют (см. пример использования Gson).