Android Gradle多项目依赖关系解析 [英] Android gradle multiproject dependency resolution

查看:516
本文介绍了Android Gradle多项目依赖关系解析的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的Android项目中,我有一个将构建依赖项复制到外部目录的任务,如下所示:

In my Android project I have a task for copying the build dependencies to an external directory as below:

task copyBuildDependencies(type: Copy) {
    delete "$buildDir/dependencies"
    afterEvaluate {
        from configurations.releaseCompileClasspath
        into "$buildDir/dependencies"

        doLast {
            FileTree files = fileTree("$buildDir/dependencies")
            files.forEach { file ->
                if (file.isFile() && file.name.endsWith(".aar")) {
                    copy {
                        from zipTree(file).matching { include "*.jar" }
                        into "$buildDir/dependencies"
                        eachFile {
                            it.path = it.path.replace(it.name, "${file.name}-${it.name}")
                        }
                    }
                }
            }
        }
    }
}

我具有正常的项目依赖项:

I have normal dependencies with project dependencies:

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    ...
    implementation 'com.google.guava:guava:11.0.2'
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.22.5'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:0.22.5'
    // Note: These are Android Library projects
    implementation project(':genericutils')
    implementation project(':module2')
    ...
}

当我运行任务copyBuildDependencies时,出现以下错误:

When I run the task copyBuildDependencies I get the following error:

Executing task 'copyBuildDependencies'...

Executing tasks: [copyBuildDependencies]

Configuration on demand is an incubating feature.

FAILURE: Build failed with an exception.

* What went wrong:
Could not determine the dependencies of task ':BiometricInterfaceLib:copyBuildDependencies'.
> Could not resolve all task dependencies for configuration ':BiometricInterfaceLib:releaseCompileClasspath'.
> More than one variant of project :genericutils matches the consumer attributes:
    - Configuration ':genericutils:releaseApiElements' variant android-aidl:
        - Found artifactType 'android-aidl' but wasn't required.
        - Required com.android.build.api.attributes.BuildTypeAttr 'release' and found compatible value 'release'.
        - Found com.android.build.api.attributes.VariantAttr 'release' but wasn't required.
        - Required com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' and found compatible value 'Aar'.
        - Required org.gradle.usage 'java-api' and found compatible value 'java-api'.
    - Configuration ':genericutils:releaseApiElements' variant android-classes:
        - Found artifactType 'android-classes' but wasn't required.
        - Required com.android.build.api.attributes.BuildTypeAttr 'release' and found compatible value 'release'.
        - Found com.android.build.api.attributes.VariantAttr 'release' but wasn't required.
        - Required com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' and found compatible value 'Aar'.
        - Required org.gradle.usage 'java-api' and found compatible value 'java-api'.
    - Configuration ':genericutils:releaseApiElements' variant android-manifest:
        - Found artifactType 'android-manifest' but wasn't required.
        - Required com.android.build.api.attributes.BuildTypeAttr 'release' and found compatible value 'release'.
        - Found com.android.build.api.attributes.VariantAttr 'release' but wasn't required.
        - Required com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' and found compatible value 'Aar'.
        - Required org.gradle.usage 'java-api' and found compatible value 'java-api'.
    - Configuration ':genericutils:releaseApiElements' variant android-renderscript:
        - Found artifactType 'android-renderscript' but wasn't required.
        - Required com.android.build.api.attributes.BuildTypeAttr 'release' and found compatible value 'release'.
        - Found com.android.build.api.attributes.VariantAttr 'release' but wasn't required.
        - Required com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' and found compatible value 'Aar'.
        - Required org.gradle.usage 'java-api' and found compatible value 'java-api'.
    - Configuration ':genericutils:releaseApiElements' variant jar:
        - Found artifactType 'jar' but wasn't required.
        - Required com.android.build.api.attributes.BuildTypeAttr 'release' and found compatible value 'release'.
        - Found com.android.build.api.attributes.VariantAttr 'release' but wasn't required.
        - Required com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' and found compatible value 'Aar'.
        - Required org.gradle.usage 'java-api' and found compatible value 'java-api'.
> More than one variant of project :module2 matches the consumer attributes:
    - Configuration ':module2:releaseApiElements' variant android-aidl:
        - Found artifactType 'android-aidl' but wasn't required.
        - Required com.android.build.api.attributes.BuildTypeAttr 'release' and found compatible value 'release'.
        - Found com.android.build.api.attributes.VariantAttr 'release' but wasn't required.
        - Required com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' and found compatible value 'Aar'.
        - Required org.gradle.usage 'java-api' and found compatible value 'java-api'.
    - Configuration ':module2:releaseApiElements' variant android-classes:
        - Found artifactType 'android-classes' but wasn't required.
        - Required com.android.build.api.attributes.BuildTypeAttr 'release' and found compatible value 'release'.
        - Found com.android.build.api.attributes.VariantAttr 'release' but wasn't required.
        - Required com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' and found compatible value 'Aar'.
        - Required org.gradle.usage 'java-api' and found compatible value 'java-api'.
    - Configuration ':module2:releaseApiElements' variant android-manifest:
        - Found artifactType 'android-manifest' but wasn't required.
        - Required com.android.build.api.attributes.BuildTypeAttr 'release' and found compatible value 'release'.
        - Found com.android.build.api.attributes.VariantAttr 'release' but wasn't required.
        - Required com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' and found compatible value 'Aar'.
        - Required org.gradle.usage 'java-api' and found compatible value 'java-api'.
    - Configuration ':module2:releaseApiElements' variant android-renderscript:
        - Found artifactType 'android-renderscript' but wasn't required.
        - Required com.android.build.api.attributes.BuildTypeAttr 'release' and found compatible value 'release'.
        - Found com.android.build.api.attributes.VariantAttr 'release' but wasn't required.
        - Required com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' and found compatible value 'Aar'.
        - Required org.gradle.usage 'java-api' and found compatible value 'java-api'.
    - Configuration ':module2:releaseApiElements' variant jar:
        - Found artifactType 'jar' but wasn't required.
        - Required com.android.build.api.attributes.BuildTypeAttr 'release' and found compatible value 'release'.
        - Found com.android.build.api.attributes.VariantAttr 'release' but wasn't required.
        - Required com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' and found compatible value 'Aar'.
        - Required org.gradle.usage 'java-api' and found compatible value 'java-api'.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 2s
16:39:07: Task execution finished 'copyBuildDependencies'.

我可以在configurations.releaseCompileClasspath上使用排除模块选项,但是assembleRelease任务失败,因为它找不到依赖项.

I can use the exclude module option on configurations.releaseCompileClasspath but then the assembleRelease task fails because it can not find the dependencies.

我创建了一个示例项目,以帮助显示我所追求的结果以及遇到的问题: https://gitlab.com/crunchy234/android-gradle-dependencies-export

I have created an example project to help show the result that I am after and the issue I am having: https://gitlab.com/crunchy234/android-gradle-dependencies-export

-编辑2 ---

需要库模块而不是库的Jar的原因是为了可以创建Xamarin Bindings库.

The reason for wanting the dependencies of the library module rather than the Jar for the library is so that a Xamarin Bindings library can be created.

因此,Xamarin绑定所需的是库的AAR(在示例代码的情况下为mastermodule)和库依赖项的所有Jars. 例如:

So what is wanted for the Xamarin Bindings is the AAR for the library (mastermodule in the case of the example code) and all of the Jars for the libraries dependencies. E.g:

mastermodule/build/dependencies/
├── animated-vector-drawable-28.0.0-alpha3.aar-classes.jar
├── annotations-13.0.jar
...
├── collections-28.0.0-alpha3.jar
├── common-1.1.1.jar
├── coordinatorlayout-28.0.0-alpha3.aar-classes.jar
...
etc

推荐答案

如果我理解正确

  1. 您的项目是一个Android库项目.
  2. 您的复制任务尝试复制AAR库中的所有jar.
  3. 重命名classes.jar.

可能下面是您想要的.将其添加到 root 项目下的build.gradle中.

Probably below is what you want. Add this into the build.gradle under root project.

// Add this into the build.gradle under **root** project.
// Add the modules that you want to exclude from having this copyXXXJar task.
def modulesExcluded = [
        'app',
        'mastermodulewantedoutput'
]

