1

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
Crunchy234
  • 1,887
  • 2
  • 16
  • 21

1 Answers1

2

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. appcompat-v7-28.0.0-alpha3 contents

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.

shizhen
  • 12,251
  • 9
  • 52
  • 88
  • Thanks for that it is a much better way of doing it. I want to get the dependencies for the library as Jar files rather than just getting the jar from the output AAR file. This is why I was using `releaseCompileClasspath` as it seems to contain all of the dependency Jars and AARs. Is there another property that I could use that would contain all the dependency Jars and AARs? – Crunchy234 Jul 03 '18 at 00:36
  • The library dependencies are packaged inside the .aar under "libs". Also, note that the final .aar file actually is a zip file, by changing .aar to .zip, you can check its content. If your objective is to copy out the dependency jars of the library as well, then you can modify the "include('*.jar')" to "include('*.jar', 'libs/*.jar')". – shizhen Jul 03 '18 at 01:43
  • Ok I don't appear to have a "libs" folder in my AAR when I unzip it. I am looking to get a copy of all of the `implementation` and `api` dependencies which don't appear to be compiled into the AAR. Is there a way to force them to be compiled into a `libs` folder inside the AAR so that this method will work? – Crunchy234 Jul 03 '18 at 02:49
  • If your implementation is for module project, I mean the **Android Library Module project**, then it won't be included inside your .aar. This is how gradle manage project dependency. – shizhen Jul 03 '18 at 03:45
  • According to your original question, **./gradlew copyModuleJars** is actually doing what you expect. Have you put the gradle snippet into your top level build.gradle and given it a try? – shizhen Jul 03 '18 at 03:47
  • Sorry I'm not that good at explaining my issue. I have tried the code above and it does not do what I want. I have created an example project to give you a better idea of what I am after: https://gitlab.com/crunchy234/android-gradle-dependencies-export – Crunchy234 Jul 03 '18 at 05:01
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/174231/discussion-between-crunchy234-and-shizhen). – Crunchy234 Jul 03 '18 at 09:55