Automating Android with Ant

Eclipse is not the only game in town when it comes to compiling Android applications.

An Alternative to Eclipse

The majority of Android application development takes place within the Eclipse environment.

Eclipse is a proven platform for not only Java application development, but also for Android applications thanks to the flexible and capable “plug-in” environment which provides sophisticated functionality for Android developers.

Two examples of this platform-specific, plug-in functionality include:

  • The layout tools provide a “What You See Is What You Get” (WYSIWYG) experience for creating user interface elements
  • The Dalvik Debugging and Monitoring Server (DDMS) lets you peer into a running device, copy files, and more

Add to this list the build-magic that the Android Developer Tools (ADT) perform behind the scenes:

  • resource compilation
  • Java Bytecode-to-Dalvik conversion
  • application packaging and installation

Working in Eclipse for Android is pretty much a no-brainer, particularly when just starting out.

But what if you want to automate your builds and not have to load Eclipse every time a source file changes? After all, shops with larger projects and multi-developer teams might want to perform nightly, incremental builds.

To automate Android builds, we can use ant. ant is a build tool similar to make. Instead of using makefiles, ant uses a file named build.xml which in turn references any number of external Java properties files. ant’s lineage traces back to the Tomcat application server project — and has since found its way into many other projects, including Android.

Creating a project

This next section assumes that you have the Android SDK installed on your development machine as well as a copy of ant in your execution path.

Create a new directory — I am going to call mine: Antroid.

To create a new project, we will use the android command line program found in the tools directory of the Android SDK. To learn more about this very capable program, type:

android /?

to see a quick display of the command line options available to us.

We want to create a new project, so the base command we want is:

android create project

This command takes a number of options. Here is the usage display:


Action "create project":
  Creates a new Android Project.
Options:
  -t --target   Target id of the new project [required]
  -k --package  Package name [required]
  -a --activity Activity name [required]
  -n --name     Project name
  -p --path     Location path of new project [required]

One of the options we need to supply is which platform we want to target. In order to determine which platforms are available on your system, execute the following command:

android list targets

The output is a list of the available targets we can choose from.

Available Android targets:
id: 1 or "android-3"
     Name: Android 1.5
     Type: Platform
     API level: 3
     Revision: 1
     Skins: HVGA (default), HVGA-L, HVGA-P, QVGA-L, QVGA-P
id: 2 or "android-6"
     Name: Android 2.0.1
     Type: Platform
     API level: 6
     Revision: 1
     Skins: HVGA (default), QVGA, WQVGA400, WQVGA432, WVGA800, WVGA854
id: 3 or "Google Inc.:Google APIs:6"
     Name: Google APIs
     Type: Add-On
     Vendor: Google Inc.
     Revision: 1
     Description: Android + Google APIs
     Based on Android 2.0.1 (API level 6)
     Libraries:
      * com.google.android.maps (maps.jar)
          API for Google Maps
     Skins: WQVGA400, WVGA800, WQVGA432, HVGA (default), WVGA854, QVGA

Because we may want to use some Google Maps features in our application, we’re going to use a target value of “3″. This “platform” is based on the 2.0.1 Android platform, but is also equipped with the Google Maps functionality. To learn more about installing multiple Android platforms via the Android SDK and AVD Manager, have a look at this Linux Magazine article.

Let’s go ahead and create a new project:

android create project --target 3 --name antroid --package com.linuxmag.antdemo --activity antroid --path .

Here is the output. Notice that all of the scaffolding for our Android project is generated for us!

Created directory /Users/fableson/Documents/Antroid/src/com/linuxmag/antdemo
Added file ./src/com/linuxmag/antdemo/antroid.java
Created directory /Users/fableson/Documents/Antroid/res
Created directory /Users/fableson/Documents/Antroid/bin
Created directory /Users/fableson/Documents/Antroid/libs
Created directory /Users/fableson/Documents/Antroid/res/values
Added file ./res/values/strings.xml
Created directory /Users/fableson/Documents/Antroid/res/layout
Added file ./res/layout/main.xml
Created directory /Users/fableson/Documents/Antroid/res/drawable-hdpi
Created directory /Users/fableson/Documents/Antroid/res/drawable-mdpi
Created directory /Users/fableson/Documents/Antroid/res/drawable-ldpi
Added file ./AndroidManifest.xml
Added file ./build.xml

The last file in the bunch is the key to using ant — build.xml. Let’s take a closer look.

Building with Ant

The syntax of ant’s build.xml is beyond the scope of both this column and at present, this author. The short story is that the build.xml file created in the previous step contains references to three Java properties files which define environmental- and project-specific settings crucial for building this project.

Of even more significance for Android projects such as this one, a number of references are made to Android SDK-supplied ant Jar files (i.e. libraries) which contain the instructions on how to build an Android project with ant. These steps include all of the Android SDK goodies like the resource compiler and packaging tools. The Android specific rules are found in:

/<YourSDKInstallDirectory>/platforms/<target_platform>/templates/android_rules.xml

Just for fun, let’s take a sneak peak at a couple sections taken from android_rules.xml:

   <!-- Generates the R.java file for this project's resources. -->
    <target name="-resource-src" depends="-dirs">
        <echo>Generating R.java / Manifest.java from the resources...</echo>
        <exec executable="${aapt}" failonerror="true">
            <arg value="package" />
            <arg line="${v.option}" />
            <arg value="-m" />
            <arg value="-J" />
            <arg path="${gen.absolute.dir}" />
            <arg value="-M" />
            <arg path="AndroidManifest.xml" />
            <arg value="-S" />
            <arg path="${resource.absolute.dir}" />
            <arg value="-I" />
            <arg path="${android.jar}" />
        </exec>
    </target>

   <!-- Puts the project's resources into the output package file
         This actually can create multiple resource package in case
         Some custom apk with specific configuration have been
         declared in default.properties.
         -->
    <target name="-package-resources">
        <echo>Packaging resources</echo>
        <aaptexec executable="${aapt}"
                command="package"
                manifest="AndroidManifest.xml"
                resources="${resource.absolute.dir}"
                assets="${asset.absolute.dir}"
                androidjar="${android.jar}"
                outfolder="${out.absolute.dir}"
                basename="${ant.project.name}" />
    </target>

It is possible to override the behavior of these build rules taken from the SDK templates.

OK, now for the hard part, let’s build our project with ant:

ant

OK, so that wasn’t too difficult, was it?

Here is a really neat thing about using ant — we can actually perform a build and install operation in one command:

ant install

This will initiate the build and then copy the application to a connected device or running emulator. Here is the output running on my Macbook and connecting to an instance of the Android emulator:

Buildfile: build.xml
    [setup] Project Target: Google APIs
    [setup] Vendor: Google Inc.
    [setup] Platform Version: 2.0.1
    [setup] API level: 6
    [setup] WARNING: No minSdkVersion value set. Application will install on all Android versions.

-compile-tested-if-test:

-dirs:
     [echo] Creating output directories if needed...

-resource-src:
     [echo] Generating R.java / Manifest.java from the resources...

-aidl:
     [echo] Compiling aidl files into Java classes...

compile:
    [javac] Compiling 1 source file to /Users/fableson/Documents/Antroid/bin/classes

-dex:
     [echo] Converting compiled files and external libraries into /Users/fableson/Documents/Antroid/bin/classes.dex...
     [echo]          

-package-resources:
     [echo] Packaging resources
 [aaptexec] Creating full resource package...

-package-debug-sign:
[apkbuilder] Creating antroid-debug-unaligned.apk and signing it with a debug key...
[apkbuilder] Using keystore: /Users/fableson/.android/debug.keystore

debug:
     [echo] Running zip align on final apk...
     [echo] Debug Package: /Users/fableson/Documents/Antroid/bin/antroid-debug.apk

install:
     [echo] Installing /Users/fableson/Documents/Antroid/bin/antroid-debug.apk onto default emulator or device...
     [exec] 458 KB/s (13187 bytes in 0.028s)
     [exec] 	pkg: /data/local/tmp/antroid-debug.apk
     [exec] Success

BUILD SUCCESSFUL
Total time: 6 seconds

That’s pretty much it — add this to the list of things that take a moment to learn and quite longer to become a “master”. I’d love to continue, but I just learned that Google released version 2.1 of the SDK — which is what the Nexus One is using — so I’m going to run and start downloading the new SDK.

Fatal error: Call to undefined function aa_author_bios() in /opt/apache/dms/b2b/linux-mag.com/site/www/htdocs/wp-content/themes/linuxmag/single.php on line 62