Continuous feedback on how our changes affect the current code allow us to confidently add functionality. Documentation around testing on the Android platform continuous or otherwise is scarce so here we explain how to continuously compile your Android project’s tests in a central area for the benefit of the whole team and it’s clients.

The main components of our continuous integration system are:

Here we wish to share and document our set up and explore some capabilities of the android maven plugin. If you are brand new to it you may wish to first check out Maven in 5 minutes and maven-android-plugin’s useful Getting Started guide.

Android maven plugin helps us with the following android deployment tasks:

  • Building your App
  • Running Behaviour / Unit Tests
  • Running Instrumentations
  • Setting up your test environment
  • Signing your release
  • Optimization of .apk files via zipalign

We want to show you a real example of an application built with the help of the maven-android-plugin. It’s an Avatar Creator app for WeeWorld.

WeeMeeWeeWorld

The app is now on the market, so go ahead and check it out! (0.99$)

If you’re quite familiar with maven and the android plugin, you might want to jump straight to the Real Life Example at the end of this post and check out the full configuration.

Building your App

To buid an apk, your app first needs to cite a version of android platform as a build path dependency in your application’s pom file (as provided scope). More on dependency scope.

<dependency>
  <groupId>com.google.android</groupId>
  <artifactId>android</artifactId>
  <version>2.2.1</version>
  <scope>provided</scope>
  <type>jar</type> <!-- optional -->
</dependency>
<!--Currently valid values: 1.5_r3,1.6_r2,2.0_r1,2.0.1_r1,2.1_r1,2.2.1-->
<!--Those packages are on the maven central repository-->


The project must then reference the maven android plugin within the project’s pom along with the android API level targeted, here we cite version 2.2 (api level 8 )

<plugin>
  <groupId>com.jayway.maven.plugins.android.generation2</groupId>
  <artifactId>maven-android-plugin</artifactId>
  <configuration>
    <sdk>
      <platform>8</platform>
    </sdk>
    <deleteConflictingFiles>true</deleteConflictingFiles>
  </configuration>
  <extensions>true</extensions>
</plugin>


Reference a java compiler version, since the default source and target values are 1.3 and 1.1 respectively, and android uses annotations conforming to java 5

<plugin>
  <artifactId>maven-compiler-plugin</artifactId>
  <configuration>
    <source>1.5</source>
    <target>1.5</target>
  </configuration>
</plugin>


If your project uses Any android platform plugins for instance Google maps, additional dependencies will also require referencing in the project’s pom:

<dependency>
  <groupId>com.google.android.maps</groupId>
  <artifactId>maps</artifactId>
  <version>8_r1</version>
  <type>jar</type>
</dependency>
<!-- Current versions:  3, 4_r2, 7_r1, 8_r1 -->
<!-- NOTE: those are the ones defined by goole and are  NOT in the maven
central repository and need to be installed manually with:
mvn install:install-file wih proper parepeters as decribed here:

http://maven.apache.org/plugins/maven-install-plugin/usage.html

e.g. mvn install:install-file
-Dfile=$ANDROID_HOME/add-ons/addon_google_apis_google_inc_8/libs/maps.jar
-DgroupId=com.google.android.maps -DartifactId=maps -Dversion=8_r1
-Dpackaging=jar -->


Additionally one should remember to specify the source directory if the folder structure does not follow the default maven structure:

<sourceDirectory>${project.basedir}/src</sourceDirectory>


At the same time remember NOT to specify the resource directory, as maven-android-plugin handles Android-specific resources on its own, and we don’t wnt duplicates.

This will already get your project building, but there’s much more that maven can do for You. Let’s look at some of that now.

Testing your App with an Instrumentation

You most hopefully have an accompanying instrumentation test instrumentation project for your Android application and maven can build and run these against your previously compiled project. Maven can build the test project, deploy both the app and the test, and run the instrumentation on an attached device or an emulator.

Within the instrumentation test project it will need the following dependency:

<dependency>
   <groupId>com.google.android</groupId>
  <artifactId>android-test</artifactId>
  <version>2.2.1</version>
</dependency>
<!-- Allowed values same as for android package -->
 


