Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Gradle script for publishing Android library with sources and javadoc to Maven repository using maven-publish plugin.
// You can use maven-publish-helper.gradle script without changes and even share it between multiple
// modules. Just place the maven-publish-helper.gradle file in the root directory of your project,
// then apply it at the bottom of your module's build.gradle file like this:
// ...content of module's build.gradle file...
apply from: '../maven-publish-helper.gradle'
publishing {
publications {
release(MavenPublication) {
// Specify own groupId as package name of your library,
// otherwise it would just use project's name (=name of the root directory) by default.
groupId 'com.example'
// Specify custom artifactId if needed,
// otherwise it would use module's name by default.
//artifactId 'custom-artifact'
// You can specify custom version,
// otherwise it would use version from `android { defaultConfig { ... } }` by default.
//version = '1.0'
}
}
}
/**
* Maven Publish Helper
*
* Requires Android Gradle plugin 3.6.0 or higher (available since Android Studio 3.6).
* See also: https://developer.android.com/studio/build/maven-publish-plugin
*
* @Author Robert Pösel
* @Version 1.5
* @Date 3.3.2020
*/
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.javaCompileProvider.get().classpath
}
}
exclude '**/R.html', '**/R.*.html', '**/index.html'
}
task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
archiveClassifier.set('javadoc')
from androidJavadocs.destinationDir
}
task androidSourcesJar(type: Jar) {
archiveClassifier.set('sources')
from android.sourceSets.main.java.srcDirs
}
// Because the components are created only during the afterEvaluate phase, you must
// configure your publications using the afterEvaluate() lifecycle method.
afterEvaluate {
publishing {
publications {
// Creates a Maven publication called "release".
release(MavenPublication) {
// Applies the component for the release build variant.
from components.release
// Adds javadocs and sources as separate jars.
artifact androidJavadocsJar
artifact androidSourcesJar
// You can customize attributes of the publication here or in module's build.gradle file.
//groupId = 'com.example'
//artifactId = 'custom-artifact'
version = android.defaultConfig.versionName // or just '1.0'
}
}
}
}
@Robyer

This comment has been minimized.

Copy link
Owner Author

@Robyer 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 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 Author

@Robyer 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 Author

@Robyer 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 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 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 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 kaedea commented Jun 7, 2018

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

@kaedea

This comment has been minimized.

Copy link

@kaedea kaedea commented Jun 7, 2018

Check my solution: maven-publish

@Tao93

This comment has been minimized.

Copy link

@Tao93 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 Author

@Robyer 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 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~

@mikemike396

This comment has been minimized.

Copy link

@mikemike396 mikemike396 commented Feb 26, 2019

Love the GIST! One thing I am getting this warning when building. Anything to be concerned with once we upgrade to 5.0?

As part of making the publishing plugins stable, the 'deferred configurable' behavior of the 'publishing {}' block has been deprecated. In Gradle 5.0 the 'enableFeaturePreview('STABLE_PUBLISHING')' flag will be removed and the new behavior will become the default. Please add 'enableFeaturePreview('STABLE_PUBLISHING')' to your settings file and do a test run by publishing to a local repository. If all artifacts are published as expected, there is nothing else to do. If the published artifacts change unexpectedly, please see the migration guide for more details: https://docs.gradle.org/4.10.1/userguide/publishing_maven.html#publishing_maven:deferred_configuration.

@yanchenko

This comment has been minimized.

Copy link

@yanchenko yanchenko commented Apr 1, 2019

Had to wrap the entire publishing {} block into project.afterEvaluate {}, otherwise bundleReleaseAar wasn't found.
Gradle 5.2.1

@tprochazka

This comment has been minimized.

Copy link

@tprochazka tprochazka commented May 15, 2019

