Android Application Development with Maven
Chapter 14
EXPLORE MORE
EXPLORE MORE
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.
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.
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.
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.
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.
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.
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.1. Creating New Projects with the Android Maven Archetypes
- 14.3.2. Using Add-Ons
- 14.3.3. Multi Module Android Projects
- 14.3.4. Using external dependencies
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 ofapk
- 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
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.
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>
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.
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.
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.
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.
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.
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).
A number of plugin goals are useful for manual execution or custom binding to a lifecycle phase e.g. in a release profile.
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
.
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
.
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.
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.
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.
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.
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.1. Other Maven Plugins
- 14.11.2. Performing a Release Build
- 14.11.3. Configuring command line usage
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.
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.
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>