If it depends upon the source code of the application which it tests:

<dependency>
  <!-- optional: compile time dependency, in this case so that we can -->
  <!-- read from the R.java for example. -->
  <groupId>my.app.group</groupId>
  <artifactId>myapp</artifactId>
  <version>${project.version}</version>
  <scope>compile</scope>
  <type>jar</type>
</dependency>


Instrumentations are run through a series of interactions within a pseudo environment so you will need to specify the Device/AVD(Android virtual Device) upon which you wish to run tests:

<groupId>com.jayway.maven.plugins.android.generation2</groupId>
<artifactId>maven-android-plugin</artifactId>
  <configuration>
  <emulator>
    <avd>22</avd>
    <!-- name of the avd to deploy to and run the instrumentation on -->
    <wait>150000</wait> <!-- wait time for the emulator to start -->
    <options>-partition-size 128 -wipe-data</options>
    <!-- additional options to run the emulator with-->
  </emulator>
  <undeployBeforeDeploy>true</undeployBeforeDeploy>
</configuration>


Devices to deploy to can be specified by a serial number but generic “usb” and “emulator” values are also valid. More detailed documentation can be found here.

Instrumentation environment

Instrumentations can interact at various hook in points during the a devices connected lifecycle. Execution and binding it to a maven lifecycle phase is specified like:

<executions>
  <!-- android plugin execution that starts the emulator. -->
  <execution>
    <id>startemulator</id>
    <!-- bound to the 'initialize' phase -->
    <phase>initialize</phase>
    <goals>
      <goal>emulator-start</goal>
    </goals>
  </execution>
</executions>


The configuration above binds the android plugin’s ‘emulator-start’ goal to the ‘initialize’ phase of the maven lifecycle. This is the equivalent of manually executing mvn android:emulator-start, from a directory with a pom containing valid configuration for it. Stopping the emulator does not require this and can be run anywhere and anytime with mvn android:emulator-stop.

If we would like to stop the emulator after running the instrumentation tests, we would add the following execution:

<execution>
  <!-- android plugin execution that starts the emulator. -->
  <id>stopemulator</id>
  <!-- bound to the 'install' phase -->
  <phase>install</phase>
  <goals>
    <goal>emulator-stop</goal>
  </goals>
<execution>



Signing your release

By default, the plugin will sign the apk with the debug key. This can be disabled, producing an unsigned apk.

<configuration>
  <sign>
    <debug>false</debug>
  </sign>
<configuration>


To sign and apk with your key, we will need to use the maven-jarsigner-plugin. Although it’s a different plugin, since it’s very relevant here’s how we did it:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-jarsigner-plugin</artifactId>
  <version>1.2</version>
  <executions>
    <execution>
      <id>signing</id>
      <goals>
        <goal>sign</goal>
      </goals>
      <phase>package</phase>
      <inherited>true</inherited>
      <configuration>
        <includes>
          <include>
${project.build.directory}/target/${project.artifactId}-${project.version}.apk
          </include>
        </includes>
        <keystore>${keystore.location}</keystore>
        <storepass>${keystore.password}</storepass>
        <keypass>${keystore.keypass}</keypass>
        <alias>${keystore.alias}</alias>
        <verbose>true</verbose>
      </configuration>
    </execution>
  </executions>
</plugin>


Configures the jarsigner plugin with the files (input, output), and the keystore details. Binds the plugin’s ‘sign’ goal to the ‘package’ phase of the maven lifecycle.

The ${kestore.*} variables above come from the settings.xml file, and look:

<properties>
  <keystore.location>path/to/test.keystore</keystore.location>
  <keystore.password>teststorepass</keystore.password>
  <keystore.keypass>testpass</keystore.keypass>
  <keystore.alias>testkey</keystore.alias>
</properties>



Optimization .apk files via zipalign.

The last stage of a deployment, but also very important is zipaligning the apk after it’s been signed. This aligns archived data in such a way that upon runtime memory can more efficiently store the related data. After this your apk is ready to go to the market. our configuration:

<plugin>
  <groupId>com.jayway.maven.plugins.android.generation2</groupId>
  <artifactId>maven-android-plugin</artifactId>
  <configuration>
    <zipalign>
      <verbose>true</verbose>
      <skip>false</skip><!-- defaults to true -->
      <inputApk>
    ${project.build.directory}/${project.artifactId}-${project.version}.apk
      </inputApk>
      <outputApk>
    ${project.build.directory}/${project.artifactId}_v${project.version}.apk
      </outputApk>
    </zipalign>
  </configuration>
  <executions>
    <execution>
      <id>zipalign</id>
      <phase>verify</phase>
      <goals>
        <goal>zipalign</goal>
      </goals>
    </execution>
  </executions>
</plugin>


Configures the plugin for the zipalign goal and binds that goal the the ‘verify’ phase of the maven lifecycle.

Real Life Example

The above describes taking full control over how maven-android-plugin builds and tests your android application. In reality though, one wouldn’t really use all of the above settings in one pom. Here’s an example of a fully-configured real-life project using ALL of the above:

weeworld
      |— WeeWorld
      |          |— pom.xml
      |— WeeWorldTest
      |          |— pom.xml
      |— pom.xml



The project makes use of a parent-child structure and maven profiles to manage both App and Instrumentation projects and handle different cases of builds. Feel free to have a look and se how we’ve done it. For more guides and tips about android development and continuous integrations check back to our blog – we’ll have something here soon!

Topics to expect:

  • Project relashionships and inheritance
  • Maven profiles
  • Hudson configuration
  • Automatic instrumentation testing on many different AVD’s using Hudson Android Plugin



References:

maven-android-plugin site, the Getting Started guide and their wiki page.
Installing a specific file into a local maven repository
Signing apk files with maven
Zipalign apk files with maven-android-plugin

Other relevant and important resources:

Maven: The complete reference book and it’s Android Chapter

Share this post:
  • Print
  • email
  • Digg
  • del.icio.us
  • Reddit
  • Twitter
  • Google Bookmarks
  • Facebook
  • HackerNews
  • Technorati
  • PDF

Tags: , , , , ,