It is really necessary to do pom.withXml manually? There is no default implementation which handles it? It looks that there are is nothing directly specific for Android? Your implementation, for example, miss tag and completely doesn't work if you are using BOM https://docs.gradle.org/5.0/userguide/managing_transitive_dependencies.html#sec:bom_import

@tprochazka

This comment has been minimized.

Copy link

@tprochazka tprochazka commented May 15, 2019

I just found this and it looks that it works much better https://github.com/wupdigital/android-maven-publish

@gsavvid

This comment has been minimized.

Copy link

@gsavvid gsavvid commented Jun 28, 2019

WARNING: API 'variant.getJavaCompile()' is obsolete and has been replaced with 'variant.getJavaCompileProvider()'.
It will be removed at the end of 2019.
For more information, see https://d.android.com/r/tools/task-configuration-avoidance.
To determine what is calling variant.getJavaCompile(), use -Pandroid.debug.obsoleteApi=true on the command line to display a stack trace.

However, variant.getJavaCompileProvider() doesn't seem to have a property classpath.

@Robyer

This comment has been minimized.

Copy link
Owner Author

@Robyer Robyer commented Jun 28, 2019

I just updated the script with changes:

  1. Wrapping into publishing{} block as yanchenko suggested.
  2. Fixed use of the obsolete variant.getJavaCompile()
  3. Fixed issue with printing exclusion rules as someone mentioned on StackOverflow

@gsavvid: You can use the updated version.

@gsavvid

This comment has been minimized.

Copy link

@gsavvid gsavvid commented Jul 7, 2019

@Robyer thanks that's fixed now. Are you planning to configure the script to export Kotlin Javadoc? Eg. using Dokka?

@Robyer

This comment has been minimized.

Copy link
Owner Author

@Robyer Robyer commented Jul 8, 2019

@gsavvid: No, I'm not even using Kotlin myself.

@gsavvid

This comment has been minimized.

Copy link

@gsavvid gsavvid commented Jul 9, 2019

Fair enough. I forked it and updated it in order to use Dokka for generating Kotlin Javadoc (aka KDoc) and also to use com.jfrog.bintray plugin for uploading to Bintray. I'll try to keep it up-to-date with whatever changes are made to the original one, here.

If anyone wants to check out my version, it's here: https://gist.github.com/gsavvid/f7ffe00d846a50de7490c2ecbd7b4169.

Thanks a lot by the way. This has been very helpful.

@matpag

This comment has been minimized.

Copy link

@matpag matpag commented Aug 22, 2019

With latest AGP 3.5.0 and Gradle 5.4.1 I have a warning at line #13 indicating: Access to 'classpath' exceeds its access rights

@btdrucke

This comment has been minimized.

Copy link

@btdrucke btdrucke commented Oct 26, 2019

I am using gradle 5.6.2 and for this version, classifier = 'sources' should be archiveClassifier.set('sources').

@ellykits

This comment has been minimized.

Copy link

@ellykits ellykits commented Dec 3, 2019

Thanks for this Script I was able to tweak it a bit and use it for publishing Android Library to GitHub Package Registry. (The dependencies were missing initially)

@Robyer

This comment has been minimized.

Copy link
Owner Author

@Robyer Robyer commented Feb 25, 2020

New Android Studio 3.6 with Android Gradle Plugin 3.6.0 has now support for Maven Publish Plugin. This script is probably not needed anymore.
https://developer.android.com/studio/build/maven-publish-plugin

@tprochazka

This comment has been minimized.

Copy link

@tprochazka tprochazka commented Feb 27, 2020

I already tried to use build-in support instead of https://github.com/wupdigital/android-maven-publish and it was not working for me, but maybe I did something wrong. Has anybody success with it already?

@iqorqua

This comment has been minimized.

Copy link

@iqorqua iqorqua commented Mar 3, 2020

