BlackBerry Development: Using Apache Ant

Learn details on how to develop BlackBerry application software using Apache Ant.


September 29, 2004
URL:http://www.drdobbs.com/blackberry-development-using-apache-ant/48800167

Research in Motion's (RIM) latest generation of Java-based BlackBerry handsets supports the Mobile Information Device Profile (MIDP) 1.0 as well as an extensive set of BlackBerry-specific APIs, a CLDC-based programming model, a proprietary development environment, unique application deployment details, and a proprietary runtime/device environment.

To help developers write BlackBerry applications, RIM offers the Java Development Environment (JDE), a BlackBerry-specific Integrated Development Environment (IDE) that supports various BlackBerry simulators for their various Java handsets. The JDE provides the typical features found on IDEs such as support for workspaces, projects, and the ability to build and debug BlackBerry applications all within the JDE.

However, you may need to build your application outside of the JDE, either because you prefer to work in a different IDE or because your BlackBerry application is just one part of a much larger system that needs to be built together. The JDE can generate a Makefile, but many developers prefer the cross-platform and extensible Apache Ant build tool.

In this article I will show how to use Ant to build BlackBerry applications. You can use this script to build from the command-line or your favorite IDE, and to integrate your application into your overall build process. I will begin with a brief introduction to the JDE's build capabilities, followed by how to use Apache Ant to build BlackBerry applications.

Using the JDE to Build Your BlackBerry Application

As previously mentioned, the JDE provides an integrated environment for writing, building and debugging your BlackBerry applications. The JDE can also generate a Makefile that you can use to build your application from the command line and/or integrate your application build into a Make-based development process. Figure 1 shows the "Generate Makefile and Resources" item on the Build menu.

Figure 1. - The JDE Build Menu

The result is a Makefile similar to the one in Listing 1. If you look at this Makefile carefully, you will note a line similar to the following:
@C:\BlackBerryJDE3.7\bin\rapc.exe -quiet import=C:\BlackBerryJDE3.7\lib\net_rim_api.jar codename=MyClientApp MyClientApp.rapc $(MyProject_sources)

This line shows how to invoke the RAPC compiler that is used by the JDE to build the application's executable .cod file.

Quick Overview of BlackBerry Files

Lets briefly cover the files that you will encounter when creating a BlackBerry application:

It is important to emphasize that what gets loaded into BlackBerry handsets are .cod files. If you have a MIDlet, it must first be converted to a .cod package.

The BlackBerry RAPC Compiler

RAPC is the command line compiler that is used to compile .java files into .cod files that are loaded onto the handheld. Figure 2 illustrates the input and outputs of the RAPC compiler:

Figure 2. - Using the RAPC Compiler

Inputs to the RAPC compiler are:

  1. Source .java files or input JAR file.
  2. JAD file for the application.
  3. List of import libraries such as the RIM APIs and dependant 3rd party libraries.
  4. Codename to use for the application - must match the .jar file name.
  5. The -midlet flag - optional flag set if building a MIDlet instead of a CLDC application. You also need to properly populate the standard MIDlet-* JAD and MANIFEST attributes

For example, the RAPC compiler's usage is as follows:

    rapc.exe import=C:\BlackBerryJDE3.7\lib\net_rim_api.jar codename=MyClientApp MyClientApp.jad MyClientApp.jar

The RAPC compiler generates a .cod file and a modified JAD file with BlackBerry specific entries added to it, such as the size of the .cod file, creation time, signature, and other. Listing 2 shows a JAD file for a BlackBerry CLDC application:

Listing 2. - Sample JAD file for a BlackBerry CLDC Application

Manifest-Version: 1.0
MIDlet-Version: 0.0
MIDlet-Jar-Size: 205354
MicroEdition-Configuration: CLDC-1.0
MIDlet-Jar-URL: MyClientApp.jar
MIDlet-Name: MyClientApp
MIDlet-1: ,,
MicroEdition-Profile: MIDP-1.0
MIDlet-Vendor: J2MEDeveloper.com
RIM-COD-Module-Dependencies: net_rim_cldc,net_rim_os
RIM-MIDlet-Flags-1: 0
RIM-COD-Module-Name: MyClientApp
RIM-COD-Size: 88616
RIM-COD-Creation-Time: 1089855050
RIM-MIDlet-Position-1: 0
RIM-COD-URL: MyClientApp.cod
RIM-MIDlet-NameResourceId-1: 0
RIM-COD-SHA1: 89 bd de fe 1d 07 3a 0d 1a 15 23 ea 94 57 c5 fa 0f 2f 1f fe
RIM-MIDlet-NameResourceBundle-1:             

