Конфигурация Gradle с многомодульной библиотекой Android

Предыдущая история

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

compile 'com.companyname.sdk:android-sdk:2.x'

и сейчас мы переписываем библиотеку с нуля, чтобы создать V3.

При этой реорганизации нам удалось разбить библиотеку на модули. Так что можно сказать, что на V3 у нас были бы следующие артефакты

compile 'com.companyname.sdk:core:3.x'
compile 'com.companyname.sdk:extra_1:3.x'
compile 'com.companyname.sdk:extra_2:3.x'
compile 'com.companyname.sdk:extra_ ....

и это даст в структуре gradle следующие модули:

root:
  |- test_app (apk just for testing, not deployed anywhere)
  |- sdk (aka: core)
  |- extra_1
  |- extra_2
  |- extra_ ... etc

для каждого модуля extra на их build.gradle есть provided (':sdk'), так что они могут использовать все из модуля sdk, но фактически не компилировать его внутри себя.

но я также хотел бы предоставить простой способ миграции для существующих хост-приложений. Это означает, что я хотел бы, чтобы в V3 также был следующий артефакт, который объединяет core и extra_1 (что в основном то, что сейчас есть в V2).

compile 'com.companyname.sdk:android-sdk:3.0.0'

Все это звучит великолепно в теории, но мне очень трудно понять структуру градиента, позволяющую мне легко экспортировать все это.

Чего я хочу достичь

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

  • android-sdk, который включает в себя как core, так и extra_1
  • core
  • extra_1
  • ... все остальные дополнения

Что я пробовал

  • добавьте дополнительный модуль с именем legacy, примените com.android.library без кода и добавьте compile project для обоих других модулей. Он генерирует пустой aar

  • добавьте базовые/устаревшие типы сборки с исходными наборами из обоих модулей. Никогда не создавалось 2 aar

  • добавить базовые/устаревшие productFlavours с исходными наборами из обоих модулей. Не компилируется, потому что не может найти импорт из sdk, который объявлен в extra_1 (некоторые из них генерируются во время обработки аннотаций или ломбока)

  • добавить основной/устаревший продуктВкусы с compile project('extra_1'). Не компилируется из-за циклической зависимости между sdk и extra_1.

Ответить

Основываясь на ответе Габриэль, я в конечном итоге копнул больше и обнаружил, что вариант создания дополнительного модуля с зависимостями является правильным. Он сгенерирует AAR с пустым манифестом и пустыми классами. Но важной частью является файл POM, который он сгенерирует и будет включать в себя правильные зависимости.

Предостережение относительно подхода касается конфигурации плагина maven-publish. Обычно вам нужен объект publishing с узлом publications и pom.withXml. мой был следующим:

   pom.withXml {
                def root = asNode()
                def license = root.appendNode('licenses').appendNode('license')
                license.appendNode('name', 'The Apache Software License, Version 2.0')
                license.appendNode('url', 'http://www.apache.org/licenses/LICENSE-2.0.txt')
                license.appendNode('distribution', 'repo')
                def dependenciesNode = asNode().appendNode('dependencies')
                configurations.compile.allDependencies.each { dependency ->
                    def dependencyNode = dependenciesNode.appendNode('dependency')
                    dependencyNode.appendNode('groupId', dependency.group)
                    dependencyNode.appendNode('artifactId', dependency.name)
                    dependencyNode.appendNode('version', dependency.version)
                }
            }

Проблема с этим подходом заключается в том, что dependency.version (в конце) не указан, и поэтому он генерирует файл POM с <version>unspecified</version>.

Решение здесь простое: замените поздний номер некоторой переменной, которая у вас есть в сценарии, с правильным номером версии. Мой выглядел так:

dependencyNode.appendNode('version', "${rootProject.ext.SDK_VERSION}")

person Budius    schedule 20.01.2017    source источник


Ответы (1)


Вы должны сделать что-то вроде этого:

root:
  |- test_app (apk just for testing, not deployed anywhere)
  |- core 
  |- extra_1
  |- extra_2
  |- extra_ ... etc
  |- android-sdk

In core/build.gradle:

apply plugin: 'com.android.library'
//...

In extra1/build.gradle:

apply plugin: 'com.android.library'
//...
dependencies {
   compile project(':core')
}

In android-sdk/build.gradle:

apply plugin: 'com.android.library'
//...
dependencies {
   compile project(':core')
   compile project(':extra')
}
person Gabriele Mariotti    schedule 20.01.2017
comment
Большое спасибо! Я тестировал это раньше и отбросил, потому что он генерировал AAR с пустыми классами и пустым манифестом. Но с вашим вкладом я в конечном итоге копнул больше и понял, что все, что нужно для генерации, - это файл POM, правильно устанавливающий зависимости. Я отредактирую свой вопрос с парой предостережений, которые я нашел по этому поводу. - person Budius; 20.01.2017
comment
Вместо compile project используйте implementation project. Когда модуль B зависит от модуля C с ключевым словом compile, а A зависит от B, A также зависит от C. Если мы заменим compile на implementation, A больше не будет зависеть от C. - person Piotr Aleksander Chmielowski; 19.02.2018