Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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)

like image 412
Jelle Fresen Avatar asked May 16 '16 09:05

Jelle Fresen


People also ask

How do I sync Gradle with dependencies?

Simply open the gradle tab (can be located on the right) and right-click on the parent in the list (should be called "Android"), then select "Refresh dependencies". This should resolve your issue.

Where should I add dependencies in Gradle project?

Gradle declares dependencies on JAR files inside your project's module_name /libs/ directory (because Gradle reads paths relative to the build.gradle file). This declares a dependency on version 12.3 of the "app-magic" library, inside the "com.example.android" namespace group.


1 Answers

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

like image 193
Hannes Struß Avatar answered Oct 07 '22 07:10

Hannes Struß