Using Gradle for building Android applications

There are two plugins available for Gradle, for building Android applications:

  • https://github.com/jvoegele/gradle-android-plugin and
  • http://tools.android.com/tech-docs/new-build-system/using-the-new-build-system

This blog-post will share some experiences of using the plugin provided by the Android Open Source Project (AOSP)

Initial build file

Lets start by creating our first initial build file, called build.gradle in the root of our project directory:

This will configure the build-script to use the maven-central repository, and apply the android-plugin to the project. It will use the default locations of where the manifest, source, resources and assets are located. These are by default located in /src/<sourceset>/ where source-set if nothing else is configured is set to main.

If we want to configure the source-set layout, we can add another section to the build.gradle file

which will match the default project layout in an Eclipse project. Please note that we added the target as well above, which is required for gradle to understand which sdk version to use.

Running for the first time

From here, we should be able to run a simple ‘gradle assemble’, which is the equivalent of a ‘mvn install’.

Ok, so now what ? Lets try running with this basic build file:

As can be seen in the output above, the target assemble, has two other targets which depend upon it, namely assembleDebug and assembleRelease. Debug and Release are actually two of the default build-types. Additional build types and modifications to the existing ones can be added under the android-element. For example, if we want to generate some extra java-code into BuildConfig.java:

This will include this boolean variable in the automatically generated BuildConfig.java for use in your application to differ in behaviour. There are other parameters that can be controlled for each build-type than the buildConfig variable.

After the build has successfully completed, you will end up with the binaries under ‘/build/apk’.

Adding depencencies

Adding depencencies in gradle is quite simple. Start by adding the repositories that you want to fetch your dependencies from, for example:

The next step is of course to list the dependencies, here is an example towards the android support library:

The ‘compile’ directive equals the one in Maven, where the dependency will be included inside your apk. It is also quite simple to add a dependency towards a jar-file local for your project if the jar-file you have a depencency isnt published in a repository. Then do:

More on build configuration

Remember the trick we could do with buildConfig above ? When combining that with Eclipse, it gives us a bit of headache, as eclipse doesnt have the same configurations as
we might have in our project. The source-path for this autogenerated file is completely different between gradle and eclipse. Lets see if we can solve that…

The first idea one might have, is to modify the eclipse project to use the BuildConfig.java that is generated from gradle, instead of the one that the Eclipse Plugin generates itself. That solution would work, but as mentioned, requires modifications to Eclipse, and could give you other problems further on.
Lets try a different approach. In Gradle it is supposed to be easy to add addtiional actions to the different build targets, and it is, but together with the Android-plugin we are using it becomes a bit more complex. This is because the build targets that are used are created dynamically based on the buildTypes-element (debug and release by default), i.e the targets assembleDebug and assembleRelease are created on the go when the build script is being executed. One way that I have used to fix this is to listen on when tasks are added. This can be done with:

This code will ensure that whenever a task is added called generateDebugBuildConfig, we will make that task dependant on our own task someDebugCustomBuildConfig (in this case a task of type Copy). This does what we wanted, hooking in a chance to do something of our own when generating the build-config.

In maven, one common way of doing build-variant configuration is to use the filter-plugin, and we will here attempt to do the same thing except in gradle. What this means, is that instead of having the boolean variable above, we will move it into an android resource file under res/values/. This requires us to do some search-and-replace in the android xml files. Lets try:

This code will take all xml files under res/ and replace ${has_prototype_feature} with ‘true’. All files that aren’t xml files will simply be copied into build/target/filtered-resources. It looks a bit odd above with the extra beginToken/endTokens, but that is as we are currently supporting both gradle and maven in this example project. Also, for this to work, we need to modify the source-set above and change:

Running it again should now replace any values in res/values/*.xml with whatever values you define here. Making several of these you can get different behaviour between different build-types of your application.

Final words

The Android Gradle plugin does what it currently can good, and with a simpler syntax than the equivalent Maven build file does.
There are some features that currently forces the user of the plugin into odd behaviours. As we saw above, its currently very hard to interact with the IDE of your choice. Some examples were presented here to work around these issues – and Im sure there are others.

Also related to IDE’s there is the actual problem of finding all your dependencies. The dependency jar-files will be downloaded to your gradle repository and your Eclipse classpath has no idea where they are. We have solved this locally by having a python script which parses build.gradle, your gradle repository and generates the .classpath file for you – not ideal, but it works.

Another area which eventually forced this example project into using both gradle and maven, was because proguard was needed on the project. The gradle plugin that currently exists does not support proguard, and thus we revert to using maven.

Complete example: sample_gradle_android_build_file

This Post Has 14 Comments

  1. Nice post, thanks!
    Moreover, today the v0.3 of the official plugin appeared on Maven Central. Let’s wait for the official announcement :)

  2. Thanks ! I had a look at the 0.3 plugin this morning, and had to make some minor adaptions to our buildscript, but was quite simple.
    Sadly, there is still no support for proguard – which is the main reason we are using maven in parallell, but I guess its coming.

  3. Any tips on generating multiple apks?

    Also, what’s the issue with pro-guard? Will we need to use maven?

  4. I have no experience about generating mutiple apk’s yet, but as far as I have read, the support in the plugin is pretty good.

    About proguard, the support right now just isnt there. Most projects however don’t need to use proguard, but if you do, then your only choice is to either use something else, or add the support for proguard yourself.
    As for http://mobilebytes.wordpress.com/2009/09/03/gradle-task-for-proguard/ I don’t think that will work – not sure if its aimed towards this plugin. An alternative could also be to use https://github.com/jvoegele/gradle-android-plugin/wiki instead, but I have no experience with that one either.

  5. Can’t seem to exclude lombok from being added to the apk, i tried to do it by creating a provided configuration like this:

    configurations {
    provided
    }

    sourceSets {
    main { compileClasspath += configurations.provided }
    }

    and then adding the dependency like this:

    dependencies {
    provided ‘org.projectlombok:lombok:0.11.8’
    }

    But i’m still getting this error:

    Error: duplicate files during packaging of APK .apk
    Path in archive: LICENSE
    Origin 1: //.gradle/caches/artifacts-24/filestore/org.projectlombok/lombok/0.11.8/jar/e43ce2be16d8990568a4182c0bf996ad3ff0ba42/lombok-0.11.8.jar
    Origin 2: //.gradle/caches/artifacts-24/filestore/org.sonatype.sisu.inject/cglib/2.2.1-v20090111/jar/7ce5e983fd0e6c78346f4c9cbfa39d83049dda2/cglib-2.2.1-v20090111.jar
    :packageRelease FAILED

    Which suggests that its including the lombok jar file into the apk, which shouldn’t be happening, any suggestions?

  6. There’s an Eclipse plugin for gradle.

    Then you can issue gradle eclipseClasspath

    And your .classpath file will be generated from the dependencies.

    1. I have tried this, but I couldn’t get it to work. Are you sure the eclipse plugin for gradle will be able to sort out android dependencies ? When I run it, I end up with a close to empty .classpath file.

  7. Nice post. Thank you!

    I’m trying to build with different phases, i.e., different package name for debug build, and this post does great help for me.

  8. Small issue, “task ->” should be “task ->”, evil evil HTML messing with you :)

Leave a Reply

Close Menu