J2ME Development on OS X, revisited
January 17th, 2008 by SamUPDATE: SINCE THIS POST WAS WRITTEN SUN HAVE RELEASED Java Platform Micro Edition Software Development Kit 3.0 for Mac OS. PLEASE USE IT INSTEAD OF THESE INSTRUCTIONS IF YOU HAVE AN INTEL APPLE.
Some time ago, I posted a tutorial for setting up a J2ME development environment on OS X. Since then, EclipseME has not been addressing any of the bugs that made it a pain to use and I have also moved on to NetBeans 6.0. In this post I will revisit how to set up a cross-platform J2ME development environment using Ant and Antenna to handle all the difficult pieces of the build process, but allowing your preferred IDE to perform pure-Java debugging through the use of the excellent MicroEmu “WTK”.
Glossary
I’ll assume that you are familiar with standard Java desktop (J2SE) development. But you might not be familiar with a few terms used specifically in the Java mobile domain (J2ME)
- J2ME is ambiguous… the kind of J2ME we are talking about is CLDC/MIDP which means mobile phones. CDC are the higher end devices such as DVD players. Only I have never actually seen any CDC devices.
- CLDC/MIDP/CDC are verbose names for the system class libraries on the device… instead of J2SE’s classes you get a ridiculously small subset plus some custom classes for persistence and user input.
- JSR is an official extension library to Java. Many of the recent JSRs have been J2ME-specific and include support for things such as location awareness, bluetooth, camera-phones and text messaging.
- MIDlet is the technical name of a J2ME application. There can be more than one MIDlet in a jar file.
- JAD is the Java Application Descriptor file that is associated to a jar file, it’s like a manifest file but contains additional information such as digital signatures, security permission requests, where to get the jar file and how big it is. It is not necessary on all phones, but you won’t be able to sign your jars without one.
- WTK is a Wireless ToolKit. Development side, a WTK provides a device emulator for running your MIDlets with step debugging, system libraries and provides several additional tools.
- Preverification. For various technical reasons, J2ME devices cannot run a jar file that has been compiled by a Java compiler… but they almost can. The final step is to preverify the jar file and do some computations on class validity that are expensive at runtime, so that your phone doesn’t have to do it. Unfortunately SUN did not have the foresight to release a Java preverifier, and is therefore the primary restriction for cross-platform J2ME development. (for example, there is no PPC Linux preverifier)
- Obfuscation. Which involves renaming all your class and variable names in the final jar… this results in a much smaller file.
Dependencies
I’ll assume you have a JDK, Ant and an IDE. You’ll need to download quite a few additional packages
- Antenna to add a lot more functionality to Ant. This is optional if you intend to use NetBeans, in which case you can get by with installing the Mobility plugin. If you use Eclipse, you should get this… EclipseME is only maintained by one guy, part time, and it shows.
- MicroEmu, get the 2.0.2 snapshot at least. This will provide you with a pure Java emulator allowing you to do step debugging in NetBeans and Eclipse. If you are on Windows/Linux, feel free to grab a few other development kits!
- SUN WTK This is SUN’s non-portable Wireless ToolKit (WTK). We are only going to extract the device system libraries. I honestly cannot believe SUN for releasing a C-based emulator. OK, so a JVM running a mini-JVM does sound a bit incestuous, but performance isn’t the priority.
- PhoneME (get the MR2 source at least). This is the open source complement of SUN’s non-portable Wireless ToolKit (WTK). We only want the preverifier binary.
- Bluecove for bluetooth support on OS X and Windows. Linux users go to Avetanna.
- ProGuard for code obfuscation and more importantly, making the jar as small as possible.
- BluetoothDeploy optionally, my little bluetooth deployer application which will automate the delivery of your MIDlet to your mobile device.
The initial setup of all this middleware is a little tricky. You must create a folder named “bin” and another called “lib”. In the “bin” folder, you must place the preverify binary that is appropriate to your system from the PhoneME project. On OS X, this can be found in the phoneme_feature/cldc/build/share/bin/darwin_powerpc/ folder of the MR2 source download. In the lib folder you must place all the jar files from the WTK2.5.2/lib folder of the SUN WTK. I also place all the Javadocs from SUN’s WTK in there too, but you’ll find that they aren’t all available and those that are are useless you will have to go looking for them elsewhere. I found that the Sony WTK and Nokia developer pages tend to have more complete Javadocs. Checking out the JCP is mostly useless as everything tends to be in PDF.
Setting up in your IDE
In your IDE (except NetBeans), set up a Java project as normal with compiler compliance set to 1.3 (no generics in J2ME I’m afraid!). Instead of adding a system library… add the midpapi20.jar and cldcapi11.jar from the lib folder we just created. This means you will now have access to the MIDP-2.0 and CLDC 1.1 APIs which are the most common system libraries on modern handsets. You might want to spend a while getting acquainted with what is (and isn’t!) a part of those APIs by following the links. You can then add additional JSRs such as the JSR-82, the Bluetooth API… note that JSRs are device-dependent. You might want to check out a database like Polish to see if your target devices have the JSRs you want to use.
When you actually want to run your MIDlet in pure Java-land, you must use a different classpath. On the runtime classpath, add the MicroEmu and Bluecove jars. Run the org.microemu.app.Main class with your MIDlet’s full classname as a parameter. This will give you step debugging in Eclipse.
If you are using NetBeans 6.0, then install the Mobility plugin and setup a custom J2ME System Library by selecting the directory where you created the “bin” and “lib” folders. The emulator binary does not exist in our setup, so change it to run the MicroEmu application, with the appropriate classpath. The support offered by this plugin means you might not even need to edit any Ant scripts.
Hello World
There are loads and loads of tutorials out there on starting the actual work of writing a MIDlet. For now, I’ll give you the basic “Hello World”, and suggest that you just dig into the CLDC/MIDP Javadocs and Google for appropriate tutorials.
There is no main method in J2ME. You define your entrance classes in the JAD file, which must extend the javax.microedition.midlet.MIDlet abstract class. The methods startApp, pauseApp and destroyApp define a MIDlet’s life cycle and you must try your best to ensure that pauseApp releases as many resources as possible back to the system and that startApp can handle both a cold start and recover from a pause. I won’t address these issues in this little example, but be ware of them.
There is no Swing or AWT in J2ME, instead you add javax.microedition.lcdui.Items (such as text, images, etc) onto a javax.microedition.lcdui.Displayable. Or draw on the javax.microedition.lcdui.Canvas directly. Game developers will want to go straight to the javax.microedition.lcdui.game.GameCanvas
User input is handled through setting up an implementation of javax.microedition.lcdui.CommandListener to listen to javax.microedition.lcdui.Commands.
So, “Hello World” looks something like
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class HelloWorld extends MIDlet implements CommandListener {
private final Command exitCommand;
private final Form form;
public HelloWorld() {
exitCommand = new Command("Exit", Command.EXIT, 1);
form = new Form("Hello World!");
form.append("from JavaBlog.co.uk");
form.addCommand(exitCommand);
form.setCommandListener(this);
}
protected void startApp() {
Display.getDisplay(this).setCurrent(form);
}
protected void pauseApp() {}
protected void destroyApp(boolean force) {}
public void commandAction(Command cmd, Displayable disp) {
if (cmd == exitCommand) {
destroyApp(false);
notifyDestroyed();
}
}
}
As a first exercise… try adding a javax.microedition.lcdui.TextBox and handling the life cycle of a pause-unpause.
Antenna
Setting up an Ant build script may sound a little scary if you’ve never used it before. However, it’s not that bad. First define some properties that will be useful (you’ll need to edit the paths to suit your setup, note that “wtk” is where we created the “bin” and “lib” folders earlier)
<taskdef resource="antenna.properties" classpath="../middleware/antenna/antenna-bin-1.0.0.jar" />
<property name="wtk.proguard.home" value="../middleware/proguard/proguard4.1/" />
<property name="wtk.home" value="../middleware/wtk/" />
<property name="jsr82.jar" value="../middleware/bluecove/bluecove-2.0.2.jar" />
<property name="btdeploy.jar" value="../middleware/bluetoothdeploy/bluetoothdeploy.jar" />
<property name="microemu.jar" value="../middleware/microemu/microemulator-2.0.2-SNAPSHOT.jar" />
<property name="wtk.midp.version" value="2.0" />
<property name="wtk.cldc.version" value="1.1" />
<property name="wtk.bluetooth.enabled" value="true" />
There are lots of other properties that Antenna recognises for setting up the device profile. I suggest you have a browse of them on the Antenna properties list. You now have access to lots of new Ant tasks for building, preverification, creating the JAD file (it’s like an external manifest file, but more of a pain) and digital signing (if you have paid for a certificate).
Typically, you’ll want to create a target that looks something like this
<target name="build">
<wtkjad version="0.0.1" name="MyApp" vendor="Me!" jadfile="myapp.jad" jarfile="myapp.jar">
<!-- typically 3 MIDlets are supported by devices -->
<midlet name="Test Suite" class="my.package.MyAppTests" />
<midlet name="My Application" class="my.package.MyApp" />
</wtkjad>
<mkdir dir="build/classes" />
<wtkbuild srcdir="src" destdir="build/classes" preverify="false" />
<wtkpackage obfuscate="false" preverify="false" jadfile="myapp.jad" jarfile="myapp.jar">
<fileset dir="build/classes" />
<fileset dir="res" />
</wtkpackage>
<wtkobfuscate jadfile="myapp.jad" jarfile="myapp.jar" />
<wtkpreverify jadfile="myapp.jad" jarfile="myapp.jar" />
</target>
and that’s it! Running ant build will now build your MIDlet and create a jar and jad file that you can send to you phone. Well, almost… there is a bug with the wtkpreverify line, and I have to type this instead
<mkdir dir="build/tmp" />
<exec executable="${wtk.home}/bin/preverify">
<arg line="-classpath ${wtk.home}/lib/cldcapi11.jar:${wtk.home}/lib/midpapi20.jar:${wtk.home}/lib/jsr082.jar" />
<arg line="-d build/tmp" />
<arg line="${tests-jarfile}" />
</exec>
<move file="build/tmp/${tests-jarfile}" tofile="myapp.jar" />
<delete dir="build/tmp" />
<wtkjad update="true" jadfile="myapp.jad" jarfile="myapp.jar" />
which is a bit ugly. If you use digital signing, then you can use a line like this to do all that
<wtksign keystore=".keystore" jadfile="myapp.jad" jarfile="myapp.jar"
storepass="${keystore.pass}" certpass="${cert.pass}" certalias="${cert.alias}" />
I’ll leave you to work out the details… setting up a certificate can be a real pain in the butt. Read David Hayes’ excellent tutorial on getting the keys set up.
If you want to be really fancy, you can create a deploy target which will send the MIDlet to your handset with
<target name="deploy" depends="build">
<java fork="yes" classname="thinktank.j2me.j2se.BluetoothDeploy" classpath="${btdeploy.jar}:${jsr82.jar}">
<arg line="INSERT YOUR HARDWARE ADDRESS HERE" />
<arg line="myapp.jad" />
<arg line="myapp.jad" />
</java>
</target>
see my previous post for more details.
Future developments
The future looks bright for better cross-platform support, as the ProGuard developers are working on a pure-Java preverifier, although it is pretty buggy at the moment. MicroEmu will then be able to bundle such a preverifier and change their naming conventions of JSR stubs to conform with the SUN WTK, making your IDE think it is the SUN WTK. It would also be good if MicroEmu came with a bin/emulator script that spoke with the Java debugger… it would make IDE setup even easier.
But really, the Mobile Java future has got to be either Android or JavaFX! Both are better than CLDC/MIDP J2ME, so it’s really up to the handset manufacturers to decide. Personally, I prefer Android because it will allow me to edit the firmware and have a truly open source Mobile OS.
Dan wrote:
January 23rd, 2008 at 6:35 am