Deploying the android libraries into your maven repository

Maven is a fantastic build tool, and a great addition to anyone developing on the android platform, however one of the first hurdles that people often stumble upon, is when their project involves one of the SDK libraries, such as Google Maps.

You’ll most likely see something like this when you attempt to first compile the project :

[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6.597s
[INFO] Finished at: Thu Jul 19 10:28:12 BST 2012
[INFO] Final Memory: 7M/81M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal on project WifiSpotter: Could not resolve dependencies for project com.jameselsey.android.apps.wifispotter:WifiSpotter:apk:0.1-SNAPSHOT: Failed to collect dependencies for [com.google.android:android:jar:2.1.2 (provided), com.google.android:android-test:jar:2.2.1 (provided), com.pivotallabs:robolectric:jar:1.0 (test), junit:junit:jar:4.8.2 (test), com.google.android.maps:maps:jar:8_r1 (provided)]: Failed to read artifact descriptor for com.google.android.maps:maps:jar:8_r1: Could not transfer artifact com.google.android.maps:maps:pom:8_r1 from/to cloudbees-private-release-repository (https://repository-
[ERROR] jameselsey
[ERROR] .forge.cloudbees.com/release): IllegalArgumentException: Illegal character in authority at index 8: https://repository-
[ERROR] jameselsey
[ERROR] .forge.cloudbees.com/release/com/google/android/maps/maps/8_r1/maps-8_r1.pom

As we can see, maven is unable to find the maps artefact, and rightly so. This is because the Google jars are not available (at least not at the time of writing this) on the maven central repositories. Fortunately for us, its relatively easy to resolve this, we just need to obtain the artefacts from our android home area, and then install them to our maven repositories so our projects have access to them.

You could manually install all of them, but this would be quite a lengthy task, and relatively unnecessary with the help of the maven-android-sdk-deployer, this nifty little tool will extract the libraries from your local android SDK installation, and install them as maven dependencies, to your local repository. From there, you can just depend on them as any other maven artefact, such as :

<dependency>
  <groupId>android</groupId>
  <artifactId>android</artifactId>
  <version>4.1_r2</version>
  <scope>provided</scope>
</dependency>

There is no need for me to cover how to use this tool, since it is pretty well documented, however I would like to refer you to a previous post of mine regarding deploying maven artefacts to a CloudBees repository, combined with this post, you can quite easily and reliably maven-ise the android dependencies, and deploy them into the cloud. Then you can build your android projects using maven from anywhere, and also take advantage of the free Jenkins service they provide.

Remember to drop in the repository into the pom.xml, and then you can simply run :

mvn clean install deploy:deploy

Hope this helps, if anything is unclear, please let me know!

Deploying artefacts into your CloudBees maven repositories.

If you’re like me, and have a fair few hobby projects on the go at any one time, you’re may want to take advantage of some of the free cloud services that are available out there. I’m particulary fond of the Maven repositories that CloudBees offer, as it gives you a safe and easy way to deploy your artefacts, whether they’re 3rd party libraries, snapshots, or even releases of your own software.

Head over to CloudBees.com and register an account, its free.

I’ve recently been doing a fair bit of work 3rd party libraries that are not available on the maven repositories, you have to download the source and compile it yourself (I have another post about an example of that). Since I often develop on different machines, and I’m not actually changing the library, I wanted a single place where I could upload a pre compiled copy of it and just depend on it as I would any other library, such as JUnit.

The first task, is to get your project compiling and working locally, once that is done you can then add the following into your pom.xml

Repository (that references a configured repository on ~/.m2/settings.xml)

<repository>
            <id>cloudbees-private-snapshot-repository</id>
            <name>cloudbees-private-snapshot-repository</name>
            <url>dav:https://repository-jameselsey.forge.cloudbees.com/snapshot/</url>
        </repository>

Also, since maven 3 requires the webdav extension, you’ll need to add this into the build/extensions section of your pom.xml:

<extensions>
            <!-- Extension required to deploy a snapshot or a release to the CloudBees remote maven repository using Webdav -->
            <extension>
                <groupId>org.apache.maven.wagon</groupId>
                <artifactId>wagon-webdav</artifactId>
                <version>1.0-beta-2</version>
            </extension>
        </extensions>

After that, make sure that your ~/.m2/settings.xml file contains details of your CloudBees repositories, here is my copy, make sure you put your password in, and replace occurences of “jameselsey” with your own user ID.

<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
-->
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<servers>
    <server>
        <id>cloudbees-private-snapshot-repository</id>
        <username>jameselsey</username>
        <password>YOUR_PASSWORD_HERE</password>
        <filePermissions>664</filePermissions>
        <directoryPermissions>775</directoryPermissions>
    </server>
    <server>
        <id>cloudbees-private-release-repository</id>
        <username>jameselsey</username>
        <password>YOUR_PASSWORD_HERE</password>
        <filePermissions>664</filePermissions>
        <directoryPermissions>775</directoryPermissions>
    </server>
    <server>
        <id>cloudbees-private-snapshot-plugin-repository</id>
        <username>jameselsey</username>
        <password>YOUR_PASSWORD_HERE</password>
        <filePermissions>664</filePermissions>
        <directoryPermissions>775</directoryPermissions>
    </server>
    <server>
        <id>cloudbees-private-release-plugin-repository</id>
        <username>jameselsey</username>
        <password>YOUR_PASSWORD_HERE</password>
        <filePermissions>664</filePermissions>
        <directoryPermissions>775</directoryPermissions>
    </server>
</servers>
<profiles>
    <profile>
        <id>cloudbees.private.release.repository</id>
        <activation>
            <property>
                <name>!cloudbees.private.release.repository.off</name>
            </property>
        </activation>
        <repositories>
            <repository>
                <id>cloudbees-private-release-repository</id>
                <url>https://repository-jameselsey.forge.cloudbees.com/release</url>
                <releases>
                    <enabled>true</enabled>
                </releases>
                <snapshots>
                    <enabled>false</enabled>
                </snapshots>
            </repository>
        </repositories>
    </profile>
    <profile>
        <id>cloudbees.private.snapshot.repository</id>
        <activation>
            <property>
                <name>!cloudbees.private.snapshot.repository.off</name>
            </property>
        </activation>
        <repositories>
            <repository>
                <id>cloudbees-private-snapshot-repository</id>
                <url>https://repository-jameselsey.forge.cloudbees.com/snapshot</url>
                <releases>
                    <enabled>false</enabled>
                </releases>
                <snapshots>
                    <enabled>true</enabled>
                </snapshots>
            </repository>
        </repositories>
    </profile>
    <profile>
        <id>cloudbees.private.release.plugin.repository</id>
        <activation>
            <property>
                <name>!cloudbees.private.release.plugin.repository.off</name>
            </property>
        </activation>
        <pluginRepositories>
            <pluginRepository>
                <id>cloudbees-private-release-plugin-repository</id>
                <url>https://repository-jameselsey.forge.cloudbees.com/release</url>
                <releases>
                    <enabled>true</enabled>
                </releases>
                <snapshots>
                    <enabled>false</enabled>
                </snapshots>
            </pluginRepository>
        </pluginRepositories>
    </profile>
    <profile>
        <id>cloudbees.private.snapshot.plugin.repository</id>
        <activation>
            <property>
                <name>!cloudbees.private.snapshot.plugin.repository.off</name>
            </property>
        </activation>
        <pluginRepositories>
            <pluginRepository>
                <id>cloudbees-private-snapshot-plugin-repository</id>
                <url>https://repository-jameselsey.forge.cloudbees.com/snapshot</url>
                <releases>
                    <enabled>false</enabled>
                </releases>
                <snapshots>
                    <enabled>true</enabled>
                </snapshots>
            </pluginRepository>
        </pluginRepositories>
    </profile>
</profiles>
</settings>

Now, if you run mvn clean install deploy:deploy, maven will create a clean build of your application, install it to your local repository, and then deploy it to your CloudBees snapshot repo.

[INFO] --- maven-deploy-plugin:2.7:deploy (default-cli) @ tess-two ---
WAGON_VERSION: 1.0-beta-2
Downloading: dav:https://repository-jameselsey.forge.cloudbees.com/snapshot/tess-two/tess-two/0.0.1-SNAPSHOT/maven-metadata.xml
Downloaded: dav:https://repository-jameselsey.forge.cloudbees.com/snapshot/tess-two/tess-two/0.0.1-SNAPSHOT/maven-metadata.xml (769 B at 0.7 KB/sec)
Uploading: https://repository-jameselsey.forge.cloudbees.com/snapshot/tess-two/tess-two/0.0.1-SNAPSHOT/tess-two-0.0.1-20120720.120205-2.apklib
Uploaded: https://repository-jameselsey.forge.cloudbees.com/snapshot/tess-two/tess-two/0.0.1-SNAPSHOT/tess-two-0.0.1-20120720.120205-2.apklib (5865 KB at 449.0 KB/sec)
Uploading: https://repository-jameselsey.forge.cloudbees.com/snapshot/tess-two/tess-two/0.0.1-SNAPSHOT/tess-two-0.0.1-20120720.120205-2.pom
Uploaded: https://repository-jameselsey.forge.cloudbees.com/snapshot/tess-two/tess-two/0.0.1-SNAPSHOT/tess-two-0.0.1-20120720.120205-2.pom (3 KB at 1.2 KB/sec)
Downloading: https://repository-jameselsey.forge.cloudbees.com/snapshot/tess-two/tess-two/maven-metadata.xml
Downloaded: https://repository-jameselsey.forge.cloudbees.com/snapshot/tess-two/tess-two/maven-metadata.xml (276 B at 0.6 KB/sec)
Uploading: https://repository-jameselsey.forge.cloudbees.com/snapshot/tess-two/tess-two/0.0.1-SNAPSHOT/maven-metadata.xml
Uploaded: https://repository-jameselsey.forge.cloudbees.com/snapshot/tess-two/tess-two/0.0.1-SNAPSHOT/maven-metadata.xml (769 B at 0.4 KB/sec)
Uploading: https://repository-jameselsey.forge.cloudbees.com/snapshot/tess-two/tess-two/maven-metadata.xml
Uploaded: https://repository-jameselsey.forge.cloudbees.com/snapshot/tess-two/tess-two/maven-metadata.xml (276 B at 0.2 KB/sec)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 49.874s
[INFO] Finished at: Fri Jul 20 13:02:24 BST 2012
[INFO] Final Memory: 16M/81M
[INFO] ------------------------------------------------------------------------

The same should work for releases, just alter the repository in the pom to point to the releases repo. This isn’t particularly CloudBees specific either, it should work on any remote maven repository, I just like CloudBees, and no, I don’t work for them :P

Any comments/suggestions, please shout!

Tesseract OCR on Android is easier if you Maven-ise it, works on Windows too…

I’ve spent the past few months working on an android application that involves an element of OCR capability, its been quite a painful journey so this is my attempt to reflect on these experiences and hopefully help others who follow in my path.

From Wikipedia : In geometry, the tesseract, also called an 8-cell or regular octachoron or cubic prism, is the four-dimensional analog of the cube.

First off, lets just cover the basics. OCR stands for Optical Character Recognition, which is the process of taking an image, and being able to interpret the image and obtain textual data from it. For example, you take a photograph of a road sign, this would be an image file such as a JPEG. You can clearly see that the road sign says “Slow down”, however to a computer program, its just an image file. OCR enables the program to literally scan the image and find text, which your program can then use elsewhere in its workings.

After spending the best part of several days attempting to create a simple OCR application on android, and after suffering much frustration due to the lack of general resources available on the subject, I was able to find some good material by Gautam and rmthetis.

Whilst those guys have made a fantastic effort in their tutorials, I still needed to do further tasks to get an OCR demo off the ground, so hopefully this post will be a good supplement to their work.

The first misconception I wanted to clean up on is “this will only work on linux“, whilst the tutorials from the aforementioned authors are targetted against linux development environments, the above statement is not entirely true. Following their tutorials I was able to get it working first time on my Windows 7 development laptop. I also got this working on my new replacement Windows 7 laptop a week or two later without any troubles (and mc Macbook Pro too), all I did was follow these instructions which are on the github page for tess-two:

git clone git://github.com/rmtheis/tess-two tess
cd tess/tess-two
ndk-build
android update project --path . 
ant release

The above will clone the tess-two project by rmtheis, build the shared objects, update the project, then build the APK. I didn’t have any trouble doing this on a Windows environment. It is worth noting however, that the ndk-build can take time, I think on my first laptop it took around 20-30 minutes to complete, but it was a low spec machine.

Maven is Awesome with a Capital A

Most of the pain I experienced was integrating the libraries into my existing project. My project was already using maven so it made sense to attempt to package up the tess projects as libraries and depend on them as I would any other library, such as commons-lang (I’ve recently discovered that Google Guava is far better, but thats another topic).

I had quite a lot of trouble doing this at first, but it probably wasn’t aided by the fact I was moving my development environment from Windows 7 to Mac OS X Lion, attempting to (for the 3rd time) migrate from IntelliJ Idea to Eclipse (I gave up, Idea is still far superior and easier to use IMHO) and I was trying to ensure the IDE was happy with the project structure, which is no mean feat. I had a lot of problems trying to get m2eclipse to recognise the APKLIB packaging concept, even with the m2eclipse android connector I still struggled with plugin compatibility issues and general mis-understanding between the eclipse plugins and maven. It always compiled directly from the command line however.

Eventually, all it boiled down to, was including a pom.xml in both the tess-two and eyes-two root folders, which instructs maven to package them up as apklib files. As detailed on the android-maven-plugin website, the plugin is smart enough to know that when you request an apklib type project, it knows exactly where to find all the artefacts to include.

After following the above instructions that I’ve pulled from the tess-two github page, drop in this pom.xml into the root folder, tess/tess-two :

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>tess-two</groupId>
  <artifactId>tess-two</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>apklib</packaging>
  <dependencies>
        <dependency>
            <groupId>com.google.android</groupId>
            <artifactId>android</artifactId>
            <scope>provided</scope>
            <version>2.3.3</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
            <version>4.8.2</version>
        </dependency>
    </dependencies>

    <build> 
        <sourceDirectory>src</sourceDirectory>
        
        <plugins>
            <plugin>
                <groupId>com.jayway.maven.plugins.android.generation2</groupId>
                <artifactId>android-maven-plugin</artifactId>
                <extensions>true</extensions>
                <version>3.2.0</version>
                <configuration>
                    <sdk>
                        <platform>10</platform>
                    </sdk>
                    <undeployBeforeDeploy>true</undeployBeforeDeploy>
                    <attachSources>true</attachSources>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Drop into the command line, and run :

mvn clean install

This will then package up the tess-two application into an APKLIB file, and install it to your local maven repository. You can then depend on tess-two for any project you like, using the following dependency :

        <dependency>
            <groupId>tess-two</groupId>
            <artifactId>tess-two</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <type>apklib</type>
        </dependency>

Of course, feel free to change the group ID or version numbers as you see fit, just make sure they match up to the tess-two pom. You can also use the above approach for the eyes-two project, but remember that eyes-two is dependent on tess-two, so don’t forget the dependency!

You should then be able to start using the TessBaseAPI as Gautam covers in his post, this post here merely gets you going with maven. I’ve been in contact with Robert, chances are we’ll be getting this properly mavenised soon, so you can then depend on it from the central repositories rather than doing the installation mentioned here, we’ll keep you posted. (Robert, if you’re reading, get back to me mate!)

Hope this is of help, any questions then please ask, I’ll also be covering the iOS tesseract soon too, that was a little easier to get started.

Thanks

Automating android application signing and zipaligning with maven

Code rage

This is something that has had me tearing my hair out for a few days now, I was pretty much border-line braveheart-ing my screen….

Code rage

I’ve recently been on a little drive to try to maven-ize my projects. All had been going well until I needed to sign and zipalign my APKs. This post will help you conquer that barrier with the use of some maven plugins.

When using ant, I was able to simply enter keystore details into build.properties and just call “ant release”. Unfortunately that approach doesn’t carry across to maven, and you have to provide some more configuration.

Firstly, before we go any further, I’m going to assume that you already have a maven android project setup, so you have a pom.xml, you’ve configured the maven-android-plugin and you can run “mvn clean install” to build your APK, and “mvn android:deploy” to deploy it to an emulator. If you haven’t got that far, I’d suggest you have a look at one of my previous posts to help get you up to speed.

So, when you want to build your application with maven, you’d run “mvn install”. That will, by default, use a debug key to sign your APK. When we want to build a releasable APK we still want to execute the same install goal, however we’ll want to use a proper key. Luckily, maven provides something called profiles.

In short, maven profiles allow you to still perform the same standard goals, yet they behave slightly different, in the manner of binding extra steps to them, all will come clearer in a moment.

This 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 and each time I was unable to get the signing process to work correctly, each time I encountered the following error :

INFO] jarsigner: attempt to rename C:\android-projects\jameselsey_andsam_branch_mavenbranch\target\LanguageSelection-1.0.0-SNAPSHOT.jar to C:\android-projects\jameselsey_ands
am_branch_mavenbranch\target\LanguageSelection-1.0.0-SNAPSHOT.jar.orig failed
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Failed executing 'cmd.exe /X /C "C:\development\tools\Java\jdk1.6.0_20\jre\..\bin\jarsigner.exe -verbose -keystore my-release-key.keystore -storepass '*****' -keypass '
*****' C:\android-projects\jameselsey_andsam_branch_mavenbranch\target\LanguageSelection-1.0.0-SNAPSHOT.jar mykeystore"' - exitcode 1
[INFO] ------------------------------------------------------------------------

I’d tried everything, even copying out the command and pasting into a command window worked, but I could not get it to work from maven. Unfortunately it seems there may be an issue with the maven-jarsigner-plugin (as suggested in the comments on the Novoda post). However fear not, for there is an alternative, the maven-jar-plugin.

The maven-jar-plugin is a similar plugin to the jarsigner plugin, however the signing APIs are now deprecated and it points you to use the (apparently) broken maven-jarsigner-plugin. Using a deprecated API doesn’t particulary concern me in this instance, as its just signing artefacts.

Take a look at my profiles section, copy this into your pom.xml :

<profiles>
<profile><!-- release profile. uses keystore defined in keystore.* properties. signs and zipaligns the app to the target folder-->
            <id>release</id>
            <activation>
                <activeByDefault>false</activeByDefault>
            </activation>
            <build>
                <defaultGoal>install</defaultGoal>
                <finalName>${project.artifactId}-${project.version}</finalName>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-jar-plugin</artifactId>
                        <version>2.2</version>
                        <executions>
                            <execution>
                                <id>signing</id>
                                <goals>
                                    <goal>sign</goal>
                                </goals>
                                <phase>package</phase>
                                <inherited>true</inherited>

                                <configuration>
                                    <keystore>
                                        my-release-key.keystore
                                    </keystore>
                                    <storepass>mypassword</storepass>
                                    <keypass>mypassword</keypass>
                                    <alias>mykeystore</alias>
                                    <verbose>true</verbose>
                                    <verify>true</verify>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>

                    <plugin>
                        <groupId>com.jayway.maven.plugins.android.generation2</groupId>
                        <artifactId>maven-android-plugin</artifactId>
                        <inherited>true</inherited>
                        <configuration>
                            <sign>
                                <debug>false</debug>
                            </sign>
                        </configuration>
                    </plugin>

                    <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}-${project.version}-RELEASE.apk
                                </outputApk>
                            </zipalign>

                        </configuration>
                        <executions>
                            <execution>
                                <id>zipalign</id>
                                <phase>install</phase>
                                <goals>
                                    <goal>zipalign</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>
</profiles>

OK, so lets walk through what the above profile does. Firstly, the “id” of the profile is “release”, so when you want to apply this profile, you’d run “mvn install -Prelease”. The “activeByDefault” is set to false, which means you need to use the above arguement, if you flip that over, you won’t need the P flag.

The execution goal is to “sign”, which is the API on the plugin, documented here. We bind this execution on to the standard “package” goal. Then we provide the configuration elements which specify the details of the keystore.

In pure English, this binds the plugin phase onto the package goal of maven, so anytime we run using this profile it’ll execute the jar signing of our artefacts. The “verify” tag gives us extra piece of mind by verifying that the signing was successful afterwards.

I’ve also setup a zipalign profile that will take the APK, zipalign it, and rename it to “*-RELEASE.apk”, so I know that particular APK is the one which I’ll release to market.

So thats it, once more a success, and its just one small step on the ladder to android glory!

Phhew!! Done, finally I was able to shutdown the laptop and go to sleep at 3am….on a school night!!!

Good luck, feel free to comment!

Peace.

Android; Continuous integration, all made lovely with Maven

Lets face it, the eclipse ADT plugin is great for getting an android application up and running quickly, but if you want an easier way to get libraries, and a continuous intergration environment for robust automated testing and building, then maven is the way to go.

IntelliJ have recently released the Early Access Program to their version X of IDEA, this comes with Android support in the community edition, meaning we’re no longer bound to using eclipse for Android development!

The first thing you want to do, is to run through the “create new project” wizard in IntelliJ, its fairly straightforward, just run through and setup a simple android applicaiton. When you’ve got that, run it up on the emulator just to make sure any autogenerated code IntelliJ created works OK.

OK so now we’re ready to start gutting it out and providing the Maven framework. First thing you need to do, in the root directory of the android project, create a file called pom.xml with the following contents

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>MavenMess</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>apk</packaging>
    <name>Maven Android Plugin - samples</name>

    <dependencies>
        <dependency>
            <groupId>com.google.android</groupId>
            <artifactId>android</artifactId>
            <version>2.2.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>${project.artifactId}</finalName>
        <sourceDirectory>src</sourceDirectory>
        <plugins>
            <plugin>
                <groupId>com.jayway.maven.plugins.android.generation2</groupId>
                <artifactId>maven-android-plugin</artifactId>
                <version>2.6.0</version>
                <configuration>
                    <sdk>
                        <!--  platform or api level (api level 4 = platform 1.6)-->
                        <platform>8</platform>
                    </sdk>
                    <emulator>
                        <!--  the name of the avd device to use for starting the emulator-->
                        <avd>GoogleAPIs</avd>
                    </emulator>
                    <deleteConflictingFiles>true</deleteConflictingFiles>
                    <undeployBeforeDeploy>true</undeployBeforeDeploy>
                </configuration>
                <extensions>true</extensions>
            </plugin>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <!--  version 2.3 defaults to java 1.5, so no further configuration needed-->
                <version>2.3</version>
            </plugin>
        </plugins>
    </build>
</project>

The POM file is what maven uses to build/test your project. If you’re not familiar with maven at this stage I’d suggest a quick browse of their documentation to get to grips with the fundamentals.

The above POM does a couple of tasks, firstly it tells maven to build an APK file using the packaging statement. You need this otherwise maven wouldn’t know what to create, and might create a WAR or EAR file instead.

You declare the android SDK as a provided dependancy. Next comes the build section, this is where the magic happens. The source directory tells maven where it can find all your android source files to compile.

You’ll need to declare usage of the Jayway plugin, this is a neat little plugin that I picked up from Hugo Josefson from Jayway, at DroidCon UK 2010. There is some configuration that you can set here such as the API level and which emulator to deploy the application to. The second plugin is the maven Java compiler, we need this in order to actually compile the class files.

Right so thats your POM sorted, next you can go ahead and delete the following items

  • \bin
  • \libs
  • build.properties
  • build.xml

You won’t need those files/directories, those are used for the autogenerated ant build script that the android IntelliJ plugin creates, and we’re now using maven.

Right thats it for the maven configuration, next comes actually running the application. The maven goal of “mvn install” will compile all your classes, so run that to check the above is OK.

To deploy your application to a device, you can run the maven goal of “mvn android:deploy”. These goals are great, but what about a 1 button click for building and deploying? Easy…

Along the top of IntelliJ, click on the drop down menu for run targets and create a new run/debug configuration. Using the goal of “android:deploy” will deploy the application to the emulator, but you can also setup a goal of “mvn install” which happens before deployment, as shown in the screenshot below. This will build and deploy your application to the emulator with one click.

All you need to do then is to go into your emulator and start your application, simple!

Any questions/suggestions, please let me know!

Big thanks to the guys at Jayway for sharing this, and making it possible.