Maven: The Complete Reference

Android Application Development with Maven

Chapter 14

14.1. Introduction

Android is an open source mobile phone and embedded device operating system developed by the Open Handset Alliance. It is based on a Linux kernel with a virtual machine environment for managed application code using Java bytecode for the runtime code generation. The development environment is based on the Java language and JVM/JDK based tooling. The generated Java bytecode is transformed into Dalvik executable code optimized for constrained devices. Once deployed to the device and executed the code will run on the Dalvik virtual machine. Java is the default programming language and the API’s are all Java based.

In most cases, development of Android applications is done within the Eclipse based Android Studio. The optionally generated Apache Ant based build can be used to build applications outside the IDE. The Android Maven Plugin was created to allow development teams to build, deploy and release Android applications with Apache Maven, taking advantage of all the powerful features available like dependency management, reporting, code analysis and much more.

Tip

The Android Maven Plugin is rapidly evolving. The documentation below applies to version 3.0.0-alpha-12 and higher. For up to date information refer to the plugin website.

14.2. Configuring Build Environment for Android Development

Before you attempt to build your Android libraries and applications with Maven, you will need to install the Android SDK and potentially install the Android API jar files into your local Maven repository or your repository server.

14.2.1. Installing the Android SDK

The Android Maven Plugin requires the presence of the Android SDK in your development environment. Install the SDK following the directions on the Android Developer web site.

The ANDROID_HOME environment variable should be configured to point to the installation directory of the Android SDK. For example if the SDK is installed in /opt/android-sdk-linux this can be achieved with

export ANDROID_HOME=/opt/android-sdk-linux

on a Unix/bash based system or

set ANDROID_HOME=C:\opt\android-sdk-linux

on a Windows system.

In addition to the SDK, the various platform versions you need for development should also be installed following the instructions. You can install a subset of available platforms or simply install all available versions.

Optionally, the path ANDROID_HOME/tools and ANDROID_HOME/platform-tools can be added to the PATH variable to allow easy command line execution of the various tools provided with the SDK.

14.2.2. Android artifact install into Maven repository

When building an Android application with Maven the compile process needs access to the Android API for the specific platform version the project is configured against. The Android SDK ships this as android.jar files in the different platform folders. In order for Maven to access these libraries, they need to be available in the local Maven repository.

Typically artifacts are available in Maven Central, however only the platform versions available in the Android Open Source Project are published to Maven Central. Newer versions of the platform as well as the compatibility package and proprietary extensions like the Google Maps support are not available there and need to be published to your Maven repository, if you want to use them in your Android project.

The artifacts published to Maven central are available as dependencies under the groupId com.google.android with the artifactId android and android-test.

The Maven Android SDK Deployer has been created to publish artifacts from the Android SDK into your local repository or repository server when using components that are not available in Central.

Download the tool by clicking on the Download Source button and extract the downloaded zip or tar archive in a folder of your choice. A folder with a naming pattern of mosabua-maven-android-sdk-deployer-XXX with XXX being a revision number like df824df will be created.

Installation to local repository

In order to install the android jar files from the different platform revisions into your local repository you run the command in the deployer folder.

cd mosabua-maven-android-sdk-deployer-df824df
mvn clean install

By default this will install all android.jar, maps.jar, usb.jar files and the compatibilty packages into your local Maven repository. You should find all newly installed files in the android, com.google.android.maps, com.android.future and android.support group identifiers under ~/.m2/repository.

Installation to remote repository

The above deployment works fine for one machine, but if you need to supply a whole team of developers and a cluster of build machines with the artifacts, you will want to deploy the artifacts once to a remote repository server that is available to all users. If you are not currently using a repository manager, you should download Nexus and configure a user with permission to deploy artifacts to a repository. To get started with Nexus, read the Nexus Installation chapter in the free, online Nexus book.

As a first step you will need to edit the repo.url property in the pom.xml in the top folder of the Maven Android SDK Deployer tool to point to the repository you want to publish to. Alternatively you can provide this property in the settings file or with -Drepo.url=theurl on the command line.

Then you need to add a server with the correct access credentials for the server to your Maven Settings file.

Snippet for settings.xml for the repository server access credentials. 

<settings>
    <servers>
        <server>
            <id>android.repo</id>
            <username>your username</username>
            <password>your password</password>
        </server>
    </servers>
</settings>

