Как автор библиотеки, вы должны убедиться, что разработчики приложений могут легко включить вашу библиотеку в свое приложение, сохраняя при этом высокое качество конечного пользовательского опыта. Вы должны убедиться, что ваша библиотека совместима с оптимизацией Android без дополнительной настройки — или документировать, что библиотека может быть неподходящей для использования на Android.
Эта документация предназначена для разработчиков опубликованных библиотек, но может быть также полезна для разработчиков внутренних библиотечных модулей в больших модульных приложениях.
Если вы разработчик приложений и хотите узнать об оптимизации вашего приложения Android, см. Включить оптимизацию приложения . Чтобы узнать, какие библиотеки подходят для использования, см. Выбирайте библиотеки с умом .
Используйте кодогенерацию вместо рефлексии
По возможности используйте генерацию кода ( codegen ) вместо рефлексии. Codegen и рефлексия — это распространенные подходы, позволяющие избежать шаблонного кода при программировании, но codegen более совместим с оптимизатором приложений, таким как R8:
- С помощью codegen код анализируется и модифицируется в процессе сборки. Поскольку после компиляции не происходит никаких серьезных изменений, оптимизатор знает, какой код в конечном итоге нужен, а что можно безопасно удалить.
- С рефлексией код анализируется и обрабатывается во время выполнения. Поскольку код на самом деле не финализирован до тех пор, пока не будет выполнен, оптимизатор не знает, какой код можно безопасно удалить. Скорее всего, он удалит код, который динамически используется через рефлексию во время выполнения, что приводит к сбоям приложения у пользователей.
Многие современные библиотеки используют codegen вместо reflect. Смотрите KSP для общей точки входа, используемой Room , Dagger2 и многими другими.
Когда рефлексия — это нормально
Если вам необходимо использовать отражение, вы должны отражать только одно из следующих:
- Конкретные целевые типы (конкретные реализаторы интерфейсов или подклассы)
- Код, использующий определенную аннотацию времени выполнения
Использование отражения таким образом ограничивает затраты времени выполнения и позволяет писать целевые правила хранения для потребителей .
Эта конкретная и целенаправленная форма отражения является шаблоном, который вы можете увидеть как в фреймворке Android (например, при инфляции действий, представлений и рисунков), так и в библиотеках AndroidX (например, при построении WorkManager ListenableWorkers или RoomDatabases). Напротив, открытое отражение Gson не подходит для использования в приложениях Android .
Напишите правила хранения для потребителей
Библиотеки должны упаковывать "потребительские" правила хранения, которые используют тот же формат, что и правила хранения приложений. Эти правила объединяются в артефакты библиотеки (AAR или JAR) и автоматически используются во время оптимизации приложения Android при использовании библиотеки.
AAR-библиотеки
Чтобы добавить потребительские правила для библиотеки AAR, используйте опцию consumerProguardFiles
в скрипте сборки модуля библиотеки Android. Для получения дополнительной информации см. наше руководство по созданию модулей библиотеки .
Котлин
android { defaultConfig { consumerProguardFiles("consumer-proguard-rules.pro") } ... }
Круто
android { defaultConfig { consumerProguardFiles 'consumer-proguard-rules.pro' } ... }
JAR-библиотеки
Чтобы связать правила с вашей библиотекой Kotlin/Java, которая поставляется как JAR, поместите файл правил в конечный каталог JAR META-INF/proguard/
с любым именем файла. Например, если ваш код в <libraryroot>/src/main/kotlin
, поместите файл правил потребителя в <libraryroot>/src/main/resources/META-INF/proguard/consumer-proguard-rules.pro
, и правила будут объединены в правильном месте в вашем выходном JAR.
Убедитесь, что окончательный JAR-файл правильно объединяет правила, проверив, находятся ли правила в каталоге META-INF/proguard
.
Оптимизация сборки библиотеки AAR (расширенная)
Как правило, не следует оптимизировать сборку библиотеки напрямую, поскольку возможные оптимизации во время сборки библиотеки очень ограничены. Только во время сборки приложения, когда библиотека включена как часть приложения, R8 может знать, как используются все методы библиотеки и какие параметры передаются. Как разработчик библиотеки, вам необходимо рассуждать о нескольких этапах оптимизации и сохранять поведение, как во время сборки библиотеки, так и во время сборки приложения, прежде чем оптимизировать эту библиотеку.
Если вы все же хотите оптимизировать свою библиотеку во время сборки, это поддерживается плагином Android Gradle.
Котлин
android { buildTypes { release { isMinifyEnabled = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } configureEach { consumerProguardFiles("consumer-rules.pro") } } }
Круто
android { buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } configureEach { consumerProguardFiles "consumer-rules.pro" } } }
Обратите внимание, что поведение proguardFiles
сильно отличается от consumerProguardFiles
:
-
proguardFiles
используются во время сборки, часто вместе сgetDefaultProguardFile("proguard-android-optimize.txt")
, чтобы определить, какая часть вашей библиотеки должна быть сохранена во время сборки библиотеки. Как минимум, это ваш публичный API. -
consumerProguardFiles
, напротив, упаковываются в библиотеку, чтобы влиять на то, какие оптимизации будут выполнены позже, во время сборки приложения, использующего вашу библиотеку.
Например, если ваша библиотека использует рефлексию для создания внутренних классов, вам может потребоваться определить правила сохранения как в proguardFiles
, так и consumerProguardFiles
.
Если вы используете -repackageclasses
в сборке вашей библиотеки, перепакуйте классы в подпакет внутри пакета вашей библиотеки. Например, используйте -repackageclasses 'com.example.mylibrary.internal'
вместо -repackageclasses 'internal'
.
Поддержка различных версий R8 (расширенная)
Вы можете настроить правила для конкретных версий R8. Это позволяет вашей библиотеке оптимально работать в проектах, использующих более новые версии R8, в то же время позволяя существующим правилам продолжать использоваться в проектах со старыми версиями R8.
Чтобы указать целевые правила R8, необходимо включить их в каталог META-INF/com.android.tools
внутри classes.jar
AAR или в каталог META-INF/com.android.tools
JAR.
In an AAR library:
proguard.txt (legacy location, the file name must be "proguard.txt")
classes.jar
└── META-INF
└── com.android.tools (location of targeted R8 rules)
├── r8-from-<X>-upto-<Y>/<R8-rule-files>
└── ... (more directories with the same name format)
In a JAR library:
META-INF
├── proguard/<ProGuard-rule-files> (legacy location)
└── com.android.tools (location of targeted R8 rules)
├── r8-from-<X>-upto-<Y>/<R8-rule-files>
└── ... (more directories with the same name format)
В каталоге META-INF/com.android.tools
может быть несколько подкаталогов с именами в форме r8-from-<X>-upto-<Y>
чтобы указать, для каких версий R8 написаны правила. Каждый подкаталог может иметь один или несколько файлов, содержащих правила R8, с любыми именами файлов и расширениями.
Обратите внимание, что части -from-<X>
и -upto-<Y>
являются необязательными, версия <Y>
является исключительной , а диапазоны версий обычно непрерывны, но могут также перекрываться.
Например, r8
, r8-upto-8.0.0
, r8-from-8.0.0-upto-8.2.0
и r8-from-8.2.0
— это имена каталогов, представляющие набор целевых правил R8. Правила в каталоге r8
могут использоваться любыми версиями R8. Правила в каталоге r8-from-8.0.0-upto-8.2.0
могут использоваться R8 с версии 8.0.0 до версии 8.2.0, но не включая ее.
Плагин Android Gradle использует эту информацию для выбора всех правил, которые могут использоваться текущей версией R8. Если библиотека не указывает целевые правила R8, плагин Android Gradle выберет правила из устаревших расположений ( proguard.txt
для AAR или META-INF/proguard/<ProGuard-rule-files>
для JAR).