Создайте один файл AAR из нескольких модулей с помощью Gradle

Как и многие другие, я пытаюсь создать один файл AAR из своего многомодульного проекта Android.

Согласно этой публикации, в настоящее время не поддерживается командой Android из-за различных ограничений (управление разрешением и зависимостями, слияние манифестов, ...).

Я пытаюсь придумать свое собственное решение, которое будет соответствовать моим потребностям. Я знаю, что у меня нет дублированных ресурсов, а внешние зависимости (например, библиотеки поддержки) предоставляются людьми, использующими мою библиотеку.

Моя структура похожа на эту:

/root
|- lib1
|- lib2
|- lib3

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

/root
|- lib1
|- lib2
|- lib3
|- distribute

Это файл build.gradle модуля distribute:

apply from: '../common.gradle' // This simply configure properties shared accross all modules
apply plugin: 'com.android.library'

def allModules = rootProject.allprojects.collect { it.name } - [rootProject.name, name]
def whiteLabelDependencies = [
        whiteLabel1: allModules - ['lib2'],
        whiteLabel2: allModules,
]

android {
    def buildTypeNames = buildTypes.collect { it.name }
    def whiteLabelTypes = productFlavors.findAll { 'type'.equals(it.dimension) }.collect { it.name }

    whiteLabelDependencies.each { whiteLabel ->
        def modules = whiteLabel.value
        def whiteLabelName = whiteLabel.key

        whiteLabelTypes.each { whiteLabelType ->
            def productFlavor = whiteLabelName + whiteLabelType.capitalize()

            buildTypeNames.each { buildType ->
                def sourceSet = productFlavor + buildType.capitalize()
                def folders = ['main', whiteLabelName, whiteLabelType, productFlavor, whiteLabelName + buildType.capitalize(), sourceSet]

                android.sourceSets.maybeCreate(sourceSet)
                android.sourceSets.getByName(sourceSet) {
                    assets.srcDirs = getPathsList(modules, folders, 'assets')
                    java.srcDirs = getPathsList(modules, folders, 'java')
                    res.srcDirs = getPathsList(modules, folders, 'res')
                    resources.srcDirs = getPathsList(modules, folders, 'resources')
                }
            }
        }
    }
}

afterEvaluate {
    whiteLabelDependencies.each { whiteLabel ->
        def assembleTask = rootProject.tasks.getByPath(":${name}:assemble${whiteLabel.key.capitalize()}")
        assembleTask.dependsOn whiteLabel.value.collect { ":${it}:assemble${whiteLabel.key.capitalize()}" }
    }
}

dependencies {
    whiteLabelDependencies.each { whiteLabel ->
        whiteLabel.value.each {
            "${whiteLabel.key}Compile" project(path: ":${it}", configuration: project.whiteLabelConfigurationName)
        }
    }
}

def List<File> getPathsList(List<String> modules, List<String> folders, String sourceType) {
    return modules.collect { module ->
        folders.collect { folder ->
            new File("${rootProject.rootDir}/${module}/src/${folder}/${sourceType}")
        }.findAll {
            it.exists()
        }
    }.flatten()
}

Кажется, это почти работает, за исключением того, что во время выполнения происходит сбой приложения, потому что оно не может найти класс R каждого модуля libx, а только один из модуля distribute. Есть ли способ заставить Gradle включать класс R каждого модуля.

Я знаю, что файл для каждого модуля создается в $module/build/generated/source/r/$whiteLabel/$buildType/$package/$module/R.java, но я не знаю, как его включить и предотвратить дублирование классов (каждый модуль может зависеть от другого).


person Gaëtan    schedule 28.06.2016    source источник
comment
libX/R.class классы объединены в один distribute/R.class?   -  person naXa    schedule 28.06.2016
comment
Нет. Каждый lib имеет свой собственный класс R, потому что каждый модуль имеет свой собственный пакет (я думаю, это ограничение/требование плагина Android Gradle). Последний класс distribute/R содержит все необходимые поля, но каждый модуль импортирует свой собственный класс R.   -  person Gaëtan    schedule 28.06.2016
comment
Поэтому (я думаю) вы должны переписать импорт во всех модулях на distribute/R во время сборки.   -  person naXa    schedule 28.06.2016
comment
Я попытался сделать это с помощью Transform API, но не нашел ни надлежащей документации, ни примера того, как изменить импорт во время компиляции.   -  person Gaëtan    schedule 28.06.2016
comment
@Gaëtan, у меня похожая проблема. Скажите, пожалуйста, удалось ли вам решить эту проблему, как вы это сделали?? Любая помощь будет оценена по достоинству.   -  person Naseeb Sheoran    schedule 27.09.2016
comment
Возможный дубликат Android Studio, как упаковать один AAR из нескольких библиотечных проектов?   -  person norbDEV    schedule 05.01.2018