Once that configuration is completed, you can deploy the artifacts with the command mvn deploy. As a result you should find the artifact in the repository of your remote server.

Installation of a subset of all platforms

By default the Maven Android SDK Deployer tool will attempt to install or deploy all versions of the platforms artifacts into a repository. If you decide to only install a subset of the components the tool can be used with profile options to only install or deploy some artifacts. This can be done by specifying the platform API versions as a profile name.

mvn install -P 3.2

Further details are available in the Maven Android SDK Deployer documentation.

14.3. Getting Started

The HelloFlashlight example application serves as a starting point to introduce you to the usage of the Android Maven Plugin. The code for the helloflashlight example application as well as various more complex examples are available as part of the plugin samples project.

To enable a Maven based build of an Android project a pom.xml has to be added in the root folder of the project:

The HelloFlashlight pom.xml file. 

<?xml version="1.0" encoding="UTF-8"?>
<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.simpligility.android</groupId>
    <artifactId>helloflashlight</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>apk</packaging>
    <name>HelloFlashlight</name>

    <dependencies>
        <dependency>
            <groupId>com.google.android</groupId>
            <artifactId>android</artifactId>
            <version>1.6_r2</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <finalName>${project.artifactId}</finalName>
        <sourceDirectory>src</sourceDirectory>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>com.jayway.maven.plugins.android.generation2</groupId>
                    <artifactId>android-maven-plugin</artifactId>
                    <version>3.0.0-SNAPSHOT</version>
                    <extensions>true</extensions>
                </plugin>
            </plugins>
        </pluginManagement>
        <plugins>
            <plugin>
                <groupId>com.jayway.maven.plugins.android.generation2</groupId>
                <artifactId>android-maven-plugin</artifactId>
                <configuration>
                    <run>
                        <debug>true</debug>
                    </run>
                    <sdk>
                        <platform>4</platform>
                    </sdk>
                    <emulator>
                        <avd>16</avd>
                    </emulator>
                    <undeployBeforeDeploy>true</undeployBeforeDeploy>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

The highlights of this pom.xml are:

  • the packaging type of apk
  • the dependency to the Android platform jar
  • and the build configuration with the Android Maven Plugin

The Android Package packaging type apk is what activates the Android-specific lifecycle modifications of the Android Maven Plugin. It takes care of all the specific calls to the Android SDK tools, that process resources, convert Java bytecode and so on. The Android Maven Plugin needs to be configured with extensions set to true for this to work as visible in the pluginManagement section.

The declared dependency to the android platform jar is available in Maven Central with various platform versions. Alternatively you could use an Android jar from the Maven Android SDK Deployer with the modified groupId and artifactId. The documentation of the deployer shows all valid dependencies.

The scope of provided is important. It signals to Maven that the contents of the jar will not need to be packaged into the application package, because they are available at runtime on the device as part of the environment.

In addition the android jar artifacts only contain exception throwing stubs for all methods in order to define the API for the compiler. They can not be executed on the development machine, but rely on an emulator or device runtime environment.

The configuration of the Android Maven Plugin is done in the build section. Initially only the sdk platform parameter is required to be specified. You can use either a platform version number or a API level number as documented on the Android developer documentation.

Tip

The version of the Android Maven Plugin in the pom file is a development version. Replace it with the latest released version, when running the example yourself or download the stable branch of the samples.

To build the application and run it on an already started emulator or attached device you could use

mvn install android:deploy android:run

14.3.1. Creating New Projects with the Android Maven Archetypes

When starting a fresh project it is easy to use the Maven Archetype Plugin to create a skeleton to start working with. Fortunately multiple archetypes for Android projects are available.

You can create a new android-quickstart project, which is similar to the helloflashlight example on the command line with

 mvn archetype:generate \
  -DarchetypeArtifactId=android-quickstart \
  -DarchetypeGroupId=de.akquinet.android.archetypes \
  -DarchetypeVersion=1.0.6 \
  -DgroupId=your.company \
  -DartifactId=my-android-application

Other archetypes available are an Android project including test execution with the archetypeArtifactId android-with-test-archetype and a project with release process configuration android-release-archetype.

Note

Many developmemt environments have a visual integration of creating new projects with a Maven archetype, so you can use that instead of the command line.

14.3.2. Using Add-Ons