Hello! I made android library and i need to asseble it into .aar with all sources and docs. I tryed a lot of ways, but new project cant see the sources. When i opened my lib as archive i can see .kt files inside classes.jar. Also sources are present inside of libs folder as .jar file. When i open .aar package inside Android Studo, i can see my classes and its source, but navigation with Ctrl+click references to compiled .class file instead of source .kt file.
After gradle updating to 3.6.0 result is the same.
Can someone help me? :)

@Robyer

This comment has been minimized.

Copy link
Owner Author

@Robyer Robyer commented Mar 3, 2020

I updated the script for use in Android Studio 3.6. We don't need to handle the XML ourselves anymore as new Android Gradle plugin 3.6.0 will handle that itself. We still need to handle javadocs and sources manually, though.

I added also example usage how to easily (re-)use the script in multiple modules without copying and changing the script file.

@iqorqua I don't know how it works with Kotlin source files, but with Java source files in AAR created with this script the sources are recognized and used correctly.

@mochadwi

This comment has been minimized.

Copy link

@mochadwi mochadwi commented Apr 10, 2020

really appreciate and thanks @Robyer, as previouly stated from you:

New Android Studio 3.6 with Android Gradle Plugin 3.6.0 has now support for Maven Publish Plugin. This script is probably not needed anymore.
https://developer.android.com/studio/build/maven-publish-plugin

You also updated it the script, I'm a little curious, do you have a full open source/project in the github/somewhere?

This block of lines:

artifact bundleDistributable {
    classifier ""
}

Encountered below issue in my project:

A problem occurred evaluating project ':app'.
> Could not find method bundleDistributable() for arguments [build_a1v67a779r9u4vrutskt4b88d$_run_closure3$_closure9$_closure11$_closure12@3c5f1e] on object of type org.gradle.api.publish.maven.internal.publication.DefaultMavenPublication.

Any ideas what suggestion for me, to solve the issue? Please let me know if you need more information

EDITED:

I've made a mistake asking the question, here, in fact I'm using the old scripts provided from https://alessiobianchi.eu/blog/obfuscated-aar-local-maven/ instead of the gist provided here.

@Robyer

This comment has been minimized.

Copy link
Owner Author

@Robyer Robyer commented Apr 11, 2020

@mochadwi I'm not sure you still need the answer, but I am using my script (at the moment it's old version) in this project: https://github.com/adaptech-cz/Tesseract4Android

@zhitaocai

This comment has been minimized.

Copy link

@zhitaocai zhitaocai commented Apr 23, 2020

Great! Thanks~

@spyhunter99

This comment has been minimized.

Copy link

@spyhunter99 spyhunter99 commented Apr 25, 2020

this doesn't seem to do the gpg signing, hashes, sources, or javadoc jars that are required for publishing to sonatype. Or am i missing something?

@Robyer

This comment has been minimized.

Copy link
Owner Author

@Robyer Robyer commented Apr 25, 2020

@spyhunter99 It creates sources and javadoc jars, but it doesn't do gpg signing or hashes. You can probably add that easily if you know how to work with Gradle, but I have no experience with Sonatype (in repository above I am using Bintray), so I can't help you with that.

@cyb3rko

This comment has been minimized.

Copy link

@cyb3rko cyb3rko commented Jul 18, 2020

First of all thanks for this gist.
I have now implemented your templates and adjusted them to my project, but how do I then set description etc. and upload my project to Bintray?

Thanks!

@Robyer

This comment has been minimized.

Copy link
Owner Author

@Robyer Robyer commented Jul 19, 2020

@cyb3rko Hi, you can look at this config file, I am using older version of my gist there, but the Bintray part at the bottom is what is important for you: https://github.com/adaptech-cz/Tesseract4Android/blob/d03bd5fc063d3f34cefd1d48481da38421970136/publish.gradle#L99-L136

EDIT: Oh, and also these lines too: https://github.com/adaptech-cz/Tesseract4Android/blob/d03bd5fc063d3f34cefd1d48481da38421970136/publish.gradle#L53-L58

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.