***Note that BlackBerry JDE and related build tools are only targeted at the Microsoft Windows NT, 2000 and XP environments.

Using Apache Ant for Blackberry Builds

There are plenty of great introductions to Ant, so here we will briefly cover the main concepts. Please refer to the resources section for a list of Ant resources.

Apache Ant is a build tool written in Java. An Ant script is an XML file that defines interdependent build tasks for a project such as "clean directories", "java compile", and "JAR classes". For our Ant scripts we leverage Antenna as much as possible. Antenna is a set of Ant tasks for building wireless Java applications targeted at MIDP; this simplifies many Ant script tasks which otherwise we would have to write ourselves.

Structuring the Project

A proper directory structure for your project will help you maintain your project's files neatly organized. Figure 3 illustrates a project organization that I have found useful; this directory structure is used by the finished Ant script I'll present below:

Figure 3. Our Project Directory Structure

The project's root directory contains the build.xml file as well as other support files such as our JAD and MANIFEST template files - we use these templates to generate our final (properly) populated JAD and MANIFEST files. The rest of our directories are for our compiled classes, build output, the source code, resource files, and support libraries.

The Ant Script for BlackBerry

Our Ant script was written following the Makefile in Listing 1. Our script provides build tasks to clean directories, and build our application. Our Ant script consist of the following major tasks:

Separating the build into these steps allows us to easily create both a JAD/JAR and COD files. Note how the common build tasks generate a MANIFEST, JAD, and JAR files, and how the generated JAD and JAR files are used as input into the BlackBerry-specific build tasks.

Figure 4. Ant Script Build Tasks

Listing 3 shows the finished Ant script:

Listing 3. The Ant Script

<?xml version="1.0"?>

<project name="MyClientApp" default="build" basedir=".">

<property name="ver" value="1.0"/> <property name="codename" value="MyClientApp"/>

<property name="midp_lib" location="${j2mewtk.home}/lib/midpapi.zip"/>

<property name="build.jars" location="lib/thirdparty"/> <property name="bbjdebuild.jars" location="${build.jars}/jde3.7"/> <property name="net_rim_api.jar" value="${bbjdebuild.jars}/net_rim_api.jar"/>

<property name="src" location="src"/> <property name="resources" location="res"/> <property name="lib" location="lib"/>

<property name="unpreverified.classes" value="classes/unpreverified"/> <property name="obfuscated.classes" value="classes/obfuscated"/> <property name="final.classes" value="classes/final"/>

<property name="name" value="${codename}"/> <property name="jad.template" value="worktrack.jad.template"/> <property name="jadfile" value="output/tojar/${name}.jad"/> <property name="jarfile" value="output/tojar/${name}.jar"/>

<property name="manifest.template" value="manifest.template"/> <property name="manifestfile" value="MANIFEST.MF"/>

<property name="temp.jar" value="output/tojar/${name}_t.jar"/> <property name="obfuscated.jar" value="output/tojar/${name}_t_o.jar"/> <property name="preverified.jar" value="output/tojar/${name}_p.jar"/> <property name="final.jar" value="output/tojar/${name}.jar"/>

<property name="wtk.home" value="${j2mewtk.home}"/> <property name="antenna.jar" value="antenna-bin-0.9.12.jar"/> <taskdef name="wtkbuild" classname="de.pleumann.antenna.WtkBuild" classpath="${build.jars}/${antenna.jar}"/>

<taskdef name="wtkpreverify" classname="de.pleumann.antenna.WtkPreverify" classpath="${build.jars}/${antenna.jar}"/>

<taskdef name="wtkpackage" classname="de.pleumann.antenna.WtkPackage" classpath="${build.jars}/${antenna.jar}"/>

<target name="init" depends="clean"> <mkdir dir="classes"/> <mkdir dir="${unpreverified.classes}"/> <mkdir dir="${obfuscated.classes}"/> <mkdir dir="${final.classes}"/> <mkdir dir="output"/> <mkdir dir="output/tojar"/> <mkdir dir="output/tocod"/> </target>

