Следуйте рекомендациям

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

Рекомендации по созданию правил хранения

Правила хранения должны быть максимально конкретными и соответствовать следующим шаблонам:

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

    -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).