In last months article, J2ME and MIDP Development, we covered the basics of Java 2 Micro Edition (J2ME) and the Mobile Information Device Profile (MIDP). We touched upon installation, configuring the environment, writing a simple MIDlet, as well as compiling, pre-verifying class files, and running a MIDlet on a mobile device emulator.
This article takes the next logical step: packaging MIDlets. It includes an introduction to the MIDlet Suite, including Java archive and application descriptor files. To put all this into practice, we'll write two short MIDlets and create a JAR and JAD to package these programs. We also look at how using Java packages changes our development process slightly. And, finally, interweaved with the development of the MIDlets in this article, you'll learn how to access MIDlets from a web server.
Although it's not a requirement to place MIDlets inside a Java Archive (JAR) file, this will be the most common means of distributing J2ME/MIDP applications. The MIDlet Suite is the name given to the entire collection of all files and resources that may be required as part of a MIDlet. The MIDlet Suite consists of
The application manager is a software program on the mobile device. This application is device dependent and implemented by the manufacturer of the device. It's responsible for installing, running, and removing MIDlets from the device. It provides error-handling support. The application manager may also provide an optional interface to allow users to start, stop, and delete MIDlets.
A production, packaged application will generally consist of many files. In addition to Java classes, other files such as images and application data, known as resources, may be part of the package. You bundle all this information together into a single entity, a JAR file.
Note: Learning about JAR files
Visit Sun's Java Tutorial
online for more information about jar files:
In addition to class and resource files, a JAR contains a manifest
file which describes the contents of the JAR. The manifest has the
name manifest.mf and is stored in the JAR file
itself. The table below lists all available attributes that may be
defined within the manifest file.
| Table 1 | |
| Attribute | Purpose |
MIDlet-Name |
Name of the MIDlet "package". For example, "Game Pack" |
MIDlet-Version |
Version number of the MIDlet |
MIDlet-Vendor |
Who created the MIDlet |
MIDlet-Icon |
Icon associated to show alongside the MIDlet-Name by the application manager. This is a graphics file stored as a PNG image. |
MIDlet-Description |
Text describing the MIDlet |
MIDlet-Info-URL |
URL that may have more information about the MIDlet and/or the vendor |
MIDlet-<n> |
This attribute contains up to three pieces of information: Inside our "Game Pack" example, we may have two entries: |
MIDlet-Jar-URL |
URL of the JAR file |
MIDlet-Jar-Size |
The JAR file size in bytes |
MIDlet-Data-Size |
The minimum number of bytes required for persistent data storage. |
MicroEdition-Profile |
What J2ME Profile is required by the MIDlet |
MicroEdition-Configuration |
What J2ME Configuration is required by the MIDlet. |
These attributes are not all required. However, without the following six, the application manager is required to refuse to load the JAR.
MIDlet-NameMIDlet-VersionMIDlet-VendorMIDlet-<n> for each MIDlet in the JAR fileMicroEdition-ProfileMicroEdition-Configuration
|
Here is an example of a simple manifest file:
MIDlet-Name: Rogue
MIDlet-Version: 1.0
MIDlet-Vendor: My Corporation Inc.
MIDlet-1: rogue, /images/rogue.png, rogue.rogueMIDlet
MicroEdition-Profile: MIDP-1.0
MicroEdition-Configuration: CLDC-1.0
Java Application Descriptor File
Although not required, you should typically include a JAD file along with the JAR. As with the manifest, this file contains information about a MIDlet. There are two reasons to create a JAD.
To provide information to the application manager about the contents of a JAR file. With this information, decisions can be made as to whether or not a MIDlet is suitable for running on the device.
As an example, by looking at the attribute MIDlet-Data-Size, the application manager can determine if the MIDlet requires more persistent memory than the device can provide.
To provide a means for parameters to be passed to a MIDlet without having to make changes to the JAR file. We'll see an example of this as we progress through the article.
The JAD files uses the same attributes as in Table 1. If you need
to create your own attributes, you can do that as well. As long as you
use attribute names that do not begin with MIDlet- you're
all set. An example of a custom attribute is shown below in the file
showProperties.jad.
As with the manifest, there are certain attributes that must be defined. If not available, the application manager will not load the MIDlet.
MIDlet-NameMIDlet-VersionMIDlet-VendorMIDlet-<n> for each MIDletMIDlet-Jar-URLMIDlet-Jar-SizeThe values of MIDlet-Name,
MIDlet-Version, and MIDlet-Vendor must be
identical to the value of the same attributes in the JAR's
manifest. As you might guess, if there is a difference in the files,
the application manager will not load the JAR.
If any other attributes names are duplicated in both files, and the values of those attributes are not the same, the application descriptor file (JAD) attributes will take precedence.
The 1.0 MIDP specification does not show the MIDlet-n attribute as one that is required in the JAD file. However, without this entry, I was not able to preview MIDlets in the device emulator. Including this attribute in both files is not a problem, and, actually, doing so may provide more clarity as to how these files are related. Thus, for completeness, all examples here will include the MIDlet-n attribute inside the JAD.
A very simple JAD file might look like
MIDlet-Name: Memo Pad
MIDlet-Version: 1.0
MIDlet-Vendor: My Corporation Inc.
MIDlet-Jar-URL: http://www.yourweb.com/MIDlets/memopad.jar
MIDlet-Jar-Size: 26248
MIDlet-1: MemoPad, /images/MemoPad.png, MemoPad.Main
Accessing JAR/JAD attributes from a MIDlet
A MIDlet can access all the attributes defined inside both the manifest file (which is part of a JAR) and those inside the JAD file. The complete package name to the method that will return information about the properties is
javax.microedition.midlet.MIDlet.getAppProperty(String name)
|
What follows is a short example to print various attributes from both those files.
manifest.mf is stored as part of
showProperties.jar:
MIDlet-Name: Show Properties MIDlet
MIDlet-Version: 1.0.1
MIDlet-Vendor: My Corporation Inc.
MIDlet-1: ShowProps, , showProperties
MicroEdition-Profile: MIDP-1.0
MicroEdition-Configuration: CLDC-1.0
MIDlet-Description: A simple property list example
MIDlet-Data-Size: 1500
Contents of showProperties.jad:
MIDlet-Name: Show Properties MIDlet
MIDlet-Version: 1.0.1
MIDlet-Vendor: My Corporation Inc.
MIDlet-Jar-URL: file://showProperties.jar
MIDlet-Jar-Size: 1132
MIDlet-1: ShowProps, , showProperties
JadFile-Version: 1.5
MIDlet-Data-Size: 500
Contents of showProperties.java:
import javax.microedition.midlet.*;
public class showProperties extends MIDlet
{
public void startApp() throws MIDletStateChangeException
{
System.out.println("Vendor: " + getAppProperty("MIDlet-Vendor"));
System.out.println("Description: " + getAppProperty("MIDlet-Description"));
System.out.println("JadFile Version: " + getAppProperty("JadFile-Version"));
System.out.println("MIDlet-Data-Size: " + getAppProperty("MIDlet-Data-Size"));
}
public void pauseApp()
{ }
public void destroyApp(boolean unconditional)
{ }
}
|
Here are a few important points:
manifest.mf is stored as part of the JAR
file showProperties.jarshowProperties.jar is referenced from the JAD file
showProperties.jad with the line,
MIDlet-Jar-URL: file://showProperties.jar MIDlet-Name,
MIDlet-Version and MIDlet-Vendor are in both
the manifest file in the JAR and the JAD file. All the values are
required to be identical.MIDlet-Description is from the manifest
file and is optional.JadFile Version is not in Table 1 and,
thus, is a user-defined attribute. Because attributes inside a JAD
file are accessible from a MIDlet, you can add attributes to the JAD
without having to change the JAR file. Put another way, you can easily
change or add parameters to be passed to the MIDlet.MIDlet-Data-Size is in both the
manifest and the JAD file. As pointed out earlier, when there are
identical attributes in both files, entries in the JAD file will take
precedence. Thus, output in figure Figure 1 shows
MIDlet-Data-Size as 500, the value from the JAD
file. Keep in mind that this does not apply to
MIDlet-Name, MIDlet-Version, or
MIDlet-Vendor, which are required to be in both files and
must be identical.
|
Packaging Multiple MIDlets in the MIDlet Suite
Before we can talk about how to package more than one MIDlet, we'll need to have more than one MIDlet available. What follows is code for two simple MIDlets. The first displays a TextBox component with a short message.
Contents of MIDlet1.java:
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class MIDlet1 extends MIDlet implements CommandListener
{
private Display display; // Reference to Display object
private TextBox tbxMain; // A Textbox to display a message
private Command cmdExit; // A Command to exit the MIDlet
// The constructor
public MIDlet1()
{
display = Display.getDisplay(this);
cmdExit = new Command("Exit", Command.SCREEN, 1);
tbxMain = new TextBox("MIDlet 1", "Welcome", 50, 0);
tbxMain.addCommand(cmdExit);
tbxMain.setCommandListener(this);
}
// Called by application manager to start the MIDlet.
public void startApp()
{
display.setCurrent(tbxMain);
}
// A required method
public void pauseApp()
{ }
// A required method
public void destroyApp(boolean unconditional)
{ }
// Check to see if our Exit command was selected
public void commandAction(Command c, Displayable s)
{
if (c == cmdExit)
{
destroyApp(false);
notifyDestroyed();
}
}
}
Here is the second MIDlet; it shows a message on the display using
a List component (MIDlet2.java):
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class MIDlet2 extends MIDlet implements CommandListener
{
private Display display; // Reference to Display object
private List lstMain; // A List of items
private Command cmdExit; // A Command to exit the MIDlet
// The constructor
public MIDlet2()
{
display = Display.getDisplay(this);
cmdExit = new Command("Exit", Command.SCREEN, 1);
lstMain = new List("MIDlet 2", Choice.IMPLICIT);
lstMain.append("Welcome Back", null);
lstMain.addCommand(cmdExit);
lstMain.setCommandListener(this);
}
// Called by application manager to start the MIDlet.
public void startApp()
{
display.setCurrent(lstMain);
}
// A required method
public void pauseApp()
{ }
// A required method
public void destroyApp(boolean unconditional)
{ }
// Check to see if our Exit command was selected
public void commandAction(Command c, Displayable s)
{
if (c == cmdExit)
{
destroyApp(false);
notifyDestroyed();
}
}
}
Call the first MIDlet1.java. Call the second
MIDlet2.java. In the directory where you save the files,
run the following to compile and pre-verify the files.
javac -bootclasspath c:\j2me\midp-fcs\classes *.java
preverify -classpath c:\j2me\midp-fcs\classes;. -d . MIDlet1 MIDlet2
jar cvfm MIDlets.jar manifest.txt MIDlet1.class MIDlet2.class spin.png
* Note: the path
c:\j2me\midp-fcsmay vary depending on your installation
Create the JAR File
Create a new file called manifest.txt and then create
a file with the following contents:
MIDlet-Name: MIDlet Examples
MIDlet-Version: 1.0
MIDlet-Vendor: My Corporation Inc.
MIDlet-1: MIDlet1, /spin.png, MIDlet1
MIDlet-2: MIDlet2, /spin.png, MIDlet2
MicroEdition-Profile: MIDP-1.0
MicroEdition-Configuration: CLDC-1.0
Create a JAR file by running the following command:
jar cvfm MIDlets.jar manifest.txt MIDlet1.class MIDlet2.class spin.png
This will create a JAR file called MIDlets.jar that
contains the contents of the manifest.txt file and both
class files.
Note: The name of the manifest file inside the JAR will be
manifest.mf. The reference above tomanifest.txtinforms the JAR program to createmanifest.mfusing the contents of the filemanifest.txt
|
Create the JAD File
Create a new file called MIDlets.jad and create a file
with the following contents:
MIDlet-Name: MIDlet Examples
MIDlet-Version: 1.0
MIDlet-Vendor: My Corporation Inc.
MIDlet-Description: Two simple examples to show how to compile and run a MIDlet
MIDlet-Jar-URL: http://localhost/MIDlets.jar
MIDlet-Jar-Size: 2604
MIDlet-1: MIDlet1, /spin.png, MIDlet1
MIDlet-2: MIDlet2, /spin.png, MIDlet2
Notice the reference to both the MIDlets:
MIDlet-1: MIDlet1, /spin.png, MIDlet1
MIDlet-2: MIDlet2, /spin.png, MIDlet2
Each line above contains the name of the MIDlet to display on the
device (MIDlet1 and MIDlet2); an (optional)
image file that the application manager will show on the display next
to the MIDlet name; and the class file to load to start the MIDlet
(MIDlet1 and MIDlet2).
You can run a MIDlet from either a local file system or a web server.
From the File System
Type the following at the command prompt to preview your MIDlet:
midp -transient file://MIDlets.jad
The -transient option notifies the emulator you want
to run a descriptor file found at a specified url. In this case:
file://MIDlets.jad, which looks for
MIDlets.jad in the current directory. You could also give
a full path to the JAD file if necessary. For example, the full path
to my JAD file is
file://OnJava/MIDlets/welcome.jad
You should see output similar to figures below, showing the main
screen of the application manager and the output of
MIDlet1 and MIDlet2.
|
From a Web server
You can also run MIDlets from a web server. After uploading the JAR and JAD file, access the JAD file by changing the url:
midp -transient http://localhost/MIDlets.jad
This accesses MIDlets.jad file on the web server
running on my computer. If you upload your files to a web server on
the Internet, simply change the reference to the appropriate domain name:
midp -transient http://www.yourwebserver.com/path/MIDlets.jad
Follow along with the steps below to create one last MIDlet.
MIDletPackage, which I created as a subdirectory of f:\onjava./resources. All class files created by the Java compiler
will be in /jclasses. The pre-verified classes will be
written in /pclasses. Here's the directory structure on
my system:
f:\onjava
|
MIDletPackage => Java source code and manifest.txt file
|
jclasses => Output from the Java compiler
pclasses => Output from pre-verifier
resources => Resource files (images, etc)
MIDLet1.java and MIDlet2.java) into the
MIDletPackage directory, and add the package statement
shown below to the top of each file. Also, if you have an image file
you've been using, copy that file into the resources directory.package simpleMIDlets;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class MIDlet1 extends MIDlet implements CommandListener
{
...
}package simpleMIDlets;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class MIDlet2 extends MIDlet implements CommandListener
{
...
}
manifest.txt and the JAD file to reference the new location of the images and the class files.MIDlet-Name: MIDlet Examples
MIDlet-Version: 1.0
MIDlet-Vendor: My Corporation Inc.
MIDlet-1: MIDlet1, /resources/spin.png, simpleMIDlets.MIDlet1
MIDlet-2: MIDlet2, /resources/spin.png, simpleMIDlets.MIDlet2
MicroEdition-Configuration: CLDC-1.0
MicroEdition-Profile: MIDP-1.0MIDlet-Name: MIDlet Examples
MIDlet-Version: 1.0
MIDlet-Vendor: My Corporation Inc.
MIDlet-Description: Packaging multiple MIDlets
MIDlet-Jar-URL: http://localhost/MIDlets.jar
MIDlet-Jar-Size: 2884
MIDlet-1: MIDlet1, /resources/spin.png, simpleMIDlets.MIDlet1
MIDlet-2: MIDlet2, /resources/spin.png, simpleMIDlets.MIDlet2MIDlet-1 and MIDlet-2. The class files are now referenced using the package name simpleMIDlets.MIDlet1 and simpleMIDlets.MIDlet2.javac -bootclasspath c:\j2me\midp-fcs\classes -d jclasses *.java
The -d option tells the compiler to write the classes files into the directory jclassesc:\j2me\midp-fcs may vary depending on your installation"-d" option tells the compiler to write the classes files into the directory jclassespreverify -classpath c:\j2me\midp-fcs\classes; -d pclasses jclasses-d option tells the pre-verifier to store the pre-verified classes in the directory pclasses. The last entry -- jclasses -- tells the preverify where to look for classes to pre-verify.c:\j2me\midp-fcs may vary depending on your installationjar cvfm MIDlets.jar manifest.txt -C pclasses . resourcesMIDlets.jar, using the file manifest.txt as the contents of the manifest file (a file called manifest.mf will be stored in the JAR).-C pclasses . tells the jar program to change to the pclasses directory and archive all (".") the filesresources informs the jar program to add all the files located in the directory named resourcesMIDlets.jad -- Application descriptor fileMIDlets.jar -- JAR file containing the MIDlets, a manifest and the image filesmidp -transient file://MIDlets.jad
From a web server: Upload the JAR and JAD files to a web server. Enter the following to view the MIDlets:
midp -transient http://localhost/MIDlets.jad
Change the path as in the previous example to reference the MIDlets on a different web server.With our new hierarchy, we can now quickly determine the contents of each directory; that is, the location of the source code, Java classes files, pre-verified class file, and resources.
|
F:\onjava
|
MIDletPackage => Java source code and manifest.txt file
|
jclasses => Output from the Java compiler
pclasses => Output from pre-verifier
resources => Images (and other resource files)
The directory simpleMIDlets (below
jclasses and pclasses) was created by the Java compiler
and the pre-verifier, respectively. Because we added the statement
package simpleMIDlets to our source files, each program
created the directory matching the package name and placed its output
in that directory. That is, the Java compiler class files are written
to
F:\onjava\MIDletPackage\jclasses\simpleMIDlets
The pre-verified classes file are written to:
F:\onjava\MIDletPackage\pclasses\simpleMIDlets
In the previous and current articles we've covered all the basics of MIDlet development. You should have all the necessary software installed and configured, and you should be comfortable with the complete development cycle.
We've also shown how you can use a JAR and JAD file to package one or more MIDlets. Finally, we've shown that running a MIDlet on the cellular phone emulator varies little, regardless of where the MIDlet reside, on a local file system or a web server.
You can download the source code for this article from the Core J2ME site.
John W. Muchow is an expert Java Developer and Trainer specializing in J2ME.
Return to ONJava.com.
Copyright © 2007 O'Reilly Media, Inc.