【问题标题】:Android gradle multiproject dependency resolutionAndroid gradle 多项目依赖解析
【发布时间】:2018-07-04 08:36:05
【问题描述】:

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

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}")
                        }
                    }
                }
            }
        }
    }
}

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

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 时,出现以下错误:

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 任务失败,因为它找不到依赖项。

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

--- 编辑 2 ---

需要库模块的依赖项而不是库的 Jar 的原因是可以创建 Xamarin 绑定库。

因此,Xamarin 绑定需要的是库的 AAR(示例代码中的主模块)和库依赖项的所有 Jars。 例如:

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

【问题讨论】:

    标签: android xamarin gradle xamarin.android android-gradle-plugin


    【解决方案1】:

    如果我理解正确

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

    可能下面就是你想要的。将此添加到 root 项目下的 build.gradle 中。

    // 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
    

    希望对您有所帮助。

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

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

    此外,您可以像我上面编辑的那样简单地修改 modulesExcluded 数组。并且可以去掉“hasProperty()”的条件检查。

    输出将在“$rootDir/dependencies”下。如下所示:

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

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

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

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

    【讨论】:

    • 感谢这是一种更好的方法。我想将库的依赖项作为 Jar 文件获取,而不仅仅是从输出 AAR 文件中获取 jar。这就是我使用releaseCompileClasspath 的原因,因为它似乎包含所有依赖项 Jars 和 AAR。我可以使用另一个包含所有依赖项 Jars 和 AAR 的属性吗?
    • 库依赖打包在“libs”下的 .aar 中。另外,请注意最终的 .aar 文件实际上是一个 zip 文件,通过将 .aar 更改为 .zip,您可以查看其内容。如果您的目标也是复制库的依赖 jar,那么您可以将“include('.jar')”修改为“include('.jar', 'libs/* .jar')"。
    • 好的,当我解压缩时,我的 AAR 中似乎没有“libs”文件夹。我正在寻找似乎没有被编译到 AAR 中的所有 implementationapi 依赖项的副本。有没有办法强制将它们编译到 AAR 内的 libs 文件夹中,以便此方法有效?
    • 如果您的实现是针对模块项目,我的意思是 Android 库模块项目,那么它将不会包含在您的 .aar 中。这就是 gradle 管理项目依赖的方式。
    • 根据您的原始问题, ./gradlew copyModuleJars 实际上正在按照您的预期进行。您是否将 gradle sn-p 放入顶层 build.gradle 并尝试过?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-23
    • 1970-01-01
    • 2013-12-12
    • 1970-01-01
    • 2018-11-10
    相关资源
    最近更新 更多