[TUT] Locally release an Android Library for JCenter or Maven Central inclusion

This post will put you on the right path to releasing and Android library to bintray ( JCenter ) or maven.org ( MavenCentral ). It will show you how you can create a maven compatible release of your Android library project. You can then use these files to release to whatever repository you want (in any way you want).

I’ve written this post as every library, plugin or helper class I have found, to me seems extremely complicated and overkill for a simple task. Hopefully after reading this post you’ll have a better understanding of the basic procedure of some of these plugins.

First things first, if you are here you should have an Android library project and want to release this project to a remote repository. You should realise that this blog post will not help you in uploading to any repository only describe how you can configure and gather your assets ready for release.

For an Android library a release consists of

  • your compiled aar file
  • an md5 and sha1 of your compiled aar file
  • javadoc of your compiled aar file
  • an md5 and sha1 of your javadoc
  • code sources of your compiled aar file
  • an md5 and sha1 of your code sources
  • a metadata file explaining release version numbers and ids
  • an md5 and sha1 of your metadata

These are all packaged under a file structure that relates to your groupId/artifactId/version number. When you are complete you will end up with something that looks like this:

released files

The creation of these files is done with the help of the maven plugin for gradle. This gives us a task called uploadArchives the name is slightly confusing as all it will do is create the above files for us and we will not actually upload them anywhere. Alongside this command we have to do some extra work to tell the gradle build system how to generate sources jar files & javadoc for our android classpath.

Lets start with uploadArchives, this task has so many configuration possibilities if you knew them all your head would explode. I’ve tried to keep this to a minimum so we can just concentrate on a simple release. To override these properties you need to open a closure inside the maven plugin task. Here the minimum we need is the repositories groupId, the libraries artifactId, the version you want to release and the location of where to release to (i.e. file:// for locally).

apply plugin: 'maven'

uploadArchives {
    repositories.mavenDeployer {
        pom.groupId = 'com.blundell'
        pom.artifactId = 'my-library-example'
        pom.version = '1.0.0'
        // Add other pom properties here if you want (developer details / licenses)
        repository(url: "file:///someLocation/")
    }
}

Now running ./gradlew build uploadArchives would build your AAR and deploy it to the directory specified above (i.e. in the correct folder structure and with it’s MD5 & SHA1. It would also deploy sources & javadoc if these where present in the build directory (which they are not yet).

Next step is to tell the Javadoc task and the Jar task that we want to edit the classpath so that the Android classes can be found. Trust me on this one that the below does that. The output files end up in /build/libs.

task androidJavadocs(type: Javadoc) {
    source = android.sourceSets.main.java.srcDirs
    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
}

task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
    classifier = 'javadoc'
    from androidJavadocs.destinationDir
}

task androidSourcesJar(type: Jar) {
    classifier = 'sources'
    from android.sourceSets.main.java.srcDirs
}

artifacts {
    archives androidSourcesJar
    archives androidJavadocsJar
}

If we now ran ./gradlew build uploadArchives it would create all the files we have bullet pointed above with the sha1 and md5 included. Thats it!

Below I have added some syntactic sugar to allow the artifact id etc to be clearly chosen and extra output to the logs to show the destination of resultant files. I’ve also included a zipping of this release as this means you can upload to bintray using one file and it will be exploded at their end.

// ./gradlew clean build generateRelease
apply plugin: 'maven'

def groupId = project.PUBLISH_GROUP_ID
def artifactId = project.PUBLISH_ARTIFACT_ID
def version = project.PUBLISH_VERSION

def localReleaseDest = "${buildDir}/release/${version}"

task androidJavadocs(type: Javadoc) {
    source = android.sourceSets.main.java.srcDirs
    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
}

task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
    classifier = 'javadoc'
    from androidJavadocs.destinationDir
}

task androidSourcesJar(type: Jar) {
    classifier = 'sources'
    from android.sourceSets.main.java.srcDirs
}

uploadArchives {
    repositories.mavenDeployer {
        pom.groupId = groupId
        pom.artifactId = artifactId
        pom.version = version
        // Add other pom properties here if you want (developer details / licenses)
        repository(url: "file://${localReleaseDest}")
    }
}

task zipRelease(type: Zip) {
    from localReleaseDest
    destinationDir buildDir
    archiveName "release-${version}.zip"
}

task generateRelease << {
    println "Release ${version} can be found at ${localReleaseDest}/"
    println "Release ${version} zipped can be found ${buildDir}/release-${version}.zip"
}

generateRelease.dependsOn(uploadArchives)
generateRelease.dependsOn(zipRelease)

artifacts {
    archives androidSourcesJar
    archives androidJavadocsJar
}

Because of the use of gradle “global properties”, you can now add your artifactId, groupId and version to your main build.gradle. Include this release file with an apply from: and you can ship it with the command ./gradlew clean build generateRelease!

Here an example useage, 4 lines of code? Not bad!

apply plugin: 'com.android.library'

// ext is a gradle closure allowing the declaration of global properties
ext {
    PUBLISH_GROUP_ID = 'com.blundell'
    PUBLISH_ARTIFACT_ID = 'my-library-example'
    PUBLISH_VERSION = '1.0.0'
}

android {
    // flavor config etc
}

dependencies {
    // dependencies
}

apply from: 'https://raw.githubusercontent.com/blundell/release-android-library/master/android-release-aar.gradle'

The example above uses a remote repository I created and a remote file. These can be found here http://github.com/blundell/release-android-library. You can either copy the file or use the remote. They both have positives & negatives with stability and flexibility, I’ll leave that to your good judgement.

I would recommend using this if you want to publish an Android AAR to JCenter & BinTray, it makes it so much easier and JCenter is what all the cool kids are using nowadays.

Comments, Questions below.

6 thoughts on “[TUT] Locally release an Android Library for JCenter or Maven Central inclusion

  1. Thank you for this. I’ve been in gradle plugin hell for about 48 hours now. This is the only tutorial I’ve seen that is both accessible and functional. Sometimes you just need to dumb it down in order to get a good solid foothold.

  2. Thanks for the article! Great help. I just needed to use the uploadArchives task to generate a valid POM so I could publish to Artifactory, and this helped me; I can just have uploadArchives pointed to a tmp directory in the build directory (non-VCS), but it will still generate a pom in build/poms/pom-default.xml. I can then point the Artifactory plugin to that generated POM.

  3. Thanks very much.

    This post and the code it contains allowed me to correctly package up my Android Studio/Gradle based open source android library (.aar) so that I could successfully put it on jCenter.

    Your code worked as is for me, with just those few suggested modifications to group id, artifact id, and version.

    Really handy. Thanks for posting this.

Leave a Reply

Your email address will not be published. Required fields are marked *