Month: January 2016

Publish Android library to Maven using Android Studio 1.5

If you are working with Android Studio and more in general with the Android platform, soon or later you will need to download a library from a Maven or JCenter repository.
If you are clueless of what I am talking about, just open an Android project using Android Studio and look at the file called build.gradle (The one called build.gradle Project and not the one specific of a module).

Gradle dependencies overview

You should see a layout similar to mine:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.5.0'
    }
}

In this file we simply asked Gradle to download the project dependencies from JCenter. This means that Android Studio, when you build the project, will query JCenter central repository and try to resolve any dependency and download them.

Now, if you move through the structure of your Android project you will find another build.grandle file.

Actually you will find one per module. You can think of a module like a component of your android application.

In this case in my module I have a reference to an external library and I declare the dependency in this way (at the bottom of my gradle file):

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.squareup.okhttp:okhttp:2.0.+'
}

So, in this example I am working with a library called okhttp, available from the package com.squareup.okhttp and more precisely I am asking for the version 2.0. The + sign at the end means that any sub-release of the major 2.0 is fine for me, so 2.0.1 or 2.0.999 they are both ok.
Now, inside my code I can declare this package and start to use its internal classes and interfaces because I know that gradle with synchronize the references into Android Studio during compile time.

Another scenario may happen if you need to work with a public library but the library is not available on Maven Central but on a custom repo. In my case, I have created an upgraded version of a famous library for Android Wear and I do not want to publish it on Maven Central but I rather keep it on my own repo. In this case, in order to use the dependency, from the module build.gradle file you must declare first where is located the Maven repository and then you can add the dependency like I did here:

repositories{
    maven{
        url "http://dl.bintray.com/raffaeu/maven"
    }
}
dependencies {
    compile 'com.mariux.teleport.lib:teleportlib:0.1.6'
}

If this part is not clear, I personally found very helpful the documentation area of gradle, which is available here.

Please pay attention that Android Studio 1.5 works with gradle 1.5 while the latest gradle is now 2.1 so some features may refer to gradle 2.1 which is not compatible with Android Studio.

Create an Maven account

Assuming that everything is clear so far now it’s time to deep dive into Maven and create your own account and repository. Without this part setup you cannot create your own library and publish it.

Head to BinTray.com and create a new Account. You can create the new account using Username and Password or you can link one of your existing social accounts: Google+, GitHub and Twitter.

SNAGHTML14e5a4ba

When your account is up and running, you should have an account home page available at this URL: https://bintray.com/[your_username].
In this page you can setup your user profile, change your profile picture and add social accounts.

Note: if you host like me, your open source projects on GitHub, I kindly suggest you to link your GitHub account because it will be a lot easier to display release notes and documentation directly from GitHub.

Now, look at the right pane of your user account and click on the Maven link. From there you will be redirected into your Maven’s package manager.

Click Add New Package to start to create your public maven library:

image

In this page, you have to setup your Maven package information. It is very important how you name your package because this will be the naming convention that we will carry forward on this tutorial, plus it will be used by your users.

From the owned repositories choose Maven and a “new Maven package” page will open:

image

Information regarding your package

In the create new package window, BinTray asks you for some basic information required for your package:

image

In my case I am using GitHub so I can easily port my source code repository, my read me files, the issues tracker and the wiki into BinTray.

Now, our package name in BinTray is called LicenseChecker but we still do not have any code or library in it, so it’s now time to move into Android Studio 1.5 and create our Package.

Android Studio and Maven

At this point it’s time to make our Android Library. In my specific case I have a library composed by 3 modules, one module refers to a demo app for Smartphone, one module refers to a demo app for Wearable device and one module is my Android Library:

image

01 – Preparation

Now, in order to be able to publish the library into BinTray we need to configure Android Studio.

  • Open the build.gradle file related to the project (the first one in my previous picture)
    • Add a reference to the following plugins:
      classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2'
      classpath "com.github.dcendents:android-maven-gradle-plugin:1.3"
    • Re-compile and verify that gradle found your plugins

Now your project build.gradle file should look like this one:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.5.0'
        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2'
        classpath "com.github.dcendents:android-maven-gradle-plugin:1.3"
    }
}

Second step, we need to apply the plug-ins to the libraries that will get published into BinTray. In my case the library project is licensecheckerlib, so I am going to edit the build.gradle of this specific module and apply the plug-ins and rebuilt:

apply plugin: 'com.android.library'
apply plugin: 'com.jfrog.bintray'
apply plugin: 'com.github.dcendents.android-maven'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

Now, in order to upload your library, Maven needs information related to the POM file. If you don’t know what is a POM file, I suggest you to have a look here.

Because we are using the Maven’s plugin for Android Studio, just add these two lines after your plugin declaration (always inside the library build.gradle file):

apply plugin: 'com.android.library'
apply plugin: 'com.jfrog.bintray'
apply plugin: 'com.github.dcendents.android-maven'

group = 'com.raffaeu.licensecheckerlib' // Change this to match your package name
version = '1.0.0' // Change this to match your version number

Here we are saying to BinTray “hey, look that I am going to upload a package called com.raffaeu.licensecheckerlib and its version is 1.0.0”.

Next step, which is optional but mandatory if you are considering to make your library visible over JCenter, Maven Central and more, you need to create a source .jar file. Yes, you need to because the plugin for Maven is capable to build only .aar packages which are not compatibles to JCenter. Always inside your library build.gradle file, create this task:

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

Second step to conform with JCenter and Maven Central is to generate also a Java Doc. The JavaDoc is very helpful for your users especially because you are releasing a custom library with custom APIs, so probably the method void doSomething() is unknown to people outside your organization, and this is why JCenter suggests to publish also a Java Doc together with your library.

The JavaDoc should also be transformed into a jar, to do so we create an additional task called generateJavadocsJar and we declare a dependency so that the task will not start until the generateJavadocs task is completed.

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

task generateJavadocsJar(type: Jar) {
    from generateJavadocs.destinationDir
    classifier 'javadoc'
}

generateJavadocsJar.dependsOn generateJavadocs

Last step for our preparation is to include the artifact keyword of gradle. The artifact keyword is used to inform gradle that a specific library is composed by additional steps, in our case the steps required to generate the .jar and the documentation:

artifacts {
    archives generateJavadocsJar
    archives generateSourcesJar
}

At this point we need to build everything and be sure that the tasks are running correctly and that our library is also including documentation and .jar.

Go to Gradle project panel > “refresh” > your library > other > install and double click the task to start it. It will rebuild your library and include also the artifacts required by JCenter:

image

You can double check that everything is done by browsing your library project’s folder and double check that the following items exist:

Your project folder:

  • Build > outputs > aar
    • library-debug.aar
    • library-release.aar
  • Build > libs
    • library-1.0.0-javadoc.jar
    • library-1.0.0-sources.jar

02 – Publish the library

All right, now we know that our library is building correctly and can be published. This is very important because you can use the install task to just rebuild everything and ensure that you are ready to go live. Technically speaking, every time you make a change you should rebuild using install and run your tests. If you get a green light than you are ready to publish into Maven.

In order to publish the artifact into Maven we need to inform the Maven Plug-in ‘com.github.dcendents.android-maven’ about who we are and what project we are going to upload.
The entire documentation for the plugin settings is available here. 

bintray {
    user = '[your BinTray username]'
    key = '[Your bintray key]'
    pkg {
        repo = 'maven'
        name = 'LicenseChecker' // the name of the package in BinTray

        version {
            name = 'licensecheckerlib' // the name of your library project
            desc = 'This is the first version'
            released  = new Date()
            vcsTag = '1.0.0' // the version
        }

        licenses = ['Apache-2.0']
        vcsUrl = 'https://github.com/raffaeu/LicenseChecker.git' // your GitHub repo
        websiteUrl = 'https://github.com/raffaeu/LicenseChecker' // your website or whatever has documentation 
    }
    configurations = ['archives']
}

Search for the Task bintrayUpload and run it:

SNAGHTML231544d5

At this point you can head to BinTray and release your package to the public.

image

Note: Remember that every time you make a new release, BinTray will not publish the package until you confirm that. This is a sort of safe guard put in place by BinTray to avoid unwanted publishing.

Last check, before asking BinTray to release your package over Maven and JCenter, you can double check that everything has been published correctly, and in my case here you go:

image