For many applications the normal Android SDK artifact (android.jar) will be sufficient, however some applications require add-ons. One of the more commonly used add-ons is the Google Maps add-on, which provides access to the Google Maps API. The Maps add-on is deployed to your Maven repository by the Maven Android SDK Deployer tool. To use an add on you just have to add the respective dependency to your pom file.

The dependency to the Google Maps API. 

<dependency>
    <groupId>com.google.android.maps</groupId>
    <artifactId>maps</artifactId>
    <version>7_r1</version>
    <scope>provided</scope>
</dependency>

Another common add-on is the compatibility library. It needs to be included in the produced apk and there does not have provided scope.

The dependency to the compatibility library for API v4 and up. 

<dependency>
  <groupId>android.support</groupId>
  <artifactId>compatibility-v4</artifactId>
  <version>r3</version>
</dependency>

14.3.3 Multi Module Android Projects

The Android Maven Plugin can be used in a multi-module project setup. An example setup would be 3 different modules linked via a parent pom.

Java Library Code

This first module could contain any business logic implemented in Java, or any other JVM based language actually, in a jar package.

Android Application Code

This second module would depend on the first module and consist of all the interface code for the Android platform. It would need to use apk packaging and the Maven Android Plugin.

Instrumentation Test

This third module would depend on the second module and implement the integration test of the application.

Together with the use of other modules to separate items it is possible to set up a multi module build for an Android application as well as a server side web application sharing e.g. the code for the core objects and business logic.

A comprehensive example setup like this called morseflash is part of the samples project for the plugin.

14.3.4. Using external dependencies

When using the Android Maven Plugin there are three types of dependencies that are treated differently.

Regular dependencies to other Java libraries

The Java byte code files (.class) of library dependencies as denoted in the normal Maven way are transformed to dalvik executable format like any source code of the current project and included in the Android package. All other files are included as contained in the source library. An example would look like this

<dependency>
    <groupId>com.simpligility</groupId>
    <artifactId>model</artifactId>
    <version>0.1</version>
</dependency>

Dependencies to other Android projects

Other Maven Android projects with packaging type apk declared as dependencies are deployed to the emulator prior to running the instrumentation tests in the integration test phase.

<dependency>
    <groupId>com.simpligility.android</groupId>
    <artifactId>intents</artifactId>
    <version>0.1</version>
    <type>apk</type>
</dependency>

Dependencies to other Android projects' sources

Other Android Maven projects with packaging type apk declared as source dependencies are pulled into the current Android application with assets and resources and used to build an application combining all artifacts including resources.

<dependency>
    <groupId>com.simpligility.android</groupId>
    <artifactId>tools</artifactId>
    <version>0.1</version>
    <type>apklib</type>
</dependency>
Tip

A common use case for using Android libraries is to separate out all application code that is independent of the application store in which the apk will be made available. Then you can have one apk per store that depends on the library and add any specific code for e.g. market access or release build requirements.

14.4. The Custom Lifecycle from the Android Maven Plugin

The Android Maven Plugin customizes the lifecycle based on the packaging. If your project has a packaging of type apk the customized lifecycle will be used.

The customized lifecycle has the following additional executions in the default lifecycle.

generate-sources Phase

Use the Android Asset Packaging Tool (aapt) of the platform version specified in the pom to package the Android specific resources like AndroidManifest.xml, assets and resources. Additional parameters can be passed to aapt with the parameter aaptExtraArgs.

process-classes Phase

Run the dx tool of the platform version specified in the pom to convert all classes (libraries, resources and project code) into davlik executable format.

package Phase

Run the Android Package tool (apk) of the Android SDK to create and sign the Android package file (apk) for installation on the emulator or device.

pre-integration-test Phase

Deploy the currently built Android application package (apk) as well as any other dependencies with packaging type apk to the emulator/device.

integration-test Phase

Run the instrumentation test classes against the deployed application.

14.5. Plugin Configuration Parameters

The Android Maven Plugin supports a large number of configuration parameters. They can typically be passed into the execution as plugin configuration, as properties defined in the pom or settings file or as command line parameters.

An example of a plugin configuration. 

<configuration>
    <sdk>
        <platform>2.1</platform>
    </sdk>
    <emulator>
        <avd>21</avd>
        <options>-no-skin</options>
    </emulator>
</configuration>

Configuration as properties in pom.xml. 

<properties>
    <android.emulator.avd>21</android.emulator.avd>
<properties>

