Saturday, July 9, 2016

How to setup dependencies in a multi module Android Gradle project with interdependencies?

Leave a Comment

The Question

How do I setup the dependencies of the modules in an Android Gradle project, where the modules have dependencies on each other, such that I can deploy a build of a new snapshot or release version of all modules in one go?

Project Setup

I have a project that consists of 2 modules: lib-core and lib-help, with lib-help depending on lib-core. I want to publish lib-core and lib-help seperately to Maven Central, such that the pom file of lib-help specifies the dependency on lib-core with the correct version.

The project is structured as follows:

/my-project-name | |--/lib-core |  |-- build.gradle |  |-- gradle.properties | |--/lib-help |  |-- build.gradle |  |-- gradle.properties | |-- build.gradle |-- gradle.properties |-- settings.gradle |-- gradle-mvn-push.gradle 

The project configuration files are as follows, showing only the relevant parts (by my judgement):

settings.gradle:

include ':lib-core', ':lib-help' 

gradle.properties:

GROUP=com.company VERSION=5.0.0-SNAPSHOT 

gradle-mvn-push.gradle:

apply plugin: 'maven'  afterEvaluate { project ->     uploadArchives {         repositories {             mavenDeployer {                 // GROUP is defined in <root>/gradle.properties                 pom.groupId = GROUP                 // ARTIFACT is defined in <root>/<module>/gradle.properties                 pom.artifactId = ARTIFACT                 // VERSION is defined in <root>/gradle.properties                 pom.version = VERSION             }         }     } }  // Contains a lot more to fill in other meta-data like project name, // developer name, github url, javadoc, signing of the artifacts, etc, etc.. 

lib-core/gradle.properties:

ARTIFACT=my-lib-core 

lib-core/build.gradle:

apply plugin: 'com.android.library'  // Contains more code to configure the android stuff, not relevant for this question  dependencies {     compile fileTree(dir: 'libs', include: ['*.jar']) }  apply from: rootProject.file('gradle-mvn-push.gradle') 

lib-help/gradle.properties:

ARTIFACT=my-lib-help 

lib-help/build.gradle:

apply plugin: 'com.android.library'  // Contains more code to configure the android stuff, not relevant for this question  dependencies {     compile fileTree(dir: 'libs', include: ['*.jar'])     compile project(':lib-core') }  apply from: rootProject.file('gradle-mvn-push.gradle') 

The Problem

When I run gradlew clean :lib-core:uploadArchives :lib-help:uploadArchives, everything compiles nicely and uploads are being pushed to the correct repository. In the Nexus Repository Manager I can see the artifacts for both modules with the correct name, version, signing, etc., but the dependency of lib-help on lib-core in the generated pom.xml is wrong. It uses the project name as groupId, the module name as the artifactId and an unspecified version name:

<dependency>     <groupId>my-project-name</groupId>     <artifactId>lib-core</artifactId>     <version>unspecified</version>     <scope>compile</scope> </dependency> 

Consequently, projects using lib-help as a dependency can't resolve the lib-core dependency. The correct values that should have been in lib-help's pom.xml are groupId=com.company, artifactId=my-lib-core and version=5.0.0-SNAPSHOT.

To fix this, I thought I'd use a maven dependency in lib-help, instead of a module dependency, like this:

dependencies {     compile fileTree(dir: 'libs', include: ['*.jar'])     compile 'com.company:my-lib-core:' + VERSION } 

Naturally, this version does not exist before the uploadArchives command of lib-core has been executed, but gradle wants to resolve the dependencies of all modules before starting execution of any of the given commands. Thus, it can't resolve this dependency and quits with an error while configuring the gradle projects. Now, I can work around this by temporarily setting the dependency of lib-help to project(':lib-core'), then release lib-core, then adjust the dependency of lib-help to 'com.company:my-lib-core:5.0.0-SNAPSHOT', then release lib-help, but that just doesn't seem the right way. It invites human mistakes (what if I accidentally increase the version number between the to uploadArchives commands?) and it takes several manual, strictly ordered steps.

The Question (reprise)

How do I setup the dependencies of the modules in an Android Gradle project, where the modules have dependencies on each other, such that I can deploy a build of a new snapshot or release version of all modules in one go? (e.g., but not necessarily, with the command gradlew clean :lib-core:uploadArchives :lib-help:uploadArchives)

1 Answers

Answers 1

It's possible to keep the local project dependencies (compile project(':core')), if you rewrite the POM before uploading:

afterEvaluate { project ->   uploadArchives {     repositories {       mavenDeployer {         // ... other config here ...          pom.whenConfigured { pom ->           pom.dependencies.forEach { dep ->             if (dep.getVersion() == "unspecified") {               dep.setGroupId(GROUP)               dep.setVersion(VERSION_NAME)             }           }         }       }     }   } } 

Here's an example of a working project: https://github.com/hannesstruss/WindFish

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment