Android gradle multiproject dependency resolution


Android gradle multiproject dependency resolution



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:


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



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


configurations.releaseCompileClasspath


assembleRelease



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




1 Answer
1



If I understand correctly



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:



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.





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 3 at 0:36


releaseCompileClasspath





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 3 at 1: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 3 at 2:49


implementation


api


libs





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 3 at 3: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 3 at 3:47







By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

api-platform.com Unable to generate an IRI for the item of type

How to set up datasource with Spring for HikariCP?

PHP contact form sending but not receiving emails