<target name="clean"> <delete file="${name}.jad"/> <delete file="${name}.jar"/> <delete file="${codename}.cod"/> <delete file="${codename}.lst"/> <delete file="${codename}.debug"/> <delete file="${codename}.csl"/> <delete file="${codename}.cso"/> <delete dir="classes"/> <delete dir="output"/> </target> <!-- Preverify the compiled code --> <target name="javacompile"> <wtkbuild srcdir="${src}" destdir="${unpreverified.classes}" bootclasspath="${net_rim_api.jar}"/> </target>

<!-- Preverify the compiled code --> <target name="preverify" depends="javacompile"> <wtkpreverify srcdir="${unpreverified.classes}" destdir="${final.classes}" classpath="${net_rim_api.jar}"/> </target>

<!-- Version the JAD and MANIFEST Files --> <target name="version" depends="preverify"> <!-- Version the MANIFEST --> <filter token="buildVer" value="${ver}" /> <filter token="midletName" value="${name}" /> <copy file="${manifest.template}" tofile="${manifestfile}" filtering="true" overwrite="true" />

<!-- Version the JAD file --> <filter token="buildVer" value="${ver}" /> <filter token="midletName" value="${name}" /> <filter token="jarName" value="${name}.jar" /> <copy file="${jad.template}" tofile="${jadfile}" filtering="true" overwrite="true" /> </target>

<!-- Package (JAR) the compiled classes. This also modifies the JAD file with JAR size information --> <target name="package" depends="version"> <delete dir="${final.classes}/META-INF" /> <wtkpackage jarfile="${final.jar}" jadfile="${jadfile}"> <fileset dir="${final.classes}"/> <fileset dir="${resources}"/> </wtkpackage> </target>

<!-- Invoke the RAPC compiler. This step is based the RAPC's usage: rapc.exe import=RIM_APIs codename=Codename JAD-File JAR-File --> <target name="rapc" depends="package" description="RIM COD Compiler"> <exec dir="." executable="${bbjdebuild.jars}/rapc.exe"> <arg line=" import=${net_rim_api.jar} "/> <arg line=" codename=${codename} "/> <arg line=" ${jadfile} "/> <arg line=" ${jarfile} "/> </exec> </target>

<!-- Once the COD file has been generated, move generated file to output directory --> <target name="build" depends="rapc"> <move file="${codename}.cod" tofile="output/tocod/${codename}.cod"/> <move file="${codename}.debug" tofile="output/tocod/${codename}.debug"/> <move file="${codename}.cso" tofile="output/tocod/${codename}.cso"/> <copy file="${codename}.alx" tofile="output/tocod/${codename}.alx"/> <copy file="${jadfile}" tofile="output/tocod/${codename}.jad"/> </target>

</project>

If you look at the rapc Ant target task in Listing 3, you will see it was written based on the RAPC compiler usage format. But please note that starting with Antenna version 0.9.13, support for RAPC compilation (contributed by me) is now available. To use the new RACP Ant support first download the latest version of Antenna, then add to your build.xml script the following task definition, similarly to how we defined the rest of the Antenna Ant tasks:

<taskdef name="wtkrapc" classname="de.pleumann.antenna.WtkRapc" classpath="${build.jars}/${antenna.jar}"/>

The following snippet shows how to use the new Antenna RACP task (feel free to replace the racp target in Listing 3 with the following code snippet). For more information please refer to the Antenna Javadoc:

<target name="rapc" description="RIM COD Compiler" depends="package">
    <wtkrapc
    	quiet="true"      	
    	midlet="false" 
    	jadfile="${jadfile}" 
    	source="${jarfile}" 
    	codename="${codename}" 
     	import="${bb.api.jar}" 
    	destdir="output/tocod/"/>
</target>

If you look at the version Ant target task, you will notice that it preprocesses the JAD and MANIFEST files, adding version information. Listings 4 and 5 show the template files, and their final state after versioning and packaging.

Listing 4a. Original JAD Template File

MIDlet-Name: @midletName@
MIDlet-Version: @buildVer@
MIDlet-Vendor: J2MEDeveloper
MIDlet-Description: 
MicroEdition-Profile: MIDP-1.0
MicroEdition-Configuration: CLDC-1.0
MIDlet-Jar-URL: @jarName@
MIDlet-Jar-Size: @jarSize@
MIDlet-1: ,,

Listing 4b. Final JAD File - Versioned and with BlackBerry-specific Information

