Чтобы включить оптимизацию приложения, необходимо использовать библиотеки, совместимые с оптимизацией Android. Если библиотека не настроена для оптимизации Android, например, если она использует отражение без объединения связанных правил хранения, она может не подойти для приложения Android. На этой странице объясняется, почему некоторые библиотеки лучше подходят для оптимизации приложения, и даются общие советы, которые помогут вам сделать выбор.
Предпочитать кодогенерацию рефлексии
Как правило, следует выбирать библиотеки, которые используют генерацию кода ( codegen ) вместо рефлексии. С помощью codegen оптимизатору проще определить, какой код фактически используется во время выполнения, а какой код можно удалить. Может быть сложно определить, использует ли библиотека codegen или рефлексию, но есть некоторые признаки — см. советы для справки.
Дополнительную информацию о кодогенерации и рефлексии см. в разделе Оптимизация для авторов библиотек .
Общие советы по выбору библиотек
Воспользуйтесь этими советами, чтобы обеспечить совместимость ваших библиотек с оптимизацией приложений.
Проверьте наличие проблем с оптимизацией
При рассмотрении новой библиотеки просмотрите трекер проблем библиотеки и онлайн-обсуждения, чтобы проверить, есть ли проблемы, связанные с минификацией или настройкой оптимизации приложения. Если есть, вам следует попробовать поискать альтернативы этой библиотеке. Имейте в виду следующее:
- Библиотеки AndroidX и библиотеки, такие как Hilt, хорошо работают с оптимизацией приложений, поскольку они используют codegen вместо рефлексии. Когда они используют рефлексию, они предоставляют минимальные правила сохранения, чтобы сохранить только необходимый код.
- Библиотеки сериализации часто используют рефлексию, чтобы избежать шаблонного кода при создании экземпляров или сериализации объектов. Вместо подходов, основанных на рефлексии (таких как Gson для JSON), ищите библиотеки, которые используют codegen, чтобы избежать этих проблем, например, используя сериализацию Kotlin .
- Библиотеки, включающие правила хранения на уровне пакета, следует по возможности избегать. Правила хранения на уровне пакета могут помочь устранить ошибки, но общие правила хранения в конечном итоге следует уточнить, чтобы сохранить только необходимый код. Для получения дополнительной информации см. раздел Adopt optimizations incrementally .
Включить оптимизацию после добавления новой библиотеки
Когда вы добавляете новую библиотеку, включите оптимизацию и проверьте, нет ли ошибок. Если есть ошибки, найдите альтернативы этой библиотеке или напишите правила сохранения. Если библиотека несовместима с оптимизацией, отправьте сообщение об ошибке в этой библиотеке.
Правила являются аддитивными
Помните, что правила keep являются аддитивными. Это означает, что определенные правила, которые включает зависимость библиотеки, не могут быть удалены и могут повлиять на компиляцию других частей вашего приложения. Например, если библиотека включает правило для отключения оптимизации кода, это правило отключает оптимизацию для всего вашего проекта.
Проверка использования отражения (расширенная)
Вы можете определить, использует ли библиотека рефлексию, проверив ее код. Если библиотека использует рефлексию, проверьте, предоставляет ли она связанные правила сохранения. Библиотека, вероятно, использует рефлексию, если она делает следующее:
- Использует классы или методы из пакетов
kotlin.reflect
илиjava.lang.reflect
- Использует функции
Class.forName
илиclassLoader.getClass
- Читает аннотации во время выполнения, например, если он сохраняет значение аннотации с помощью
val value = myClass.getAnnotation()
илиval value = myMethod.getAnnotation()
, а затем что-то делает соvalue
Вызывает методы, используя имя метода в виде строки, например:
// Calls the private `processData` API with reflection myObject.javaClass.getMethod("processData", DataType::class.java) ?.invoke(myObject, data)
Отфильтровать плохие правила хранения (расширенные)
Вам следует избегать библиотек с правилами сохранения, которые сохраняют код, который на самом деле следует удалить. Но если вам необходимо их использовать, вы можете отфильтровать правила, как показано в следующем коде:
// If you're using AGP 8.4 and higher
buildTypes {
release {
optimization.keepRules {
it.ignoreFrom("com.somelibrary:somelibrary")
}
}
}
// If you're using AGP 7.3-8.3
buildTypes {
release {
optimization.keepRules {
it.ignoreExternalDependencies("com.somelibrary:somelibrary")
}
}
}
Пример из практики: почему Gson отказывается от оптимизации
Gson — это библиотека сериализации, которая часто вызывает проблемы с оптимизацией приложений, поскольку она активно использует отражение. Следующий фрагмент кода показывает, как обычно используется Gson, что может легко привести к сбоям во время выполнения. Обратите внимание, что когда вы используете Gson для получения списка объектов User, вы не вызываете конструктор и не передаете фабрику в функцию fromJson()
. Создание или использование определенных приложением классов без любого из следующих является признаком того, что библиотека может использовать открытое отражение:
- Класс приложения, реализующий библиотеку, стандартный интерфейс или класс
- Плагин генерации кода, как KSP
class User(val name: String)
class UserList(val users: List<User>)
// This code runs in debug mode, but crashes when optimizations are enabled
Gson().fromJson("""[{"name":"myname"}]""", User::class.java).toString()
Когда R8 анализирует этот код и не видит UserList
или User
, инстанцированными где-либо, он может переименовать поля или удалить конструкторы, которые, по-видимому, не используются, что приведет к сбою вашего приложения. Если вы используете какие-либо другие библиотеки аналогичным образом, вам следует проверить, не помешают ли они оптимизации приложения, и если это так, избегайте их.
Обратите внимание, что Room и Hilt создают типы, определяемые приложением, но используют codegen, чтобы избежать необходимости рефлексии.