Configuration on command line invocation. 

mvn android:emulator-start -Dandroid.emulator.avd=21

A number of other parameters have defaults that point to the default location as used by the standard Android/Eclipse project layout, but can be customized if desired.

  • androidManifestFile
  • assetsDirectory
  • resourceDirectory
  • sourceDirectories

Some of the other useful parameters are

device

Specify usb, emulator or a specific serial number. Read Section 14.6, “Device Interaction” for more information.

undeployBeforeDeploy

This parameter will cause the application as well as the test application to be undeployed from the device before each deployment.

14.6. Device Interaction

The Android Maven Plugin has powerful features for interacting with attached devices and emulators implemented in a number of goals. They use the android.device parameter to determine a specific device as specified by the serial number, all connected emulators or all connected devices should be affected. A value of emulator will trigger execution on all emulators connected via adb and a value of usb will affect all devices.

The following goals support the device parameter and sequential execution against all devices.

android:deploy

The deploy goal deploys the built apk file, or another specified apk, to the connected device(s). This goal is automatically performed when running through the integration-test lifecycle phase on a project with instrumentation tests (e.g. mvn install or mvn integration-test).

android:undeploy

The undeploy goal removes the apk of the current project, or another specified apk, from the connected devices and emulators.

android:redeploy

The redeploy goal executes undeploy and deploy consecutively on all specified devices and emulators.

android:instrument

The instrument goal runs the instrumentation tests after automatically deploying the test application and the tests. It honors the standard Maven skip test properties as well as android.test.skip. It supports a number of further parameters that are explained in more detail in Section 14.9, “Testing Android Application Code”.

android:pull

The pull goal can be used to copy a file or directory from the device. Source and destination file have to be specified with the android.pull.source and android.pull.destination configuration parameters.

android:push

The push goal can be used to copy a file or directory to the device. Configuration is done with the android.push.source and android.push.destination parameters.

android:run

The run goal will start the application on the device. If the run.debug paramter is set to true starting will wait for a debugger to connect.

14.6.1. Emulator Interaction

The emulator-start goal can start an existing Android device emulator. The start up can be configured with the parameters emulator.avd specifying the name of the virtual device, emulator.wait specifying a wait period and emulator.options specifying further command line options passed to the emulator command.

The emulator-stop and emulator-stop-all goals stop the specified or all attached Android emulator(s).

14.7. Other Useful Android Maven Plugin Goals

A number of plugin goals are useful for manual execution or custom binding to a lifecycle phase e.g. in a release profile.

14.7.1. Manifest-update

The manifest-update goal can be used to do in place updates to the AndroidManifest.xml file. It can update a number of parameters like versionName, versionCode and others and supports the parameters manifest.versionName, manifest.versionCode, manifest.versionCodeAutoIncrement, manifest.versionCodeUpdateFromVersion, manifest.sharedUserId and manifest.debuggable.

14.7.2. Zipalign

The zipalign goal can execute the zipalign command as required for creation an apk for upload to the Android Market. It supports the parameters zipalign.skip, zipalign.verbose, zipalign.inputApk and zipalign.outputApk.

14.7.3. Help

The help goal provides overall as well as plugin goal specific help on the command line.

14.8. Internal Android Maven Plugin Goals

The Android Maven Plugin supports a number of goals that are part of the default lifecycle and are invoked automatically. In most cases you will not have to invoke these goals directly, but it can be useful to know about them and their configuration options.

android:apk

The apk goal creates the android package (apk) file. By default the plugin signs the file with the debug keystore. The configuration parameter <sign><debug>false<debug><sign> can be used to disable the signing process.

android:deploy-dependencies

The deploy-dependencies goal deploys all directly declared dependencies of <type>apk</type> in this project. This goal is usually used in a project with instrumentation tests, to deploy the apk to test onto the device before running the deploying and running the instrumentation tests apk. The goal is automatically performed when running through the integration-test life cycle phase on a project with instrumentation tests (e.g. mvn install or mvn integration-test).

android:dex

The dex goal converts compiled Java classes to the Android Dalivk Executable (dex) format. The dex execution can be configured with the parameters dex.jvmArguments, dex.coreLibrary, dex.noLocals and dex.optimize.

android:generate-sources

The generate-sources goal generates R.java based on the resources specified by the resources configuration parameter. It generates Java files based on aidl files. If the configuration parameter deleteConflictingFiles is true (which it is by default), this goal has also deletes any R.java files found in the source directory, deletes any .java files with the same name as an .aidl file found in the source directory and deletes any Thumbs.db files found in the resource directory.

android:internal-integration-test

The internal-integration-test goal is called automatically when the lifecycle reaches the integration-test phase. It determines whether to call the goal instrument in this phase based on the existence of instrumentation test classes in the current project. The goal is internal to the plugin lifecycle and should not be used as separate invocation on the command line.

android:internal-pre-integration-test

The internal-pre-integration-test goal is called automatically when the lifecycle reaches pre-integration-test phase. It determines whether to call the goals android:deploy-dependencies and android:deploy in this phase and if necessary invokes them. The goal is internal to the plugin lifecycle and should not be used as separate invocation on the command line.

14.9. Testing Android Application Code

Testing Android Application code can be done in a unit test fashion with rich junit support as part of the Android SDK as well as integration type testing called instrumentation testing.

14.9.1. Unit tests

The Android Maven Plugin includes the execution of the Surefire plugin and as such unit tests can be included in the project like in any other project. The default path for test classes in the Eclipse and therefore Android Development Toolkit is test and therefore Maven has to be configured to access code from there with the configuration

Adding the test folder to the build configuration. 

<build>
    <testSourceDirectory>test</testSourceDirectory>
    ...

Alternatively the Maven conventions can be implemented by moving the source code for the application and the test source code into src/main/java and src/test/java and reconfiguring the Eclipse project files.

14.9.2. Instrumentation tests

Instrumentation tests are integration tests bundled into an application that run on the emulator or device and interact with another deployed application to test the behaviour. The common setup to run instrumentation tests would be two parallel projects, one for the application and one for the instrumentation tests. These modules are tied together as modules of a parent pom.

The Android Maven Plugin samples contains the morseflash as well as theapidemos-15 examples for a project set up in this manner. The setup of the instrumentation test application with the Android Maven Plugin is the same as for a normal application with the added dependency to the application that needs to be tested. It is important to add the type of apk to the dependency to allow the Android Maven Plugin to find the Android package of the application.

<dependency>
    <groupId>com.simpligility.android</groupId>
    <artifactId>intents</artifactId>
    <version>0.1</version>
    <type>apk</type>
</dependency>

Instrumentation test execution supports a large number of configuration parameters that are displayed in the plugin configuration layout in Available parameters for instrumentation testing.

Available parameters for instrumentation testing. 

<test>
  <skip>true|false|auto</skip>
  <instrumentationPackage>packageName</instrumentationPackage>
  <instrumentationRunner>className</instrumentationRunner>
  <debug>true|false</debug>
  <coverage>true|false</coverage>
  <logonly>true|false</logonly>  avd
  <testsize>small|medium|large</testsize>
  <createreport>true|false</createreport>
  <classes>
    <class>your.package.name.YourTestClass</class>
  </classes>
  <packages>
    <package>your.package.name</package>
  </packages>
</test>

Unless createreport is set to false the instrumentation test run will produce junit xml compatible test output in the build output folder for test results target/surefire-reports for each device or emulator the tests run on.

14.10. Native Application Builds

The Android Maven Plugin supports building application that include native code as well. Define the environment variable ANDROID_NDK_HOME to point to the required Android NDK installation and have a look at the native projects in the samples of the plugin for more details.

14.11. Tips and Tricks

14.11.1. Other Maven Plugins

Apart from the features of the Android Maven Plugin you have access to all the other Maven plugins to automate things like license header file checks, resource filtering and many more.

14.11.2. Performing a Release Build

A release build for an Android application needs to create an apk file that has been signed and zipaligned. In addition it is adviseable to run shrinking and obfuscation. All these steps can be done with the Maven Jarsigner Plugin, the Proguard Maven Plugin and the zipalign goal of the Android Maven Plugin. A sample configuration of a release build is available in the morseflash example application of the plugin samples.

14.11.3. Configuring command line usage

In order to use the Android Maven Plugin goals on the command line with the short plugin name android outside a directory that contains a reference to the plugin, you have to add the following pluginGroups snippet to your settings.xml file.

Snippet for settings.xml to enable short plugin name usage. 

<pluginGroups>
    <pluginGroup>
        com.jayway.maven.plugins.android.generation2
    </pluginGroup>
</pluginGroups>