Auto-update of Midlets
Join the DZone community and get the full member experience.
Join For FreeAny professional application should be capable of updating itself
over the internet. Even Midlets! The idea is fairly easy in that the
Midlet needs to make a call to the server to check what version the
latest software has, and compare that to the installed version. If
there is a newer version available, then it needs to start the (mobile)
device's browser and point it at the URL of the new JAD file. The
device will take care of the download and installation after that. So,
the following article shows you exactly how this can be implemented.
First off, refer to the previous article, which described a framework for making server calls.
The sequence diagram looks like this:
Based on the framework, the following JSP can be installed serverside, which reads the version number out of the JAD file:
<%@page import="java.io.FileInputStream"%> <%@page import="java.io.RandomAccessFile"%> <%@page import="java.io.File"%> <%@page import="java.util.List"%> <html> <body> <% RandomAccessFile raf = null; try{ String version = null; String path = request.getSession().getServletContext().getRealPath("index.jsp"); File f = new File(path); f = f.getParentFile(); f = new File(f, "jads/nameOfJad.jad"); raf = new RandomAccessFile(f, "r"); String curr = null; while((curr = raf.readLine()) != null){ if(curr.startsWith("MIDlet-Version:")){ version = curr.substring(16); break; } } %>OK <%=version%>| add other master data like the users details, their roles, etc. here... <% }catch(Exception e){ log.warn("failed to read master data", e); %>ERROR <%=e.getMessage() %> <% }finally{ if(raf != null) raf.close(); } %> </body> </html>
This JSP is called when the Midlet starts, and effectively delivers
"master data" to the device, such as the users roles, account details
and importantly, the version number of the latest available JAD file on
the server. Based on this version number, which is read as the
MIDlet-Version property out of the JAD on the server, the client can
decide if the currently installed version is up to date. The Midlet
does this by calling the getAppProperty(String) method,
passing it the String "MIDlet-Version", which reads the version of the
local JAD, that was used to install the current version.
Once the client has decided that there is a newer version available, it
can ask the user if they wish to update by making an Alert the current
screen. If the user chooses to install the update now, then all that is
left is to open the devices browser to point at the new JAD which is
online, and then close the application. Putting it together in a
convenient method gives the following:
private void checkForUpdate(){
final String currentVersion = getAppProperty("MIDlet-Version"); //eg 1.0.62
new MasterDataGetter(currentVersion, model, this) {
public void onSuccess(Object md) {
MasterData masterData = (MasterData) md;
model.setMasterData(masterData);
if(currentVersion != null && masterData.getLastestVersion() != null){
if(isUpdateAvailable(masterData.getLastestVersion(), currentVersion)){
//does the user want to?
Alert a = new Alert(
"An update is available (version " + masterData.getLastestVersion() + ".\r\n" +
"Would you like to download and install it now?");
a.setType(AlertType.CONFIRMATION);
a.removeCommand(Alert.DISMISS_COMMAND);
final Command no = new Command("No", Command.ITEM, 1);
final Command yes = new Command("Yes", Command.ITEM, 2);
a.addCommand(yes);
a.addCommand(no);
a.setCommandListener(new CommandListener() {
public void commandAction(Command c, Displayable d) {
if(c == yes){
try {
platformRequest(Constants.getBaseUrl() + "jads/nameOfJad.jad");
destroyApp(true); //coz we are performing an update!
} catch (ConnectionNotFoundException e) {
//tough titties :-( ie platformRequest couldnt be called
e.printStackTrace();
handleException("Failed to open browser to get installation files.", e, AlertType.ERROR);
} catch (MIDletStateChangeException e) {
handleException("Failed to destroy midlet", e, AlertType.ERROR);
} finally {
notifyDestroyed();
}
}else if(c == no){
showCurrentView();
}
}
});
Display.getDisplay(Main.this).setCurrent(a, currentView);
} //endif is update available?
} //endif neither version is null
//now we have already called maxant, and the user has confirmed that they are
//happy to go online (eg BlackBerry shows them the URL of the first connection
//attempt), we can continue to GA. we are trying to hide this fact from the user
//as it may put of some users.
gaUploader.track("start");
}//end #onSuccess
public void onError(int code, String result) {
if(model.isShowDebugInfo()) sendDebugLog.callServer("error with update check " + code + ": " + result);
//tough titties, dont offer to upgrade
}
}.callServer();
}
Opinions expressed by DZone contributors are their own.
Comments