Mavenizing Android: Adventures with Eclipse and Jenkins

[Basteifelsen - Bild] I have written on Maven and Android about over a year ago. Since then a lot of things have happened: the Maven plugin for Android has advanced considerably, there are new Android versions, improved Android tools, an Android m2e connector and many other things.

When I went back to one of my apps to start programming on it again, I noted that my Android Maven build setup was not working anymore in Eclipse after a year of lying dormant. I also found that after a bit of re-factoring I had introduced a few bugs into my code. Not a big surprise since all my Android testing had been manual testing on a device or the emulator because the test setup that comes with Android was too complex for my experience in writing tests.

For my other coding projects I have set up Jenkins and Sonar to help me analyse the quality of my code and execute my tests all the time. I learned to enjoy the advantages of good test coverage and regularly executed builds. It was time to re-think my style of Android programming and testing.

My goals

  • improve quality of my code to make development cheaper in the long term
  • therefore I needed to improve test coverage of my Android code
  • and run the tests regularly on a build server

My tools

  • automatic builds: I chose Maven as build tool
  • tests: I decided to go with Robolectric
  • build server: install the Jenkins Android plugin

Following is the list of issues I stumbled about

Fixing the maven build

So after finding the broken Maven build, I decided to try again. I noticed that Maven now had a quick start for Android and so got me a nice sample pom.xml. That was a huge step forward. Note: Take care to check if you are using the latest version of the Android plugin! I was using an old alpha version at first.

[code language=”xml”]
<plugin>
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
<artifactId>android-maven-plugin</artifactId>
<version>3.4.0</version>
<configuration>
<androidManifestFile>${project.basedir}/AndroidManifest.xml</androidManifestFile>
<assetsDirectory>${project.basedir}/assets</assetsDirectory>
<resourceDirectory>${project.basedir}/res</resourceDirectory>
<nativeLibrariesDirectory>${project.basedir}/src/main/native</nativeLibrariesDirectory>
<genDirectory>${project.basedir}/target/gen</genDirectory>
<sdk>
<path>/opt/android/</path>
<platform>16</platform>
</sdk>
</configuration>
</plugin>
[/code]

Fixing Eclipse

There is also an issue with Eclipse and the (currently) latest Android Tools 20, which can easily be fixed be installing a few missing dependencies. I found this via stackoverflow.

When m2eclipse keeps telling you it doesn’t know about the lifecycle of the Android goals just go for the quick fix and hit “Discover Connectors” it will lead you to the Android M2Eclipse connector which you can install and after that m2eclipse is happy.

Building in Eclipse

There are a few things I didn’t manage to configure the way I wanted to. Most notable: the Android Eclipse plugin keeps setting the output directory to bin/classes no matter what I tried. I stopped mission impossible and instead tried to get Maven to write to bin/classes instead of target/classes. At that point the Android Eclipse plugin started complaining that R.java was modified manually every time the maven builder re-created the file. So I went back to the way everything was originally and muttered some … Right now when I search for R.class I find three files, one each in: bin/classes, target/classes and target/android-classes. This is not pretty, but I decided it wasn’t worth my time to fix the ugly and instead get on with the test stuff.

However before getting there I had another problem: when executing tests in Eclipse I kept getting “ClassNotFound” issues – but this was not really the problem I was looking for. I just thought it was because this behaviour was fixed after execxuing a “mvn clean install” on the project I thought it was an issue with either the Eclipse or Android auto building: both were enabled (one is in the project menu, the other in the preferences in Eclipse). I finally noticed all the classes were indeed in bin/classes. So I checked the classpath: it was in order. I finally found that all I needed to do was “Maven -> Update Project Configuration“. I really wonder why this has to be triggered manually … this causes such a load of different and weird behaviours all the time.

So at this point my Eclipse is building and I can run my tests – except … there’s more.

Update After some more trouble with Eclipse not auto-building I turned off the Maven Builder in Project > Properties > Builders. Eclipse protested about possible side effects. But now my classes seem to be compiled into bin correctly and the test runner finds them.

Robolectric and ANDROID_HOME

The Robolectric page has some good documentation and a nice introduction to writing tests with the framework. I combine this with Mockito and Junit.

Do check for the latest versions of all the frameworks: it doesn’t do to start with an old one. For example older versions of Robolectric do not allow logging to be redirected to system.out. Older versions also don’t have so many issues with ANDROID_HOME …

With Robolectric there is just one issue and that is again with Eclipse: the sheep are looking for a home first thing after being woken up. Meaning: ANDROID_HOME must be set and available in your environment. I have not found out how to do that globally in Eclipse. In fact after searching all over the place I found this neatly hidden on the Robolectric homepage:
If you get a RuntimeException saying: “no such layout layout/main”. If you get the error message “java.lang.RuntimeException: error inflating layout” this just means that the android.jar dependency was not found.

Here’s how you do the logging thing:

[code language=”java”]
static {
System.setProperty("robolectric.logging", "stdout");
}
[/code]

Jenkins vs Android

There is a nice Android plugin for jenkins. I ended up installing Android manually with a lot of fun with the command line:

[code language=”bash”]
/opt/android/tools/android update sdk -u -t android-16
[/code]

Update: with my initial pom.xml I never actually made the tests run on jenkins, I just thought I did. I was having the following issue with the google dependencies: in Eclipse the tests would only run when the google dependencies were in scope “compile” but the maven build would fail when the dependencies were anything but “provided”.
[code language=”xml”]
<dependency>
<groupId>com.google.android</groupId>
<artifactId>android</artifactId>
<version>${platform.version}</version>
<scope>provided</scope>
</dependency>
[/code]
I ended up following the advice from this stackoverflow question: I added the android.jar into the project libs/ directory, where the Eclipse Android plugin finds it and let’s the tests run and kept the maven compile clean for building on Jenkins.

Additional hints: Take care to also mark your test dependencies (junit, mockito and especially robolectric) as scope test in your pom.xml otherwise you may get an error “Ignoring InnerClasses attribute” that kills both your Maven and your Eclipse builds. I found the solution here.

So that’s it

So to finish this, here’s a list of the main issues I had:

  • Classes not found after “Clean Project” in Eclipse. Cause: Seems to be caused by conflict between bin/classes and target/classes. Solution: turn off the Maven Builder
  • “java.lang.RuntimeException: error inflating layout” when running robolectric tests. Cause: android.jar is not on classpath. Solution: add android.jar as provided dependency in pom.xml and as library in libs/ dir of project
  • Robolectric tests fail with a variety of fun reasons. Cause: ANDROID_HOME is not found. Solution: add sdk path to maven android plugin and set the variable on your Eclipse test configuration manually.
  • The jenkins plugin for android, did not download android automatically. Cause: no idea. Solution: do it manually (see above)
  • Final words: check your android versions – there is one to set in the AndroidManifest.xml, there is one to set in the pom.xml and I believe there is one you set somewhere in the Eclipse settings of the project. Check if the version you use is installed both on your development machine and your build server.
This entry was posted in android, development, processes. Bookmark the permalink.

One Response to Mavenizing Android: Adventures with Eclipse and Jenkins

  1. Roberto S. says:

    You saved my life 😀