In this two part series I’m going to try my best to describe how I use Apache Ant and Eclipse to write/debug software for the BlackBerry platform.
Requirements
- BlackBerry JDE 4.1+
- Ant 1.6.x+ (if not using eclipse, or your ide does not support ant)
- Eclipse 3.x (or your ide of choice)
- BlackBerry Ant Tools
Prepare your workspace
This isn’t necessary per-say but you owe it to yourself. First step is adding a user library for the blackberry api. Go to Window->Preferences and drill down, Java->Build Path->User Libraries.
Click New and enter “BlackBerry 4.2″ as the library name. Click Add JARs and find your rim api jar (JDE_HOME/lib/net_rim_api.jar). Also be sure to set the javadoc location (JDE_HOME/docs/api). This will give you documentation popups when you do code assist (ctrl+space) and meaningful variable names when using code generation (eg: abstract method stubs).
Setup ant classpath
We will be using a set of ant tasks to automate the build process of our application so download the latest version of BlackBerry Ant Tools and extract the zip somewhere. Where you put bb-ant-tools.jar is up to you but I prefer to put it in my ant lib directory (eclipse/plugins/org.apache.ant_1.6.5/lib). Go to Window->Preferences and drill down, Ant->Runtime. Click Add External JARs and find bb-ant-tools.jar.
That’s it! The workspace is good to go.
Hello, World!
Alright, now lets get to the soldering! I mean programming (sorry, wrong pass-time). Ever since the first cave man/woman programmer chiseled the first cave program on his/her cave wall it has been a “Hello, World!” program. I don’t know what happens to those who break this tradition and I don’t want to find out.
Create a new java project and call it whatever the hell you want, but keep in mind what I just said about “Hello, World!”. Select the option to create separate source and output folders and click next.
In the Libraries tab select the JRE System Library and click Remove. Click Add Library and select User Library and click next. Check the checkbox beside the library we created when preparing our workspace and click finish. Click finish to create the project.
Create the class ca.slashdev.HelloWorldApp:
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.container.MainScreen;
public class HelloWorldApp extends UiApplication {
public HelloWorldApp() {
MainScreen screen = new MainScreen();
screen.add( new LabelField( " Hello, World! " ));
pushScreen(screen);
}
public static void main(String[] args) {
new HelloWorldApp().enterEventDispatcher();
}
}
< taskdef resource ="bb-ant-defs.xml" />
<!-- rapc and sigtool require the jde.home property to be set -->
< property name ="jde.home" location ="/Users/josh/lib/JDE4.2" />
<!-- directory of simulator to copy files to -->
< property name ="simulator.home" location ="/Volumes/Java/JDE4.2/simulator" />
< property name ="src.dir" location ="src" />
< property name ="build.dir" location ="build" />
< property name ="cod.name" value ="ca_slashdev_HelloWorld" />
< target name ="build" >
< mkdir dir ="${build.dir}" />
< rapc output ="${cod.name}" srcdir ="${src.dir}" destdir ="${build.dir}" >
< jdp title ="Hello World" />
</ rapc >
</ target >
< target name ="sign" >
< sigtool codfile ="${build.dir}/${cod.name}.cod" />
</ target >
< target name ="clean" >
< delete dir ="${build.dir}" />
</ target >
< target name ="load-simulator" depends ="build" >
< copy todir ="${simulator.home}" >
< fileset dir ="${build.dir}" includes ="*.cod,*.cso,*.debug,*.jad,*.jar" />
</ copy >
</ target >
</ project >
Show the Ant view by clicking Window->Show View->Ant. Drag the build.xml file into this view. Now you can simply double-click on the targets to run them. This would be a good time to run the build target. No errors? Sweet! Run the load-simulator target to copy files into the simulator.
Debugging
JDE 4.1 and above comes with a tool called JDWP. Start JDWP from your JDE install. Now lets setup a remote debug configuration in eclipse. Click Run->Debug. Select the Remote Java Application category and click the new button. Enter a name for the configuration and select the project. Click Debug and the simulator should spring to life.
Set a breakpoint at the line where the screen gets pushed to the stack. In the simulator, launch the Hello World application and eclipse should switch to the debug perspective and execution should be suspended at your breakpoint.
Recap
So what have we covered? We’ve added the blackberry api as a user library, installed the blackberry ant tools project and wrote a simple but effective build script. How many applications have you written that are this simple? Probably not many. Lets now look at a more complex setup with dependencies.
Hello, World! with dependencies
If you’ve gotten this far I’m going to assume that I can short cut some of the details now.
Create a general project in the workspace called common. This directory will be shared by all of the projects. Each project will import it’s build script as well as some common properties.
Create a file called build.xml:
< taskdef resource ="bb-ant-defs.xml" />
< dirname property ="common.basedir" file ="${ant.file.common}" />
< property file ="${common.basedir}/common.properties" />
< property name ="src.dir" location ="src" />
< property name ="build.dir" location ="build" />
< target name ="build" depends ="deps" >
< mkdir dir ="${build.dir}" />
< rapc quiet ="true" output ="${cod.name}"
srcdir ="${src.dir}" destdir ="${build.dir}" >
< jdp file ="project.properties" />
< import >
< fileset dir ="${common.basedir}/.." includes ="${deps.list}/build/*.jar" />
</ import >
</ rapc >
</ target >
< target name ="deps" if ="deps.list" >
< subant >
< dirset dir ="${common.basedir}/.." includes ="${deps.list}" />
</ subant >
</ target >
< target name ="sign" >
< sigtool codfile ="${build.dir}/${cod.name}.cod" />
</ target >
< target name ="clean" >
< delete dir ="${build.dir}" />
</ target >
< target name ="load-simulator" depends ="build" >
< copy todir ="${simulator.dir}" >
< fileset dir ="${build.dir}" includes ="*.cod,*.csl,*.cso,*.debug,*.jar" />
</ copy >
</ target >
< target name ="load-device" depends ="sign" >
< exec executable ="${jde.home}/bin/JavaLoader.exe" >
< arg value ="-usb" />
< arg value ="load" />
< arg file ="${build.dir}/${cod.name}.cod" />
</ exec >
</ target >
</ project >
And create a file called common.properties:
jde.home=/Users/josh/lib/JDE4.2 simulator.home=/Volumes/Java/JDE4.2/simulator
Be sure to set these two properties to values appropriate for your setup. Hint: if you are using the simulator inside the JDE, set simulator.home=$(jde.home}/simulator.
Hello World dependency
Now lets create a library for our HelloWorld project to depend on. Create a new Java project and call it libHello and be sure to select the option to create separate source and output folders.
For the sake of demonstration, lets create a simple class with a string property that contains the infamous hello world message. Create the class called ca.slashdev.HelloWorld:
public class HelloWorld {
private String _message;
public HelloWorld() {
_message = " Hello, World! " ;
}
public String getMessage() {
return _message;
}
}
build.xml:
<
project
name
="libHello"
default
="build"
>
<
import
file
="../common/build.xml"
/>
<
property
name
="cod.name"
value
="ca_slashdev_libHello"
/>
</
project
>
project.properties:
title=Hello World Library type=library
Drag the build.xml file into the Ant view and run the build target. Ooooh, ahhhh. Now wasn’t that easy? Our common build script does all the work, we just give it some properties to work with. The project.properties file contains everything you would normally specify in the project settings dialog in the RIM JDE. Check out the documentation from the blackberry ant tools project for a full list of values that can be specified.
Retrofit Hello World application
Right click the HelloWorld project in the workspace and click properties. Go to the projects tab and add libHello project to the build path.
Replace the contents of the build.xml file in HelloWorld with this:
< import file ="../common/build.xml" />
< property name ="cod.name" value ="ca_slashdev_HelloWorld" />
< property name ="deps.list" value ="libHello" />
</ project >
Create the project.properties file:
title=Hello World type=cldc
Change the ca.slashdev.HelloWorldApp class to use the ca.slashdev.HelloWorld class in libHello:
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.container.MainScreen;
public class HelloWorldApp extends UiApplication {
public HelloWorldApp() {
HelloWorld hello = new HelloWorld();
MainScreen screen = new MainScreen();
screen.add( new LabelField(hello.getMessage()));
pushScreen(screen);
}
public static void main(String[] args) {
new HelloWorldApp().enterEventDispatcher();
}
}
Final thoughts
We did it. We compiled, compiled with dependencies, and debugged a blackberry application all without using RIM’s IDE. Compiling is provided by the rapc ant task from the blackberry ant tools project, and no need for .jdp or .jdw files anymore since all module settings are inside standard properties files. Furthermore, I’d like to point out that both examples in this guide can be just as easily built outside of Eclipse. This is an important distinction because I firmly believe that a developer should be free to use whatever tools they are most comfortable with. If that happens to be a standard text editor, and the command line so be it.
The acute observer will notice that all of my screen captures are from Mac OS X. I should point out that the rapc compiler works just fine under OS X and Linux (using blackberry ant tools project). However, I am unaware of any way to run the simulator, sign cod files, or use javaloader natively on these operating systems. Virtualization software such as Parallels provide a less than ideal solution where by you can run your simulator session inside of a virtual machine. This tends to be slow, but works in a pinch. Such is a topic for another post.