Android Application Development With Maven - Sample Chapter
Android Application Development With Maven - Sample Chapter
P U B L I S H I N G
Jonathan LALOU
$ 29.99 US
19.99 UK
Patroklos Papapetrou
Right from the beginning, this book will cover how to set
up your Maven development environment and integrate it
with your favorite IDE. By sequentially working through the
steps in each chapter, you will quickly master the plugins
you need for every phase of the Android development
process. You will learn how to use Maven to manage
and build your project and dependencies, automate
your Android application testing plans, and develop and
maintain several versions of your application in parallel.
Most significantly, you will learn how to integrate your
project into a complete factory.
Android Application
Development with Maven
ee
Sa
m
pl
C o m m u n i t y
E x p e r i e n c e
D i s t i l l e d
Android Application
Development with Maven
Learn how to use and configure Maven to support all phases
of the development of an Android application
Patroklos Papapetrou
Jonathan LALOU
Android Application
Development with Maven
During the months we were writing this book, a lot of people asked us what would make
this book special and why someone should care to read it. The most powerful argument
that I heard all this time was, "Hey, Google official supports only Gradle to build
Android applications and the latest release of Android Studio makes extensive use
of Gradle. Ant was already replaced and Maven is nowhere. Why do you spend time
writing about developing Android applications with Maven?"
Good questions! The answers, however, is hidden within the question itself. First of all,
there are no books out there that explain step by step about all the development phases
and critical tasks to build and manage the life cycle of an Android Application with
Maven. Maven is stillno matter if we like it or notthe most popular build tool.
Many "traditional" software houses that have invested time and efforts to standardize
their development process around Maven want to make the next step and expand their
portfolio to the Android Market. Clearly, having another build tool only for Android
development doesn't look very practical, although it's an option.
Companies would save a lot of money if they could just plug their Android applications
to the existing development life cycle, driven by Maven. At the same time, it's true that
Maven is a very mature, flexible, and robust build tool. Its extensibility through plugins
and the idea of descriptively configuring the build process without the need to write
scripts made it the de-facto standard.
The reality, however, has shown us that it's not always that easy. Maven provides all the
required plugins to do almost everything, but there are no instructions or well-structured
documentation. You can find blog posts here and there that shortly cover some topics
but this is not enough.
This book aims to fill that gap. It will not teach you how to write Android applications,
although you will find some simple examples. It will guide you, however, from A to Z,
about how to set up all the necessary Maven configuration to compile, run, test,
deploy, release, and verify the quality of an Android application. It's convenient for
both experienced and young Android developers because we provide all the example
code to see Maven in action. This book is also for those of you who already have
some Maven experience but feel lost when you try to integrate it with your Android
development process.
You can read the book sequentially if you have little experience with Maven, but you
can also use it as a reference and jump to any chapter you want as each one is dedicated
to a particular topic. The provided code is separated in different folders per chapter
so that you can easily run the examples and verify that you have correctly followed
the instructions of the book.
We are confident that you will find the book useful and practical, and we hope that
it will help you build your next Android application with Maven.
that is, the basic or complex graphical components and their position,
padding, and so on. Keep in mind, however, that most Android
projects have more than one activity. In this case, this folder will
contain information for each activity: you can consider each activity
as being a screen. The following code snippet shows the contents of
the activity_main.xml file:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight=
"@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world"/>
</RelativeLayout>
and so on.
src/main/java: Here is the folder for Java code specific to the application.
On root.
Chapter 2
package="com.packt.androidMaven"
android:versionCode="1"
android:versionName="1.0-SNAPSHOT">
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="21"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity android:name=".HelloAndroidActivity">
<intent-filter>
<action
android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.
LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
[ 35 ]
The sole difference, compared to other Java project, is the packaging: here, our archive
is neither a "jar" nor an "ejb" or a "war" files, but the Android specific format: APK:
<packaging>apk</packaging>
The next block is made of properties. This corresponds to a good practice to factorize
constants, version numbers, and so on in a unique location, so as to limit and avoid
conflicts of versions:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<platform.version>5.0.1_r2</platform.version>
<android.plugin.version>3.8.2</android.plugin.version>
</properties>
At last, the build block references the Maven plugin for Android. This will be
explored later.
You can add the following block in your settings.xml file,
available in $M2_HOME/conf or ~/.m2 location:
<pluginGroups>
<pluginGroup>
com.jayway.maven.plugins.android.generation2
</pluginGroup>
</pluginGroups>
Then, you will be able to call the plugin without writing the full
qualified name (com.jayway.maven.plugins.android.
generation2:android-maven-plugin).
[ 36 ]
Chapter 2
Creating an AVD
Before running any application, you have to create an Android Virtual Device
(AVD), a kind of software emulator for Android device. Alternatively, you can
run directly on a physical device (phone, tablet, and watch), which is actually
faster. However, creating AVD instances allows you to test your application in a
variety of configurations (OS version, screen size, memory, and so on) which is
almost impossible to do with real devices. You can perform this operation via the
Graphical User Interface (GUI), or in command line. Both produce the same result.
When you see the dialogthe list probably contains no emulators click on New
to add a new AVD. Fill out the fields relating to the device you want to emulate,
as shown in the following screenshot:
[ 37 ]
A pop up will confirm the result and the details of the device.
By default, the AVD are stored in ~/.android/avd or
%USERPROFILE%\.android\avd location. You can override this
location by adding an environment variable named ANDROID_
SDK_HOME, pointing to $ANDROID_HOME/.android for instance.
Beware that AVD Manager will not create this folder if it does not yet
exist; you have to create this folder before running AVD Manager!
In-command line
To create an AVD in-command line, you have to determine the list of AVD you can
create owing to the configuration and content of your SDK.
Run the following command:
%ANDROID_HOME%\tools\android list target
You get the following output (only the first target is printed, as well as the headers of
the others):
Available Android targets:
---------id: 1 or "android-21"
Name: Android 5.0.1
Type: Platform
API level: 21
Revision: 2
Skins: HVGA, QVGA, WQVGA400, WQVGA432, WSVGA, WVGA800
(default), WVGA854, WXGA720, WXGA800, WXGA800-7in, AndroidWearRound,
AndroidWearS
quare, AndroidWearRound, AndroidWearSquare
Tag/ABIs : android-tv/armeabi-v7a, android-tv/x86, androidwear/armeabi-v7a, android-wear/x86, default/armeabi-v7a, default/x86,
default/x8
6_64
---------id: 2 or "Google Inc.:Google APIs :21"
The general pattern to create an AVD is:
$ANDROID_HOME/tools/android --name <name> --target <target> [options]
[ 38 ]
Chapter 2
The target with id 1 parameter corresponds to the platform android-21, and the
default skin is WVGA800. So, to create the same AVD as in the preceding output,
the command line will be as follows:
$ANDROID_HOME/tools/android create avd --name Nexus_7_2012 \
--target "android-21" \
--skin WVGA800 \
--abi default/armeabi-v7a \
--path ~/.android/avd/Nexus_7_2012
Nonetheless, this command-line-created AVD differs from the one created via the
GUI, on the RAM size and heap size. You can edit the config.ini file within the
folder where the AVD is stored (by default, in a subfolder of ~/.android/avd/),
and manually change these settings (as well as many others):
avd.ini.encoding=ISO-8859-1
abi.type=armeabi-v7a
hw.cpu.arch=arm
hw.cpu.model=cortex-a8
hw.lcd.density=240
hw.ramSize=512
image.sysdir.1=system-images\android-21\default\armeabi-v7a\
skin.name=WVGA800
skin.path=platforms\android-21\skins\WVGA800
tag.display=Default
tag.id=default
vm.heapSize=48
[ 39 ]
If you have to create multiple AVD with specific RAM and heap
sizes, you can straightly edit the template, which is located in the skin
you have chosen from the folder, for example, $ANDROID_HOME/
platforms/android-19/skins/WVGA800/hardware.ini.
You can print a list of the installed AVDs by running the command:
$ANDROID_HOME/tools/android list avd
You can also rename, move, and delete AVD with the three command lines,
respectively:
$ANDROID_HOME//tools/android move avd --name Nexus_7_2012 --rename
Nexus_7_2012_bis
AVD 'Nexus_7_2012' moved.
$ANDROID_HOME/tools/android move avd --name Nexus_7_2012_bis --path
$ANDROID_HOME/tmp
AVD 'Nexus_7_2012_bis' moved.
$ANDROID_HOME/tools/android delete avd --name Nexus_7_2012_bis
Deleting file ....\avd\Nexus_7_2012_bis.ini
Deleting folder ...android-sdk-r22.6\tmp
AVD 'Nexus_7_2012_bis' deleted.
[ 40 ]
Chapter 2
Cleaning
Our first step is to clean the project from any generated source code or other artifacts.
Typically, the Maven clean goal is included among any other target command, but
for clarity, since it's the first time we explain this, we will run separate commands.
During the next chapters, you will notice that the clean goal is executed with other
Maven goals. Open a terminal window and navigate to the root of our example
project. Then, run the following command:
mvn clean
Generating sources
Run mvn android:generate-sources command. Have a look at the expected output:
[INFO] Scanning for projects...
[INFO]
[INFO] ----------------------------------------------------------------------[INFO] Building chapter1 1.0-SNAPSHOT
[INFO] ----------------------------------------------------------------------[INFO]
[INFO] --- android-maven-plugin:3.8.2:generate-sources (default-cli) @
chapter1 --[INFO] ANDROID-904-002: Found aidl files: Count = 0
[INFO] ANDROID-904-002: Found aidl files: Count = 0
[INFO] Manifest merging disabled. Using project manifest only
[INFO] C:\dev\android\sdk\build-tools\21.1.2\aapt.exe [package, -f, -
[ 41 ]
Basically, as hinted, android:generate-sources goal calls the aapt tool from the
Android SDK.
As expected, a target/generated-sources file has been created. It contains the
regular files already seen in the preceding text, such as the R.java file.
Build
To build with Maven, simply run mvn clean install.
This compiles the project and generates several artifacts under target directory:
[ 42 ]
Chapter 2
(.class files).
Actually, in the operation of building, our aim is to get an APK file; therefore,
running another goal such as mvn clean android:apk may have obtained the
same result.
Emulator
You can start and stop one or many emulators with Maven commands:
Start
mvn android:emulator-start starts up an AVD. By default, Maven searches for
an AVD named Default. This can be overridden via changing some options:
[ 43 ]
Actually, under Windows the plugin only calls a VB script to launch the emulator.
Stop
mvn android:emulator-stop stops up an AVD. By default, Maven searches for
an AVD named Default. Like emulator-start goal, this default behavior can be
overridden if the POM contains a <configuration> block pointing at the AVD,
or if the command line includes the option -Dandroid.emulator.avd=<name_of_
the_AVD>
Stop all
mvn android:emulator-stop stops all AVD running on the system.
[ 44 ]
Chapter 2
Deploy
With Maven, provided that you have already built the project through mvn clean
Then, in the emulator, the APK that you have compiled and deployed appears in the
application list (as shown in the following screenshot: fourth line, second column):
[ 45 ]
Undeploy
To undeploy the application, run:
mvn android:undeploy
[ 46 ]
Chapter 2
[ 47 ]
Architecture principles
Now that we are able to build and deploy on an AVD, let's resume the development
phase itself.
Standalone application
In "simple cases", the Android application has no contact with any other tier.
The application is self-dependent. Therefore, the principles of architecture
common to any other standalone application apply.
The application has to be divided based on functional criteria, for instance:
domain or model, Data Access Object (DAO), service, and view. In Android
terminology, views are activities. A graph of direct dependencies is shown
in the following image:
In other terms, the view may have direct access to the services, but not to the DAO
layer. Yet, any layer is aware of the model.
This best practice allows developing many applications built on common basic
blocks, with a frontend and a behavior being totally different.
The management of external dependencies is regular: dependencies are defined
mainly by the triplet groupId, artifactId, and version parameters; the
dependency scope can be compile, provided, runtime, or system. If your
application depends on another Android application, do no forget that the
dependency type is apk, and not jar.
[ 48 ]
Chapter 2
This error is not to worry about. If it does bore you, you can get the
source code of the dependencies in the case of open source projects,
and then include them in your own source code (anyway, beware of
licenses such as General Public License (GPL) that may require you to
make your application source code become GPL, too). More seriously,
this problem means your project, or one of its dependencies or even
sub-dependencies, requires Java 1.3 back-compatibility. As stated, you
can ignore this warning.
three submodules:
<modules>
<module>model</module>
<module>service</module>
<module>AndroidTier</module>
</modules>
[ 49 ]
Our first module, model, consists of a single file, representing an entity Book,
as a Java bean, with mere properties, getters and setters, and an overridden
toString() method:
public class Book {
private Integer id;
private String title;
private String format;
private String color;
private Integer numberOfPages;
private Boolean brandNew;
public Book() {
}
public String toString() {
return "Book{" +
"id=" + id +
", title='" + title + '\'' +
", format='" + format + '\'' +
", color='" + color + '\'' +
", numberOfPages=" + numberOfPages +
", brandNew=" + brandNew +
'}';
}
// plus getters and setters
}
Chapter 2
<parent>
<groupId>com.packt.androidMaven</groupId>
<artifactId>sampleProject</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>service</artifactId>
<version>${project.parent.version}</version>
<name>service</name>
<dependencies>
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>model</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
</project>
The Android application consists of a single activity, calling the service and displaying
the result:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final TextView textview;
final Book book;
book = bookService.createBook("Maven and Android", "eBook",
"black", 150);
textview = new TextView(this);
textview.setText(book.toString());
setContentView(textview);
}
You can build the project from the parent POM folder:
mvn clean install
[ 52 ]
Chapter 2
[ 53 ]
An Android application integrated within a larger project must follow the same rules
as any other multi-tier project:
The Android application artifact should contain only the resource and source code
specific to the application. In other terms, matching with Model-View-Controller
(MVC) design pattern, concentrate the look and feel the information in the project
that will generate the APK. Business treatments, common to the Android application
and a web application for instance, must be factorized in a common business layer.
[ 54 ]
Chapter 2
Another best practice is to expose the entities and interfaces needed by the Android
application in a minimal set of dependencies.
In the following schema, the Android application depends only on an artifact named
contract, gathering entities and declared service interfaces. You may notice that the
service implementation web application artifacts also depend only on contract as
well as on dao:
[ 55 ]
The entity parameter has no special dependency, unlike service parameter that
depends on entity parameter.
contract declares itself as pom, and propagates the two dependencies onto entity
and service parameters:
<?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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.packt.androidMaven.chapter2</groupId>
<artifactId>multitiers</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<packaging>pom</packaging>
<artifactId>contract</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- This POM declares and propagates two dependencies -->
<dependencies>
<dependency>
<groupId>com.packt.androidMaven.chapter2</groupId>
<artifactId>entity</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.packt.androidMaven.chapter2</groupId>
<artifactId>service</artifactId>
[ 56 ]
Chapter 2
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
[ 57 ]
Summary
Thus, in this second chapter, we learned or revised concepts related to Android
SDK and tools. We reviewed how to create AVDs in the GUI and in the command
line. We saw how to start/stop an emulator from Maven, and how to clean, build,
deploy, and undeploy an APK onto an emulator. Finally, we described best practices
in the architecture of Android projects managed by Maven.
In the next chapter, we will begin exploring unit testing.
[ 58 ]
www.PacktPub.com
Stay Connected: