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

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

问题描述

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

task copyBuildDependencies(type: Copy) {删除$buildDir/dependencies"后评价{从configuration.releaseCompileClasspath进入$buildDir/dependencies"最后一个{FileTree files = fileTree("$buildDir/dependencies")files.forEach { 文件 ->if (file.isFile() && file.name.endsWith(".aar")) {复制 {来自 zipTree(file).matching { 包括*.jar"}进入$buildDir/dependencies"每个文件{it.path = it.path.replace(it.name, "${file.name}-${it.name}")}}}}}}}

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

依赖项{实现文件树(包括:['*.jar'],目录:'libs')...实现 'com.google.guava:guava:11.0.2'实现org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"实现 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.22.5'实现 'org.jetbrains.kotlinx:kotlinx-coroutines-android:0.22.5'//注意:这些是 Android 库项目实施项目(':genericutils')实施项目(':module2')...}

当我运行任务 copyBuildDependencies 时,我收到以下错误:

正在执行任务copyBuildDependencies"...执行任务:[copyBuildDependencies]按需配置是一个孵化功能.FAILURE:构建失败,出现异常.* 什么地方出了错:无法确定任务:BiometricInterfaceLib:copyBuildDependencies"的依赖关系.>无法解析配置 ':BiometricInterfaceLib:releaseCompileClasspath' 的所有任务依赖项.>项目的多个变体 :genericutils 匹配消费者属性:- 配置 ':genericutils:releaseApiElements' 变体 android-aidl:- 找到 artifactType 'android-aidl' 但不是必需的.- 需要 com.android.build.api.attributes.BuildTypeAttr 'release' 并找到兼容值 'release'.- 找到 com.android.build.api.attributes.VariantAttr 'release' 但不是必需的.- 需要 com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' 并找到兼容值 'Aar'.- 需要 org.gradle.usage 'java-api' 并找到兼容值 'java-api'.- 配置 ':genericutils:releaseApiElements' 变体 android-classes:- 找到 artifactType 'android-classes' 但不是必需的.- 需要 com.android.build.api.attributes.BuildTypeAttr 'release' 并找到兼容值 'release'.- 找到 com.android.build.api.attributes.VariantAttr 'release' 但不是必需的.- 需要 com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' 并找到兼容值 'Aar'.- 需要 org.gradle.usage 'java-api' 并找到兼容值 'java-api'.- 配置 ':genericutils:releaseApiElements' 变体 android-manifest:- 找到 artifactType 'android-manifest' 但不是必需的.- 需要 com.android.build.api.attributes.BuildTypeAttr 'release' 并找到兼容值 'release'.- 找到 com.android.build.api.attributes.VariantAttr 'release' 但不是必需的.- 需要 com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' 并找到兼容值 'Aar'.- 需要 org.gradle.usage 'java-api' 并找到兼容值 'java-api'.- 配置 ':genericutils:releaseApiElements' 变体 android-renderscript:- 找到 artifactType 'android-renderscript' 但不是必需的.- 需要 com.android.build.api.attributes.BuildTypeAttr 'release' 并找到兼容值 'release'.- 找到 com.android.build.api.attributes.VariantAttr 'release' 但不是必需的.- 需要 com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' 并找到兼容值 'Aar'.- 需要 org.gradle.usage 'java-api' 并找到兼容值 'java-api'.- 配置 ':genericutils:releaseApiElements' 变体 jar:- 找到 artifactType 'jar' 但不是必需的.- 需要 com.android.build.api.attributes.BuildTypeAttr 'release' 并找到兼容值 'release'.- 找到 com.android.build.api.attributes.VariantAttr 'release' 但不是必需的.- 需要 com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' 并找到兼容值 'Aar'.- 需要 org.gradle.usage 'java-api' 并找到兼容值 'java-api'.>项目 :module2 的多个变体与消费者属性相匹配:- 配置 ':module2:releaseApiElements' 变体 android-aidl:- 找到 artifactType 'android-aidl' 但不是必需的.- 需要 com.android.build.api.attributes.BuildTypeAttr 'release' 并找到兼容值 'release'.- 找到 com.android.build.api.attributes.VariantAttr 'release' 但不是必需的.- 需要 com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' 并找到兼容值 'Aar'.- 需要 org.gradle.usage 'java-api' 并找到兼容值 'java-api'.- 配置 ':module2:releaseApiElements' 变体 android-classes:- 找到 artifactType 'android-classes' 但不是必需的.- 需要 com.android.build.api.attributes.BuildTypeAttr 'release' 并找到兼容值 'release'.- 找到 com.android.build.api.attributes.VariantAttr 'release' 但不是必需的.- 需要 com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' 并找到兼容值 'Aar'.- 需要 org.gradle.usage 'java-api' 并找到兼容值 'java-api'.- 配置 ':module2:releaseApiElements' 变体 android-manifest:- 找到 artifactType 'android-manifest' 但不是必需的.- 需要 com.android.build.api.attributes.BuildTypeAttr 'release' 并找到兼容值 'release'.- 找到 com.android.build.api.attributes.VariantAttr 'release' 但不是必需的.- 需要 com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' 并找到兼容值 'Aar'.- 需要 org.gradle.usage 'java-api' 并找到兼容值 'java-api'.- 配置 ':module2:releaseApiElements' 变体 android-renderscript:- 找到 artifactType 'android-renderscript' 但不是必需的.- 需要 com.android.build.api.attributes.BuildTypeAttr 'release' 并找到兼容值 'release'.- 找到 com.android.build.api.attributes.VariantAttr 'release' 但不是必需的.- 需要 com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' 并找到兼容值 'Aar'.- 需要 org.gradle.usage 'java-api' 并找到兼容值 'java-api'.- 配置 ':module2:releaseApiElements' 变体 jar:- 找到 artifactType 'jar' 但不是必需的.- 需要 com.android.build.api.attributes.BuildTypeAttr 'release' 并找到兼容值 'release'.- 找到 com.android.build.api.attributes.VariantAttr 'release' 但不是必需的.- 需要 com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Aar' 并找到兼容值 'Aar'.- 需要 org.gradle.usage 'java-api' 并找到兼容值 'java-api'.* 尝试:使用 --stacktrace 选项运行以获取堆栈跟踪.使用 --info 或 --debug 选项运行以获得更多日志输出.使用 --scan 运行以获得完整的见解.* 在 https://help.gradle.org 获得更多帮助2 秒内构建失败16:39:07:任务执行完成copyBuildDependencies".

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

我创建了一个示例项目来帮助显示我所追求的结果和我遇到的问题:

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

输出将在$rootDir/dependencies"下.类似于以下内容:

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

这些 jars 是从您自己的源代码生成的,即您的 genericutilsma​​stermodule 源.如果库的传递依赖是.jar"格式,它们将进入.aarlibs/",如果它们是.aar"格式,我认为你不能简单地选择它的 classes.jar 而是去掉它的相关和必要的部分,除非你有一些特殊的要求和那些缺少的部分与您的项目无关.

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

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

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')
    ...
}

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'.

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

Edit: 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

--- Edit 2 ---

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.

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

解决方案

If I understand correctly

  1. your project is an Android library project.
  2. your copy task tries to copy all the jars inside the AAR library.
  3. rename the classes.jar.

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.'
} 

Run below command to verify

./gradlew copyModuleJars

Hope it helps.

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

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.

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

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

  • debug
    • genericutils-debug.jar
    • mastermodule-debug.jar
  • release
    • genericutils-release.jar
    • mastermodule-release.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.

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

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天全站免登陆