16 Responses to “Android continuous integration – Android Maven plugin”

  1. Luigi 22. Sep, 2010 at 1:42 pm #

    Nice article,
    just one thing, I have found that jarsinger is problematic, I have got some problem with lock on files

    with a little bit of search I find out that maven-jar-plugin can do the same and is more solid

    http://maven.apache.org/plugins/maven-jar-plugin/usage.html

  2. Artem 15. Oct, 2010 at 2:05 pm #

    I run “mvn install” in Android Test Project and after “/home/artem/android-sdk-linux_x86/platforms/android-8/tools/dx [--dex, --output=/home/artem/projects/maven/maven-testTest/target/classes.dex, /home/artem/projects/maven/maven-testTest/target/android-classes]” receive trouble processing “javax/xml/parsers/DocumentBuilder.class”. I will be gratefull for any suggestions.

  3. Martin 26. Oct, 2010 at 9:06 pm #

    Great article!
    How do you combine your folder structure with eclipse? Are WeeWorld and WeeWorldTest projects, or are they folders in the single project weeworld?

  4. Sergio 29. Oct, 2010 at 2:03 pm #

    I have always problems with gen (source folder) folders on the different proyects (modules) because thery ares never loaded as source folders, in addition when I include those folders as source and I try to mvn install in eclipse it’s appears an error saying that classfiles are not found. If I make mvn clean and after mvn install at the command line it works perfectly but eclipse doesn’t work anyway, I’ve already tried with another different plugin but the result is the same. I’ve taken your example changing the names of the files and id. what’s the problem due to??

    Help please, I’ve already spent 3 days trying to run an example with different modules conected by a parent pom but it’s impossible.

    Thank’s

  5. Kamil 30. Oct, 2010 at 8:06 pm #

    @Martin. The eclipse integration is still somewhat clunky and was not a priority. The set-up above was mostly meant for continuous ingration. It can be done but is not great just yet. Check out the maven-android-plugin google group for some advice on that: http://groups.google.com/group/maven-android-developers?pli=1

    @Artem. Could You please give more context on the matter? feel free to email me and I’ll see if I can help

    @Sergio. I will have a look at that and try to help You.

    @Lugi. Good advice, thanks!

  6. Sergio 02. Nov, 2010 at 4:03 pm #

    I think it’s impossible to use Eclipse with maven plugins, we can open the Maven structure with eclipse, select the gen folders as source folders and start to work with each project separately, running the project as android projects individually, but we can’t try to execute maven orders like install or clean because if we do this, the Maven project structure modify the android structure under Eclipse IDE and the project become unstable. So, in my opinion the best thing we can do is charging maven structure in Eclipse, and work separately as individual android projects but on the other hand execute Maven orders under command line.

    Is not a beautiful solution but is the only we can do at the moment, I expect to receive a master lesson about how to fix this problem or some different plugin that allows integrate maven into Eclipse in an easier way.

    Thank’s a lot everybody.

  7. Matthias 05. Dec, 2010 at 9:43 am #

    Hey cheers Kamil for sharing this.

    I just want to give a quick heads up to everyone that by depending on the Android JAR from Maven Central you will be up for a bumpy ride.

    The problem is that the artifact you will download is NOT identical to the android.jar bundled with a vanilla Google system image; instead, it rakes together all the 3rd party components like Apache HttpClient and org.json by in turn depending on their respective Maven artifacts.

    That’s an issue, because for instance the JSON JAR it depends on is NOT identical to the one coming with Android; it in fact lacks classes which are there in a stock Android JAR. That means you will end up with compilation failures on your build server and other nice side-effects.

    As to this whole maven-android thing, I can only say: been there, done that. It sucks. I’d really like to devote more time to this issue, but don’t have any at the moment, so I’m really really curious what Carl is up to with SBT. I may look into Gradle at some point, since it seems to go naturally with Java (being based on Groovy that is) and unlike Maven, it’s extensible without requiring you to hold a degree in Mavenology.

    Keep us posted!

  8. Bert van Brakel 11. Jan, 2011 at 8:02 am #

    @Kamil using the eclipse maven plugin along with the maven-android-plugin, and the eclipse android plugin. At this point in time they seem to work together more or less. Import the projects as maven projects, then build, then refresh and eclipse is happy. Still not as seamless as it should be but definitely workable.

  9. Gain 06. May, 2011 at 11:49 am #

    Great explanation for android integration process. I love it.

  10. Manish Rai 11. Aug, 2011 at 8:12 am #

    can you tell about the most effective tool that runs automated testing on android apps, thanks for your article maven it was very informative.

  11. Ricardo 26. Aug, 2011 at 10:13 am #

    No mention of the Android Connector for M2E:

    http://rgladwell.github.com/m2e-android

  12. James Elsey 15. Sep, 2011 at 6:34 pm #

    I agree with the first post by Luigi, I couldn’t get the jarsigner plugin to work, so I used the alternative.

    Wrote up a tutorial here :
    http://www.jameselsey.co.uk/blogs/techblog/automating-android-application-signing-and-zipaligning-with-maven/

  13. Ant Weiss 16. Jan, 2012 at 3:09 pm #

    Hi Kamil,
    thanks for this clear and well-written guide.
    One question I have to ask, though – why use maven, when you can do all the same and more with Ant automation which comes bundled with Android SDK?
    What are the real benefits of using Maven?

  14. Eric So 16. Feb, 2012 at 6:34 pm #

    @Artem

    About the <> exception, I found out the solution. You just need to exclude the package below along with jar. Let me know if it helps for you.

    com.company
    app
    1.0.1

    xerces
    xmlParserAPIs

Trackbacks/Pingbacks

  1. A Successful internship: Intern’s perspective « Graduate Developer Community - 30. Nov, 2010

    [...] We needed a build and continuous integration server for android. There is no current well working solution out there and Kamil was set to play around with Maven/Hudson and a mac mini to come out with some sort of solution. The conclusion of his work is summarized in his blog post: http://novoda.com/2010/08/13/android-continuous-integration-android-maven-plugin/ [...]

  2. Automating android application signing and zipaligning with maven | James Elsey - 15. Sep, 2011

    [...] has already been covered, in a useful post by the guys at Novoda, and various other blog posts scattered around the web. I’ve followed at least 10 tutorials [...]