Instantly share code, notes, and snippets.

Embed
What would you like to do?
Gradle script for publishing Android library to local Maven repository using maven-publish plugin. With dependencies (also handling transitive: false and custom exclude rules), including sources and javadoc.
apply plugin: 'maven-publish'
task androidJavadocs(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
android.libraryVariants.all { variant ->
if (variant.name == 'release') {
owner.classpath += variant.javaCompile.classpath
}
}
exclude '**/R.html', '**/R.*.html', '**/index.html'
}
task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
classifier = 'javadoc'
from androidJavadocs.destinationDir
}
task androidSourcesJar(type: Jar) {
classifier = 'sources'
from android.sourceSets.main.java.srcDirs
}
publishing {
publications {
maven(MavenPublication) {
//groupId 'cz.example'
//artifactId 'custom-artifact'
//version = android.defaultConfig.versionName
artifact bundleReleaseAar
artifact androidJavadocsJar
artifact androidSourcesJar
pom.withXml {
final dependenciesNode = asNode().appendNode('dependencies')
ext.addDependency = { Dependency dep, String scope ->
if (dep.group == null || dep.version == null || dep.name == null || dep.name == "unspecified")
return // ignore invalid dependencies
final dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', dep.group)
dependencyNode.appendNode('artifactId', dep.name)
dependencyNode.appendNode('version', dep.version)
dependencyNode.appendNode('scope', scope)
if (!dep.transitive) {
// If this dependency is transitive, we should force exclude all its dependencies them from the POM
final exclusionNode = dependencyNode.appendNode('exclusions').appendNode('exclusion')
exclusionNode.appendNode('groupId', '*')
exclusionNode.appendNode('artifactId', '*')
} else if (!dep.properties.excludeRules.empty) {
// Otherwise add specified exclude rules
final exclusionNode = dependencyNode.appendNode('exclusions').appendNode('exclusion')
dep.properties.excludeRules.each { ExcludeRule rule ->
exclusionNode.appendNode('groupId', rule.group ?: '*')
exclusionNode.appendNode('artifactId', rule.module ?: '*')
}
}
}
// List all "compile" dependencies (for old Gradle)
configurations.compile.getDependencies().each { dep -> addDependency(dep, "compile") }
// List all "api" dependencies (for new Gradle) as "compile" dependencies
configurations.api.getDependencies().each { dep -> addDependency(dep, "compile") }
// List all "implementation" dependencies (for new Gradle) as "runtime" dependencies
configurations.implementation.getDependencies().each { dep -> addDependency(dep, "runtime") }
}
}
}
}
@Robyer

This comment has been minimized.

Copy link
Owner

Robyer commented Mar 2, 2017

Just updated script with fix for multiple exclusion rules. Thanks to wkarl on Stack Overflow - http://stackoverflow.com/revisions/42160584/3

@amrfarid140

This comment has been minimized.

Copy link

amrfarid140 commented Nov 15, 2017

Thanks !
Just a quick note for anyone using this script. If you are using 'implementation' instead of 'compile' then modify

configurations.compile.getAllDependencies() to configurations.implementation.getAllDependencies()

@Robyer

This comment has been minimized.

Copy link
Owner

Robyer commented Mar 27, 2018

@amrfarid140 I think that's not correct. "implementation" dependencies shouldn't be exposed (as it is implementation detail of the library). Instead, you should use "api" if that dependency should be exposed from the library to the project. So here you should use configurations.api.getAllDependencies().

I updated this gist to fetch both "compile" and "api" dependencies.

@Robyer

This comment has been minimized.

Copy link
Owner

Robyer commented Mar 27, 2018

By reading dcendents/android-maven-gradle-plugin#61 I better understand how to define the implementation/api dependencies. I updated this gist again.

@cjurjiu

This comment has been minimized.

Copy link

cjurjiu commented Mar 29, 2018

Thanks for the script!

Quick point regarding something I noticed if support for the older compile configuration is dropped (i.e. configurations.compile.getAllDependencies().each { dep -> addDependency(dep, "compile") } is removed:

api dependencies includes dependencies declared as implementation. Because of this, if support for compile is removed, the current version of the script generates two entries for dependencies added using the api configuration: one entry using the compile scope, the other using the runtime scope.

For example:

dependencies {
	api "groupA:artifactA:1.0.0"
	implementation "groupB:artifactB:1.0.0"
}

yields:

<dependencies>
    <dependency>
      <groupId>groupA</groupId>
      <artifactId>artifactA</artifactId>
      <version>1.0.0</version>
      <scope>compile</scope>
    </dependency>
<!--- START : redundant entry ---> 
    <dependency>         
      <groupId>groupA</groupId>
      <artifactId>artifactA</artifactId>
      <version>1.0.0</version>
      <scope>runtime</scope>
    </dependency>
<!--- END   : redundant entry --->        
    <dependency>
      <groupId>groupB</groupId>
      <artifactId>artifactB</artifactId>
      <version>1.0.0</version>
      <scope>runtime</scope>
    </dependency>
  </dependencies>

To fix this, I made the following change: Only add implementation dependencies using the runtime maven scope, if they're not included in the list of dependencies declared as api:

// List all "implementation" dependencies as "runtime" dependencies
configurations.implementation.getAllDependencies().each { dep ->
    if (!configurations.api.getAllDependencies.contains(dep)) {
        //only add a dependency as "runtime" if it's not included in the "api" list of dependencies
        addDependency(dep, "runtime")
    }
}

This would correctly declare api dependencies only once:

<dependencies>
    <dependency>
      <groupId>groupA</groupId>
      <artifactId>artifactA</artifactId>
      <version>1.0.0</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>groupB</groupId>
      <artifactId>artifactB</artifactId>
      <version>1.0.0</version>
      <scope>runtime</scope>
    </dependency>
  </dependencies>         
@cjurjiu

This comment has been minimized.

Copy link

cjurjiu commented Mar 30, 2018

Edited comment above to include a crucial point of information: my remark is valid if support for the older compile version is dropped (i.e. configurations.compile.getAllDependencies().each { dep -> addDependency(dep, "compile") } removed).

Otherwise, the output is correct, since api is counted as compile anyway.

@nateridderman

This comment has been minimized.

Copy link

nateridderman commented May 7, 2018

@cjurjui I saw the same duplicates in my project, but it wasn't related to whether or not the compile version was dropped. Thanks for the fix!

@kaedea

This comment has been minimized.

Copy link

kaedea commented Jun 7, 2018

@Robyer getting version 'unspecificed' with compile a local java module.

@kaedea

This comment has been minimized.

Copy link

kaedea commented Jun 7, 2018

Check my solution: maven-publish

@Tao93

This comment has been minimized.

Copy link

Tao93 commented Jun 13, 2018

@cjurjiu @nateridderman Hi, I found by changing all getAllDependencies to getDependencies , the duplication in pom file disappeared. It seems getAllDependencies returns all dependencies that suits its definition. For example, a api dependency is in configurations.api.getAllDeps() and configurations.implementation.getAllDeps(), while a compile dependency is in all three getAllDeps() list since compile suits all three definition: compile, api and runtime.

@Robyer

This comment has been minimized.

Copy link
Owner

Robyer commented Nov 23, 2018

Updated script - Renamed bundleRelease to bundleReleaseAar as it was changed in new Gradle (see this answer).

EDIT: I'm not seeing notifications for your comments, I only noticed them now. So my current gist doesn't contain fix(es) mentioned in above comments.

EDIT: Nice finding, @Tao93. I updated the script to use getDependencies, so duplication issue should be fixed in current gist version.

@81813780

This comment has been minimized.

Copy link

81813780 commented Jan 2, 2019

Thx, it's save my a lot of time , but I have problem when apply multiple excludes, cause generate pom error format.

error pom content like this :

      <exclusions>
        <exclusion>
          <groupId>*</groupId>
          <artifactId>example1</artifactId>
          <groupId>*</groupId>
          <artifactId>example2</artifactId>
        </exclusion>
      </exclusions>

right pom content like this:

      <exclusions>
        <exclusion>
          <groupId>*</groupId>
          <artifactId>example1</artifactId>
        </exclusion>
        <exclusion>
          <groupId>*</groupId>
          <artifactId>example2</artifactId>
        </exclusion>
      </exclusions>

I fix this by code :

		       // Otherwise add specified exclude rules
                            final exclusionsNode = dependencyNode.appendNode('exclusions')
                            dep.properties.excludeRules.each { ExcludeRule rule ->
                                final exclusionNode = exclusionsNode.appendNode('exclusion')
                                exclusionNode.appendNode('groupId', rule.group ?: '*')
                                exclusionNode.appendNode('artifactId', rule.module ?: '*')
                            }

at last , a little error seems like less than not in comment:

// If this dependency is **not** transitive, we should force exclude all its dependencies them from the POM

thx again~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment