2014-01-05 4 views
15

Краткая форма: Каковы некоторые способы организации кода/POM для AAR, так что приложения, использующие этот AAR, имеют только зависимости, которые им действительно нужны?Gradle для Android, AAR и условные зависимости

Длинная форма:

Предположим, что у нас есть приложение, которое зависит от проекта Android библиотеки упаковываются в AAR (L).

L содержит смесь классов, и любое данное приложение (например, A) будет использовать только подмножество этих классов. Например:

  • L может содержать Fragment реализации для нативного уровня API 11 фрагментов, портированные фрагменты и ActionBarSherlock-приправленных фрагменты

  • L может содержать Activity реализации для регулярных мероприятий, FragmentActivity, ActionBarActivity и ActionBarSherlock-ароматизированная деятельность

  • L может вызывать события через LocalBroadcastManager, Square Отто и greenrobot в EventBus

  • И так далее

Эти случаи имеют два основных сходств, как я это вижу:

  1. приложения обычно заботятся только о некоторых из классов. Например, приложение, использующее Otto, не заботится о коде, который ссылается на EventBus greenrobot, или на приложение, которое использует ActionBarActivity, не будет заботиться о ActionBarSherlock.

  2. Если AAR является артефактом в репо, приложениям не понадобятся все возможные зависимости вверх, которые необходимы для построения AAR. Например, приложению, которое использует исходный уровень API 11 фрагментов не нужно будет support-v4 или actionbarsherlock, хотя сама AAR нуждается в них, чтобы построить AAR

Если бы мы должны были пойти с JAR-файлами вместо AARS и свалками управление зависимостями, это довольно просто. Построение JAR будет иметь зависимости от времени компиляции (например, support-v4). Однако приложения, использующие этот JAR, могут пропустить эти зависимости, и пока эти приложения не используют классы, которые действительно нуждаются в этих зависимостях, жизнь хороша.

Однако у меня возникли трудности с тем, как сделать то же самое с артефактами AAR и Maven, указанными в файле build.gradle. Если L имеет блок dependencies, ссылающийся на зависимости вверх, приложения будут, в свою очередь, загружать эти зависимости транзитивно, когда приложения зависят от L.

Одним из решений, которое, я уверен, будет работать, является разделение L на несколько библиотек. Например, используя сценарий фрагмента, мы могли бы иметь:

  • L1, который содержит реализацию для нативной версии фрагментов Level API 11, плюс любой общий код, необходимый для других сценариев. У этой библиотеки не было бы зависимостей вверх по течению.

  • L2, который содержит реализацию, которая использует backport фрагментов Android Support. L2 будет иметь зависимости от L1 и от support-v4.

  • L3, который содержит реализацию, в которой используются фрагменты с ароматом Шерлока. L3 будет иметь зависимости от L1 и actionbarsherlock.

Затем приложение будет выбрать, будет ли зависеть от L1, L2 или L3, и, следовательно, только получить необходимые вверх по течению зависимостей (если таковые имеется).

Мой вопрос: это лучшее решение? Или есть что-то еще в мире Gradle для Android, AAR и артефактов в стиле Maven, которые позволят приложениям зависеть от одного L? Я обеспокоен возможными комбинаторными взрывами библиотек для обработки разнообразного сочетания зависимостей вверх. Я также обеспокоен необычными приложениями, которые на самом деле do нуждаются в нескольких реализациях, и можем ли мы надежно определять зависимости для них (например, приложение в зависимости от L1 и L2, потому что это то, что автор этого приложения считает нужным для приложения) ,

Я знаю, что есть способы для приложения к блоку исключить зависимостей (см ответа Джозефа Эрла синтаксиса), так что приложение может зависеть от L, но затем блокирует actionbarsherlock вверх по течению зависимости, если она не нужна , Хотя это может сработать, в тех случаях, когда я являюсь автором L, я предпочитаю подход L1/L2/L3, поскольку это кажется более чистым.

Любые другие предложения?

+0

Я голосую за отделенные библиотеки, даже если он сильно болит в поддержке. Не нужно упоминать L1, поскольку L3 имеет транзитивную зависимость от L1 –

+0

Что означает аббревиатура AAR? – gunar

+0

@gunar: Android ARchive – CommonsWare

ответ

6

Я не знаю никакой функции управления зависимостями, которая помогла бы с этим.

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

  • Вы должны полагаться на пользователях L, чтобы удалить правильные зависимости ,
  • У вас будут классы в библиотеке, которые нелегко будет вырезать с помощью Proguard. Proguard не удалит что-либо, что расширяет Fragment/Activity/etc, и L должен предоставить файлы правил proguard, чтобы не удалять классы, которые расширяют поддержку Fragment/Activity/etc ... Это затруднит удаление нежелательных классов.
  • Некоторая реализация может иметь дополнительные ресурсы, и прямо сейчас мы не сможем избавиться от ненужных ресурсов.

Я думаю, что разделение библиотеки - это правильная вещь, но это будет сложно сделать, пока у нас не будет вкусов в библиотечных проектах. Как только у нас это будет, я думаю, что с ним будет намного легче справиться. У вас не будет базы L1 и L2/L3, расширяющей ее. Вместо этого у вас будет одна библиотека, которая генерирует разные варианты, каждая из которых имеет свои собственные зависимости.

С учетом размеров вкуса вы можете обрабатывать комбинации поддержки libs vs event libs, хотя вы бы окончательно получили некоторые взрывы, если вы добавите больше измерений.

Преимущества многовариантной библиотеки заключаются в том, что гораздо проще обмениваться кодами через подмножество вариантов, не вводя еще больше подбиблиотек. Вы также можете иметь двунаправленные ссылки между основным кодом и вкусами, которые вы не могли бы использовать с L2/L3 в зависимости от L1.

Что касается поддержки Ant/Eclipse, это определенно будет сложным. Я бы окончательно проигнорировал Анта. Если кто-то заботится только о построении командной строки, они должны уже переместиться в Gradle. Что касается Eclipse, то в какой-то момент у нас будет поддержка Gradle, но я понимаю, если вы не можете ждать.

+0

«Я бы проигнорировал Ant окончательно. Если кто-то заботится только о построении командной строки, они уже должны двигаться к Грейдлу ». - прямо сейчас, я предполагаю, что ~ 95% сборок командной строки, отличных от CI, выполняется через Ant. Переход от Ant к Gradle ускорится, как только Gradle для Android переместится в основное русло (например, developer.android.com), но до 2015 года Ant полностью исчезнет. Кроме того, на данный момент, если вы поддерживаете Eclipse, вы получаете бесплатную поддержку Ant. Независимо от того, спасибо за ваш ответ и дали, когда вы разместили его, пожалуйста, не забудьте спать! :-) – CommonsWare

+0

Это правда, большинство пользователей ADT, использующих CI, вероятно, будут использовать Ant для создания CI. –

6

В проекте приложения можно исключить транзитивные зависимости в Gradle (например, исключить включение ActionBarSherlock, если вы знаете, что он не будет использоваться), например.

dependencies { 
    compile('org.hibernate:hibernate:3.1') { 
    // Excluding a particular transitive dependency: 
    exclude module: 'cglib' //by artifact name 
    exclude group: 'org.jmock' //by group 
    exclude group: 'org.unwanted', module: 'iAmBuggy' //by both name and group 
    } 
} 

Вы можете также ProGuardDexGuard) уплотнить и раздеть неиспользуемый код.

Gradle doesn't yet support marking dependencies as optional как Maven делает (который может быть использован в проекте библиотеки).

+4

Только что заметил, кто задал вопрос! Вы, наверное, знаете большую часть этого: –

+0

Это то, что я имел в виду как «блокирующие зависимости». Вскоре я уточню вопрос, чтобы указать на ваш ответ. Тем не менее, 'exclude' похоже на то, что может понадобиться разработчику приложения, но в идеале этого избежать. ProGuard/DexGuard, безусловно, помогают, но не являются идеальными решениями. Мой вопрос заключается в том, как минимизировать необходимость во всем этом, в первую очередь, с точки зрения публикации библиотеки (или библиотек) в лучшей форме. Неразрешенная проблема, на которую вы ссылаетесь, несомненно, поможет. Благодаря! – CommonsWare

+0

Разделение на несколько библиотек, вероятно, лучше всего (например, многомодульный проект) - я не знаю лучшего решения. –

0

Ну, первое, что я хотел бы упомянуть, это конфигурации Gradle, которые на самом деле являются отражением конфигураций Ivy: модуль, который вы развертываете в каком-то репозитории, может иметь разные конфигурации, и каждая конфигурация может иметь свой собственный набор зависимостей. http://www.gradle.org/docs/current/userguide/dependency_management.html#ssub:multi_artifact_dependencies

Тем не менее, Maven не подходит для этого случая, поскольку в мире Maven нет конфигураций. А классификаторы артефактов не позволят вам иметь разные зависимости.

Что мы можем сделать с Maven, это удалить объявления зависимости времени компиляции от POM или пометить их областью provided. Возможность AFAIK указывать зависимости только времени компиляции будут доступны в будущих версиях плагина Android Gradle. https://code.google.com/p/android/issues/detail?id=58626

+0

«Но есть отдельная конфигурация с именем apk, используемым для сборки APK (AAR). Последняя конфигурация в основном расширяет время компиляции, и мы можем настроить то, что добавлено к ней». - Я вижу только синтаксис исключения локального JAR. «В результате мы можем достичь проекта, в который добавлен пакет поддержки android для компиляции конфигурации, но он не отражается в файле POM, загруженном в репозиторий, так что зависимость от вашей библиотеки не вызывает переходную выборку пакета поддержки». - Извините, но я не вижу, как это возможно с помощью 'apk.exclude'. И все же спасибо за ссылку! – CommonsWare

+0

Что касается синтаксиса, есть возможность добавить правило исключения с использованием имени модуля или группы. Я обновляю ответ. Тем не менее, я просто подумал, что на самом деле POM не генерируется из одной конкретной конфигурации. Но конфигурации используются для сопоставления областей зависимостей.Таким образом, возможно, рабочее решение состоит в том, чтобы иметь отдельную конфигурацию с «предоставленными» зависимостями (которые вообще не будут сопоставлены с POM) и вручную распространять путь к классам компиляции с этой конфигурацией. –

+0

Только что получил обновление по соответствующей проблеме: https://code.google.com/p/android/issues/detail?id=58626 –

Смежные вопросы