subprojects { prj ->

    // Skip excluded modules
    if (modulesExcluded.contains(prj.name)) {
        prj.afterEvaluate {
            tasks['preBuild'].dependsOn(copyModuleJars)
        }
        return
    }

    prj.afterEvaluate {

        /**
         * Dynamically create task "copyXXXJar" according to build variant of each library module.
         */
        android.libraryVariants.all { variant ->

            def capitalizedVariantName = variant.name.capitalize()
            def variantName = variant.flavorName
            if (!variantName || variantName == "") {
                variantName = variant.buildType.name
            } else {
                variantName += "-${variant.buildType.name}"
            }
            //================================================================================
            // Define build/copy variant jar and copy to dependencies
            //================================================================================
            def copyJarTask = project.tasks.create("copy${capitalizedVariantName}Jar", Copy) {
                group "Copy Jar"
                description "Rename the classes.jar to ${project.name}-${variantName}.jar and copy it into dist folder."


                def fromDirModule = "$buildDir/outputs/aar/${project.name}-${variantName}.aar"
                def intoDirModule = "$rootDir/dependencies/$variant.buildType.name"
                from(zipTree(fromDirModule))
                into(intoDirModule)
                include('*.jar')
                include('libs/*.jar')
                rename('classes.jar', "${project.name}-${variantName}.jar")

                dependsOn "assemble${capitalizedVariantName}"
            }
            copyModuleJars.dependsOn(copyJarTask)
        }
    }
}

// Task to copy all the modules' jars. It can be run with command [ ./gradlew copyModuleJars ]
task copyModuleJars {
    group = 'Copy Jar'
    description = 'Copy the classes.jar from each module.'
} 

运行以下命令进行验证

./gradlew copyModuleJars

希望它会有所帮助.

--------- 已编辑 ----------

--------- Edited ----------

我检查了您的gitlab项目.看起来您只需要.aar内部的jar.我想说这可能会引起一些问题,因为您删除了关联的res文件,aidl文件,资产和R.txt等,它们被视为.aar库的必需部分.例如,当您解压缩一个依赖项 appcompat-v7-28.0.0-alpha3 时,它实际上将具有以下布局,不仅限于classes.jar .

I checked your gitlab project. It looks you only need the jar inside the .aar. I'd like to say this may cause some problems because you drop the associated res files, aidl file, assets and R.txt, etc which are considered as necessary parts of the .aar library. For example, one of your dependency aar appcompat-v7-28.0.0-alpha3, will actually have below layout when you unzip it, NOT ONLY the classes.jar.

此外,您可以像我在上面编辑的那样简单地修改 modulesExcluded 数组.并且可以删除条件检查" hasProperty()".

Additionally, you can simply modify the modulesExcluded array as I edited above. And the condition check of "hasProperty()" can be removed.

输出将在" $ rootDir/dependencies "下.如下所示:

The output will be under "$rootDir/dependencies". Something like below:

  • 调试
    • genericutils-debug.jar
    • mastermodule-debug.jar
    • debug
      • genericutils-debug.jar
      • mastermodule-debug.jar
      • genericutils-release.jar
      • mastermodule-release.jar

      这些jar是从您自己的源代码生成的,即您的 genericutils mastermodule 源.如果库的传递依赖项为" .jar "格式,则它们将进入 .aar 的" libs/"格式为" .aar ",我认为您不能简单地选择其 classes.jar ,而是剥离其关联和必要的部分,除非您有一些特殊要求,缺少部分与您的项目无关.

      These jars are generated from your own source code, i.e. your genericutils and mastermodule sources. If the transitive dependencies of library are in ".jar" format, they will go into "libs/" of the .aar, if they are in ".aar" format, i don't think you can simply pick its classes.jar but strip its associated and necessary parts unless you have some special requirement and those missing part don't matter with your project.

      -------- 已编辑2 ---------

      -------- Edited 2 ---------

      如果您只关心源代码,而在代码逻辑中不使用任何资源(res,R.txt,aidl,jni等),例如可能您的 genericutils 模块就是这种情况,那么您只需简单地选择classes.jar.当您将其用作普通Java库时,它不会引起任何问题.

      In case that you only concern about the source code and don't use any resources (res, R.txt, aidl, jni etc) inside your code logic, e.g. probably your genericutils module will be such kind of case, then you can simply pick up the classes.jar only. It won't cause any issue when you use it as a normal Java library.

      这篇关于Android Gradle多项目依赖关系解析的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