Manifest-Version: 1.0
MIDlet-Jar-Size: 160220
MIDlet-1: ,,
MIDlet-Jar-URL: MyAppClient.jar
MicroEdition-Configuration: CLDC-1.0
MIDlet-Version: 1.0
MIDlet-Name: MyAppClient

MIDlet-Description: MIDlet-Vendor: J2MEDeveloper MicroEdition-Profile: MIDP-1.0 RIM-COD-Module-Name: MyAppClient RIM-COD-Module-Dependencies: net_rim_cldc,net_rim_os RIM-COD-Creation-Time: 1092667276 RIM-COD-URL: MyAppClient.cod RIM-COD-SHA1: a1 82 6f e6 1a 62 80 b8 8b 63 6c 54 69 11 0b 4b 63 78 05 84 RIM-COD-Size: 92928

Listing 5a. Original MANIFEST Template File

MIDlet-Name: @midletName@
MIDlet-Version: @buildVer@
MIDlet-Vendor: J2MEDeveloper
MIDlet-Description:
MicroEdition-Configuration: CLDC-1.0
MicroEdition-Profile: MIDP-1.0
MIDlet-1: , ,

Listing 5b. Final Versioned MANIFEST File

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.6.1
Created-By: 1.4.2-b28 (Sun Microsystems Inc.)
MIDlet-Name: MyAppClient
MIDlet-Version: 1.0
MIDlet-Vendor: J2MEDeveloper
MIDlet-Description: 
MicroEdition-Configuration: CLDC-1.0
MicroEdition-Profile: MIDP-1.0
MIDlet-1: , ,

Running Our Application from Within Ant

Running our application in the simulator requires us to first copy the generated files into the simulator directory, then invoke the appropriate simulator with the appropriate arguments. For this we will add two more steps to our Ant script:

  1. Update the BlackBerry simulator file system, and
  2. Run our application in the simulator.

The simulator to invoke will depend on which simulators you have installed on your computer. To write our run build task for a particular handset the easiest thing to do is to open the appropriate batch file for the simulator for the handset of interest (found in the simulator directory), and just transfer the input arguments into the Ant task. For example, for the the 7500 handset we would open the OS7500.bat batch file. We will see that the batch file invokes the osloader.exe passing the os7500.dll as one of its argument. The usage of the osloader.exe command is a follows:

    osloader.exe Os7500.dll /wi /app:DisableRegistration /rsim=0x20000001 /F16384 /H1119264 /GRES=240x160x16 /rport=19780 /rport=8205 jvm.dll

If you look at Listing 6 below, you will see how our run Ant task mirrors the line above:

Listing 6. Ant Tasks to Run Your Application

<target name="updatesim" description="Update BlackBerry Simulator">
   <copy todir="${blackberry.simulator.path}/">
        <fileset dir="output/tocod"/>
   </copy>
</target>

<!-- The following same arguments were in the OS7500.bat file: osloader.exe Os7500.dll /wi /app:DisableRegistration /rsim=0x20000001 /F16384 /H1119264 /GRES=240x160x16 /rport=19780 /rport=8205 jvm.dll  --> <target name="run" description="Run">    <exec dir="${blackberry.simulator.path}" executable="${blackberry.simulator.path}/osloader.exe">        <arg line=" Os7500.dll /wi " />        <arg line=" /wi " />        <arg line=" /app:DisableRegistration " />        <arg line=" /rsim=0x20000001 " />        <arg line=" /F16384 " />        <arg line=" /H1119264 " />        <arg line=" /GRES=240x160x16 " />        <arg line=" /rport=19780 " />        <arg line=" /rport=8205 " />        <arg line=" jvm.dll " />    </exec> </target>

In Summary

In this article we have covered the JDE's build capabilities. We also covered Ant, its benefits, and how to use if for your BlackBerry build process. Ant is a very powerful build tool, and with this article you should now have enough information to support Ant for all your BlackBerry builds, build your application from IDEs such as IDEA, Eclipse and Netbeans, and integrate your BlackBerry build into your overall build process.

Resources

C. Enrique Ortiz is a software architect and developer, and a mobile/wireless technologist and writer. He is author or co-author of many publications, a co-designer of Sun Microsystems' the Mobile Java Developer Certification Exam, and has been an active participant in the wireless Java community and of various J2ME expert groups.

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.