Saturday, 01 June 2013

Using local .aar Android library packages in gradle builds

Since Gradle became the new build system for Android there were a lot of questions popping up all over the net about how to use it. The new build system comes with a number of great features like multi project builds, android archive packages (.aar) for android libraries and so on. Unfortunately, since the new build system is quite fresh (version 0.4.2 at the moment), the documentation is rather limited, so not everything is clear and simple.

For example, if you have a solution with an android library and an android app (that depends on the library), your build will work just fine. But what if you want to decouple the library, keep it separate so that you can use it in other projects or share it with the community? The Gradle build system will package it as an android archive package (.aar) and you can add that as a dependency to your projects. The only problem is that referencing .aar packages locally doesn't work very well, and it seems like that's by design. As explained by +Xavier Ducrichet in this comment:

using aar files locally can be dangerous. I want to look at either detecting issues or putting huge warnings.

This means that to add a reference to an .aar package it it would have to ideally be stored in the central maven repository (now that maven central finally supports android archive packages!). But what if that's not an option, for example if the library you're referencing is in development?

A simple and extremely straightforward option is to create a local maven repository on your dev machine, and install your library in there. Then reference it from your gradle build. And doing it is surprisingly simple!

  1. Since you're developing for android, I assume you already installed the latest JDK and set the JAVA_HOME environment variable, but if you didn't - now is the time.
  2. Then you'd want to install Maven. You can download it here: http://maven.apache.org/download.cgi
    Set the MAVEN_HOME environment variable to the path where you extracted maven, and add the maven's bin folder to the PATH environment variable.
  3. To test that maven is working fine, open a new console window and run the following:
mvn -version
  1. If everything is fine, it's time to add your library to the maven repository. In the command prompt run the following:
mvn install:install-file -Dfile=d:\mylibrary-{version}.aar -DgroupId=com.example -DartifactId=mylibrary -Dversion={version} -Dpackaging=aar

Don't forget to replace the proper path to your library, setting your groupId, artifactId and version number.

  1. Finally, edit your build.gradle to start looking at the local maven repository. For example, if you want to use both maven central and your local repo you can add both of them to the repositories configuration.
    Here's an example of a very basic build.gradle for an android app using the library we registered above:
buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.4.2'
    }
}

apply plugin: 'android'

repositories {
    mavenCentral()
    mavenLocal()
}

dependencies {
    compile('com.example:mylibrary:0.2')
}

android {
    compileSdkVersion 17
    buildToolsVersion '17.0.0'
}
  1. Finally, run the build command to build your app:
gradle clean build

Of course pushing the file to the maven repo from the command line every time is going to become very old very soon! So instead you can use the "maven-publish" gradle plugin to do the same. We can store the version and the groupId in the build.gradle file, and the artifactId will be taken from the project name (i.e. the folder name where your project is stored).

Unfortunately the plugin works well with the gradle java plugin, but it's not quite there with the android plugin, so we'll have to configure it a bit. The main problem is to get the resulting .aar file in the maven publication profile. To do that we'll run a call to android.libraryVariants, which will initialise this object, and create all the subtasks required for the build, including "bundleRelease" which is creating the .aar file.

Here is what my build.gradle file looks like:

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

apply plugin: 'android-library'
apply plugin: 'maven-publish'

version '0.2'
group 'com.example'

android {
    compileSdkVersion 17
    buildToolsVersion '17.0.0'

    defaultConfig {
        versionCode 2
        versionName '0.2'
    }
}

android.libraryVariants
publishing {
    publications {
        maven(MavenPublication) {
            artifact bundleRelease
        }
    }
}

If you want to change the artifactId to something custom, you can change the project name in settings.gradle by adding this line:

rootProject.name = 'mylibrary'

That's it. Now open a command prompt in your project's folder and run the following to build and publish your library to the local maven repository:

gradle clean build publishToMavenLocal

Acouple basic articles that I used to get this to work: