October 12

fat aar от Google. Дождались?

TL;DR

Google начали делать свой инструмент для создания fat aar, но сильно его не доработали. В Open Source остались сомнительные решения, написанные на Groovy, поэтому сделал свой с блэкджеком, в смысле с shadow-jar.

https://medium.com/@vpjigin/create-aar-file-from-android-library-code-ebc81283f211

Интро

Думаю многие слышали про такой формат дистрибуции нескольких библиотек или Gradle модулей, запакованных в один артефакт. В любом случае напомню, что по умолчанию каждый Gradle модуль с подключенным плагином com.android.library можно собрать как один aar, но могут быть случаи, когда все же есть необходимость объединить несколько библиотека в одном aar артефакте. Такая идея не нова. Например, в Java мире это называется uber jar или fat jar и готовится он с помощью довольно известных плагинов maven-shade-plugin и shadow-jar для Gradle.

Необходимость

Так ли нам нужен fat aar? В основном, нет. Если правильно организовать многомодульность в проекте и заложить то, что эти модули будут опубликованы как библиотеки, и все будет прекрасно.

Необходимость может появиться в ряде случаев. Например, если у вас есть локальные jar и aar файлы, которые нужно опубликовать вместе с библиотекой, но исходники уже утеряны. Другой пример, если не хочется раскрывать идеальную многомодульную архитектуру для пользователей библиотеки. В конце концов, может быть случай, что нужно поделиться куском приложения с другим проектом, а сроки горят.

Еще причин почему это может быть нужно, можете найти в issue по этой теме, который висит аж с 2017 года. В комментарии там пришли люди из разных компаний. Например, вот свежий комментарий человека из Netflix:

https://issuetracker.google.com/u/0/issues/62121508#comment200

А Google что, не делает? На самом деле начинали делать в 2022 и назвали они свое творение Fused Library.

Fused Library

Да, плагин назван так, что его вряд ли кто-то нашёл бы... Но все же он нашёлся. К тому же, появлялись коммиты с обновлениями буквально в дни, когда я его смотрел.

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

Я потратил пару вечеров, пытаясь его завести, но лишь расстроился тому, насколько сырой все же инструмент.

1. Сразу бросается в глаза то, что он не умеет формировать aar файл...

Он все объединяет в jar. Понятно, что ошибка в том, не выставлено расширение файла при конфигурации задачи, но уже тут можно делать выводы, что решение нерабочее. И все же продолжил исследование инструмента на случай, если надумаю починить и доработать.

2. По картинке из пункта 1 можно заметить, что нет никаких классов в собранном jar. Все дело в том, что плагин даже это не умел делать, так как там забыли упаковать классы в jar. Благо это исправили в июле этого года.

https://cs.android.com/android-studio/platform/tools/base/+/2dbae3aaee02cb2beb6e31ad8b2b5edbafebd511

3. Нет поддержки различных build variants. Поддерживает только один build type - debug. С учетом того, что fat aar чаще нужен в релизной сборке, такое нам не подойдет.

https://cs.android.com/android-studio/platform/tools/base/+/mirror-goog-studio-main:build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/FusedLibraryPlugin.kt;drc=1e11a7a99f7873f920b1c89eb134dbcc4af0c1af;l=303

Тут завершу список проблем, потому что их просто нельзя починить. Да, реализация интересная и отличается от всего, что было до этого, но его нельзя доработать без форка всего AGP, так как используется internal api. К тому же, по последним изменениям непонятно, какие планы у разработчиков. Ясно одно, что проект все еще экспериментальный, поэтому велика вероятность того, что решения, которые будут приниматься, не совпадут с моими предложениями. (Как-то у меня была попытка законтрибьютить в AGP - там так же все же предпочли сделать по своему.)

Учитывая все это, прекратил ковырять этот плагин. Сильно сырой все же.

Что в Open Source?

Взяв весь свой пыл куда-нибудь закотрибьютить пошёл искать решения в GitHub. Нашёл пару решений, но самое популярное, написанное с использованием Groovy, уже заброшено. Этот заброшенный плагин был форком других похожих плагинов. Теперь уже его форкнули для поддержки AGP 8 и нетранзитивных R-классов.

В актуальном форке хоть и решили проблемы с AGP 8, но остались другие.

1. Есть проблема со слиянием ресурсов с одинаковыми id. Такое может быть, потому что плагин соединяет ресурсы только после того, как сформирует конечные артефакты.

2. Нет возможности выполнять формировать shaded jar, то есть перемещать классы в разные пакеты. Такое, например, делали в компиляторе Kotlin, чтобы зависимость для Idea не конфликтовала с зависимостью для Gradle. Ну и по проекту можно найти разные применения shadow-jar.

Пошёл искать дальше и обнаружил ещё один плагин. Он полностью написан на Kotlin, имеет еще больше проблем, некоторые вещи недоделаны, а поддерживается только AGP 4. Напомню, что на дворе AGP 8 и не за горами AGP 9.

И все же я решил оживить именно этот проект. Потому что, по моему мнению, автор старался делать иначе, чем в других проектах, и так, чтобы это было надежно. Это можно заметить по исследованию задач для формирования aar, результат которых он оставил в виде комментариев в коде.

Grease

Итак, что было сделано:

  • Переход с AGP 4 на AGP 8.
  • Доработал слияние ресурсов, вдохновившись Fused Library. Решение получилось надежнее, чем у fat-aar-android.
  • Подключил shadow-jar и научил его трансформировать метаданные Kotlin и AndroidManifest.xml. Кроме того, работу shadow-jar можно конфигурировать.

Может показаться, что это немного, но по сути плагин был полностью переписан в рамках первого пункта.

Было большим удивлением то, что после того, как освежил инструмент, у него сразу появились клиенты, которые начали накидывать issues. Количество звезд при этом выросло в два раза. Поэтому, пока Google доделывает Fused Library, есть альтернатива в виде Grease.

Опубликовано в Полуночные Зарисовки