程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> J2ME >> 開發高可移植性J2ME的軟件

開發高可移植性J2ME的軟件

編輯:J2ME

  隨著MTK的流行,使現在的J2ME虛擬機市場上品牌眾多,除了索愛,Nokia S40,Moto,三星,LG等國際大品牌的虛擬機,更是有MTK,展訊內置的一些不知名的虛擬機,因此當初Write Once,Run AnyWhere變成了Write Once,Debug AnyWhere了。對於一個沒有經驗的J2ME程序員來說,開發一個兼容性高的軟件變成了噩夢,不斷的在不同手機,不同平台上打log,在這台手機上解決了這個問題,跑到另外一台機器上問題有重新了,噢,my god!我不干了。別急!我寫這篇文章的目的就是要告訴大家,對於這種狀況,我們也不是束手無策的。下面就等我慢慢的道來解決之道。

  本文主要適合那些有經驗的J2ME程序員在優化軟件,或者是需要考慮軟件兼容性時的參考文檔。

  Jblend 平台

  JBlend 是一家日本的嵌入式虛擬機廠家生產的J2ME虛擬機,此虛擬機大量的用於低端手機平台,本人發現有使用此虛擬機的平台有,MTK,MOTO。

  官方網站:http://www.aplixcorp.com/chs/index.Html 。

  索尼愛立信平台

  索愛的虛擬機平台是:Java Platform。最新版本是8。索愛的平台在性能上,程序的穩定性方面要優於其他虛擬機平台。而且APIs方面的bug也很少,在網絡支持方面也很優秀。基本上不會因為你忘記關閉連接而導致連接洩漏。

  官方網站:http://developer.sonyeriCSSon.com/site/zhcn/docs_and_tools/p_docs_and_tools.JSP

  S40平台

  S40平台是Nokia針對S60智能操作系統推出適應低端手機的手機操作系統,相對其他虛擬機平台來說,S40虛擬機對J2ME的支持相對比較完善,而且穩定些,不過網絡環境這塊,S40對網絡資源洩漏特別關注,具體不同的手機,對同時打開多個連接有限制,這裡建議大家做個測試,就不再累贅了。

  官方網站:http://www.forum.nokia.com/

  S40平台詳解:http://tech.sina.com.cn/mobile/n/2006-09-22/1053107637.sHtml

  S60 平台

  Nokia 智能機平台下的J2ME虛擬機。相對S40來說,S60支持的特性比較多,而且有些比較特殊的用法,比如獲取系統相關屬性的時候就是其中之一。

  什麼是JCP?

  JCP(Java Community Process) 是一個開放的國際組織,主要由Java開發者以及被授權者組成,職能是發展和更新Java技術規范、參考實現(RI)、技術兼容包(TCK)。Java技 術和JCP兩者的原創者都是SUN計算機公司。然而,JCP已經由SUN於1995年創造Java的非正式過程,演進到如今有數百名來自世界各地Java 代表成員一同監督Java發展的正式程序。JCP維護的規范包括J2ME、J2SE、J2EE,XML,OSS,JAIN等。組織成員可以提交JSR(Java Specification Requests),通過特定程序以後,進入到下一版本的規范裡面。所有聲稱符合J2EE規范的J2EE類產品(應用服務器、應用軟件、開發工具等),必須通過該 組織提供的TCK兼容性測試(需要購買測試包),通過該測試後,需要繳納J2EE商標使用費。兩項完成,即是通過J2EE認證(Authorized Java Licensees of J2EE)。

  什麼是JSR?

  JSR是Java Specification Requests的縮寫,意思是Java 規范請求。是指向JCP(Java Community Process)提出新增一個標准化技術規范的正式請求。任何人都可以提交JSR,以向Java平台增添新的API和服務。JSR已成為Java界的一個重要標准。

  下面是J2ME JSR規范列表

  名稱

  內容

  JSR 118

  MIDP 2.1 規范。定義了MIDP 相關的接口,高級UI,低級UI,RMS,網絡相關的APIs

  JSR 82

  定義了藍牙接口相關的APIs

  JSR135

  Mobile Media API,定義了多媒體相關開發的組件APIs

  JSR 172

  1. 一個輕量級的標准XML解析器

  2. Web Services的遠程調用API

  其中這個JSR172實現的輕量級的XML解析器是JAXP1.2(Java API for XML Processing)的一個子集。我們可以查看WTK提供的API看到J2ME-xml提供的類一共只有12個,這說明這個輕量級的XML解析器是適合 在移動電話這種資源受限設備上運行的。

  JSR 75

  JSR 75(PDA Optional Packages for the J2METM Platform)中定義了兩個可選包:

  PIM (The Personal Information Management)API,提供對個人信息數據的訪問,一般包括名片夾,日歷項,和待辦事項。

  FC(The FileConnection) APIs,提供對本地文件系統的訪問。

  JSR 177

  安全APIs

  JSR 211

  Content Hander 內容處理APIs,可以調用此API打開相應的文件,比如你可以打開jar安裝文件,打開mp3。

  JSR 239

  Open GL@ES。主要用於圖形相關操作

  JSR 179

  Location APIs 主要是用於LBS服務

  JSR 180

  SIP APIs

  SIP是一個應用層的信令控制協議。用於創建、修改和釋放一個或多個參與者的會話。這些會話可以好似Internet多媒體會議、IP電話或多媒體分發。會話的參與者可以通過組播(multicast)、網狀單播(unicast)或兩者的混合體進行通信。

  JSR 184

  Mobile 3D Graphics APIs,3D圖形開發。

  JSR 229 

  手機支付APIs

  JSR 234

  手機高級多媒體支持,可以支持更豐富的多媒體操作

  JSR 238

  國際化支持APIs

  JSR 248

  JSR 248: Mobile Service Architecture MSA 移動服務架構。

  MSA for CLDC規范定義了移動電話上的下一代Java平台,當然是基於CLDC的J2ME平台。

  MSA for CLDC的目的是為了減少J2ME平台的API分裂,為開發者定義一個高操作性的應用程序和服務環境。

  JTWI(Java Technology for Wireless Industry,JSR 185)定義了一系列的規范來強制實現JTWI規范的設備必須實現某些JSR,例如MIDP2.0,WMA和MMAPI等。MSA for CLDC可以認為是JTWI的第2版,它規定了一個高度集中的J2ME平台運行環境。

  檢查JSR支持

  檢查JSR的支持簡單的方式有兩種:

  1. 是通過System.getProperty("property_name")的方式進行判斷,一般如果存在相關的APIs支持,它會返回一個非null字符串。

  檢測代碼

System.getProperty(property_key);
public String getInfo(String info) { 
if (info == null) { 
return   "<unknown>";
} else { 
return info; 
} 
}

  2. 通過Class.forName(clase_name)的方式。

private boolean hasClassExit(String aClassName) {
try {
Class.forName(aClassName);
return true;
} catch (Exception e) {
return false;
}
}

  上面的檢測代碼相對比較簡單,而且也容易理解,關鍵是那些JSR 支持的屬性名稱,或者APIs的寫法。

  下面是部分屬性名稱,僅供參考。

  System property

  Description

  Value

  microedition.platform

 

  Defined in CLDC 1.0 and CLDC 1.1. 

  microedition.encoding

 

  Always returns ISO-8859-1.

  microedition.configuration

 

  Defined in CLDC 1.0 and CLDC 1.1.

  microedition.profiles

 

  依賴於底層實現

  microedition.locale*

  JSR 37

  依賴於底層實現

  microedition.commports

 

  依賴於底層實現

  microedition.hostname

 

  localhost

  microedition.profiles

 

  MIDP2.0

  file.separator

  文件分割符

  依賴於底層實現(/,)

  microedition.pim.version

  JSR 75

  1.0

  microedition.smartcardslots

  JSR 177

  依賴於底層實現

  microedition.location.version

  JSR 179

  1.0

  microedition.sip.version

  JSR 180

  1.0

  microedition.m3g.version

  JSR 184

  1.0

  microedition.jtwi.version

  JSR 185

  1.0

  wireless.messaging.sms.smsc

  JSR 205

  依賴於底層實現

  wireless.messaging.mms.mmsc

  JSR 205

  依賴於底層實現

  CHAPI-Version

  JSR 211

  JSR 211

     

  Nokia的一些系統參數

  com.nokia.Network.Access

  網絡參數

  pd - GSM

  pd.EDGE -  EDGE

  pd.3G - 3G

  pd.HSDPA - 3G

  csd -   GSM CSD/HSCSD 

  bt_pan - Bluetooth PAN network

  wlan - WIFI

  na -  無任何網絡

  com.nokia.mid.dateformat

  日期格式

  Yy/mm/dd

  com.nokia.mid.timeformat

  時間格式

  hh:mm

  com.nokia.memoryramfree

  動態內存分配

  Note: S60 第3版不支持

 

  com.nokia.mid.batterylevel

  電池狀態

 

  com.nokia.mid.countrycode

  城市代碼

 

  com.nokia.mid.Networkstatus

  網絡工作狀態

 

  com.nokia.mid.Networkavailability

  網絡是否激活狀態

 

  com.nokia.mid.Networkid

  網絡ID

  返回2個值

  Network ID

  網絡簡稱

  com.nokia.mid.Networksignal

   

  com.nokia.mid.cellid

  Cellid

  基站信息ID

  com.nokia.mid.imei

  Imei號

  手機唯一標識號

  com.nokia.mid.imsi

 

  應用程序屬性

  應用程序屬性值是在應用程序描述符文件或者MANIFEST文件中定義的,當我們部署應用程序的時候可以定義應用程序屬性。比如下面是一個典型的JAD文件內容。

  MIDlet-1: HttpWrapperMidlet,httpwrapper.HttpWrapperMIDlet

  MIDlet-Jar-Size: 16315

  MIDlet-Jar-URL: HttpWrapper.jar

  MIDlet-Name: HttpWrapper

  MIDlet-Vendor: Vendor

  MIDlet-Version: 1.0

  MicroEdition-Configuration: CLDC-1.0

  MicroEdition-Profile: MIDP-1.0

  Which-Locale: en

  其中Which-Locale就是應用程序屬性值,我們可以通過MIDlet的成員方法getAppProperty()來得到它,代碼片斷如下:

import Javax.microedition.midlet.*;
public class MyMIDlet extends MIDlet {
private String suiteName;
private String which_locale;
public MyMIDlet(){
suiteName = getAppProperty(  "MIDlet-Name"  );
which_locale = getAppProperty("Which-Locale");
}
//這裡省略了其他代碼
}

  屬性值對大小寫是敏感的,如果屬性值在底層系統、JAD文件和Manifest文件中都沒有定義的話,那麼將返回Null。

  簡單的Demo

  下面是簡單的測試環境的代碼,有經驗的朋友可以很容易就就跑起來。

  代碼片段

/**
* getSysInfo
*/
private void getSysInfo() {
addInfo( "Microedition Configuration: ",
getInfo(System.getProperty( "microedition.configuration")));
addInfo( "Microedition Profiles: ",
getInfo(System.getProperty( "microedition.profiles")));
addInfo( "microedition.jtwi.version:",
getInfo(System.getProperty( "microedition.jtwi.version")));
addInfo( "microedition.platform:",
getInfo(System.getProperty( "microedition.platform")));
addInfo( "microedition.locale:",
getInfo(System.getProperty( "microedition.locale")));
addInfo( "default encoding:",
getInfo(System.getProperty( "microedition.encoding")));
addInfo( "microedition.commports",
getInfo(System.getProperty( "microedition.commports")));
addInfo( "microedition.hostname",
getInfo(System.getProperty( "microedition.hostname")));
//  microedition.smartcardslots
addInfo( " microedition.smartcardslots",
getInfo(System.getProperty( " microedition.smartcardslots")));
addInfo( "com.nokia.Network.Access",
getInfo(System.getProperty( "com.nokia.Network.Access")));  
addInfo( "com.nokia.mid.dateformat",
getInfo(System.getProperty( "com.nokia.mid.dateformat")));
addInfo( "com.nokia.mid.timeformat",
getInfo(System.getProperty( "com.nokia.mid.timeformat")));
addInfo( "com.nokia.memoryramfree",
getInfo(System.getProperty( "com.nokia.memoryramfree")));
addInfo( "com.nokia.mid.batterylevel",
getInfo(System.getProperty( "com.nokia.mid.batterylevel")));
addInfo( "com.nokia.mid.countrycode",
getInfo(System.getProperty( "com.nokia.mid.countrycode")));
addInfo( "com.nokia.mid.Networkstatus",
getInfo(System.getProperty( "com.nokia.mid.Networkstatus")));
addInfo( "com.nokia.mid.Networksignal",
getInfo(System.getProperty( "com.nokia.mid.Networksignal")));
addInfo( "com.nokia.mid.Networkid",
getInfo(System.getProperty( "com.nokia.mid.Networkid")));
addInfo( "com.nokia.mid.Networkavailability",
getInfo(System.getProperty( "com.nokia.mid.Networkavailability")));
addInfo( "com.nokia.mid.cellid",
getInfo(System.getProperty( "com.nokia.mid.cellid")));
addInfo( "com.nokia.mid.imei",
getInfo(System.getProperty( "com.nokia.mid.imei")));
addInfo( "com.nokia.mid.imsi",
getInfo(System.getProperty( "com.nokia.mid.imsi")));
String[] timeZoneIDs = Java.util.TimeZone.getAvailableIDs();
StringBuffer timeZonesBuffer = new StringBuffer();
for (int i = 0; i < timeZoneIDs.length; i++) {
timeZonesBuffer.append(timeZoneIDs[i]).append('n');
}
addInfo( "Total memory:",
Long.toString(Runtime.getRuntime().totalMemory()) + " bytes");
addInfo( "Free memory:",
Long.toString(Runtime.getRuntime().freeMemory()) + " bytes");
addInfo( "Available TimeZones:", timeZonesBuffer.toString());
addInfo( "Default TimeZone:", Java.util.TimeZone.getDefault().getID());
addInfo( "com.siemens.mp.lcdui.Image", hasClassExit("com.sIEmens.mp.lcdui.Image") + "");
addInfo( "com.motorola.phonebook.PhoneBookRecord",        hasClassExit("com.motorola.phonebook.PhoneBookRecord") + "");
addInfo( "com.motorola.Dialer", hasClassExit("com.motorola.Dialer") + "");
addInfo( "com.jblend.util.Case", hasClassExit("com.jblend.util.Case") + "");
addInfo( "com.samsung.util.AudioClip", hasClassExit("com.samsung.util.AudioClip") + "");
addInfo( "com.mot.iden.multimedia.Lighting",     hasClassExit("com.mot.iden.multimedia.Lighting") + "");
}
private boolean hasClassExit(String aClassName) {
try {
Class.forName(aClassName);
return true;
} catch (Exception e) {
return false;
}
}
public String getInfo(String info) {
if (info == null) {
return "<unknown>";
} else {
return info;
}
}
public void addInfo(String name, String value) {
iForm.append(new StringItem(name, value));
}

  代碼片段2

public void collectInfos(TestClIEnt midlet, Display display) {
try {
Class.forName( "Javax.microedition.media.control.VideoControl");
addInfo( "MMAPI: ", "yes" );
addInfo( "MMAPI-Version: ",  getInfo(System.getProperty("microedition.media.version")) );
} catch (ClassNotFoundException e) {
addInfo( "MMAPI: ", "no" );
}
try {
Class.forName( "Javax.wireless.messaging.Message");
addInfo( "WMAPI 1.1: ", "yes" );
try {
Class.forName( "Javax.wireless.messaging.MultipartMessage");
addInfo( "WMAPI 2.0: ", "yes" );
} catch (ClassNotFoundException e) {
addInfo( "WMAPI 2.0: ", "no" );
}
} catch (ClassNotFoundException e) {
addInfo( "WMAPI 1.1: ", "no" );
}
try {
Class.forName( "Javax.bluetooth.DiscoveryAgent");
addInfo( "Bluetooth-API: ", "yes" );
try {
Class.forName( "Javax.obex.ClIEntSession");
addInfo( "Bluetooth-Obex-API: ", "yes" );
} catch (ClassNotFoundException e) {
addInfo( "Bluetooth-Obex-API: ", "no" );
}
} catch (ClassNotFoundException e) {
addInfo( "Bluetooth-API: ", "no" );
}
try {
Class.forName( "Javax.microedition.m3g.Graphics3D");
addInfo( "M3G-API: ", "yes" );
} catch (ClassNotFoundException e) {
addInfo( "M3G-API: ", "no" );
}
try {
Class.forName( "Javax.microedition.pim.PIM");
addInfo( "PIM-API: ", "yes" );
} catch (ClassNotFoundException e) {
addInfo( "PIM-API: ", "no" );
}
try {
Class.forName( "Javax.microedition.io.file.FileSystemRegistry");
addInfo( "FileConnection-API: ", "yes" );
} catch (ClassNotFoundException e) {
addInfo( "FileConnection-API: ", "no" );
}
try {
Class.forName( "Javax.microedition.location.Location");
addInfo( "Location-API: ", "yes" );
} catch (Java.lang.Throwable e) {
addInfo( "Location-API: ", "no" );
}
try {
Class.forName( "Javax.microedition.XML.rpc.Operation");
addInfo( "WebServices-API: ", "yes" );
} catch (ClassNotFoundException e) {
addInfo( "WebServices-API: ", "no" );
}
try {
Class.forName( "Javax.microedition.sip.SipConnection");
addInfo( "SIP-API: ", "yes" );
} catch (ClassNotFoundException e) {
addInfo( "SIP-API: ", "no" );
}
try {
Class.forName( "com.nokia.mid.ui.FullCanvas");
addInfo( "Nokia-UI-API: ", "yes" );
} catch (ClassNotFoundException e) {
addInfo( "Nokia-UI-API: ", "no" );
}
try {
Class.forName( "com.sIEmens.mp.MIDlet");
addInfo( "SIEmens-Extension-API: ", "yes" );
try {
Class.forName( "com.sIEmens.mp.color_game.GameCanvas");
addInfo( "SIEmens-ColorGame-API: ", "yes" );
} catch (ClassNotFoundException e) {
addInfo( "SIEmens-ColorGame-API: ", "no" );
}
} catch (ClassNotFoundException e) {
addInfo( "SIEmens-Extension-API: ", "no" );
}
}

  附表:屬性表

  表1 MMAPI屬性

  屬性名稱

  屬性作用

  supports.mixing

  代表手機是否支持混音(同時播放多個Player),返回值為“true”或“false”

  supports.audio.capture

  代表手機是否支持聲音捕獲(錄音),返回值為“true”或“false”

  supports.video.capture

  代表手機是否支持視頻捕獲(錄像),返回值為“true”或“false”

  supports.recording

  代表手機是否支持記錄(record),返回值為“true”或“false”

  audio.encodings

  代表手機支持的聲音格式,返回值格式為“encoding=audio/wav”,多個格式之間使用至少一個空格進行間隔

  video.encodings

  代表手機支持的視頻格式,返回值格式為“encoding=video/3gpp”,多個格式之間使用至少一個空格進行間隔

  video.snapshot.encodings

  代表手機使用getSnapshot方法獲得的視頻快照格式,返回值格式為“encoding=png”,多個格式之間使用至少一個空格進行間隔

  streamable.contents

  代表手機支持的流媒體格式,返回null代表不支持

  表2 Wireless Messaging API屬性

  屬性名稱

  屬性作用

  wireless.messaging.sms.smsc

  代表手機發送短信時的短信服務中心號碼

  表3FileConnection API

  屬性名稱

  屬性作用

  fileconn.dir.photos

  代表手機中存儲照片和其它圖片的目錄,例如“file:///c:/My files/ Images /”

  fileconn.dir.videos

  代表手機中存儲視頻的目錄,例如“file:///c:/My files/Video clips/”

  fileconn.dir.tones

  代表手機中存儲聲音的目錄,例如“file:///c:/My files/Tones/”

  fileconn.dir.memorycard

  代表手機中存儲卡的根目錄。例如“file:///d:/”

  fileconn.dir.private

  (Nokia S40不支持) 

  代表手機中MIDlet的私有工作目錄,例如“file:///c:/System/MIDlets/[1015f294]/scratch”

  fileconn.dir.photos.name

  代表手機中圖片目錄的名稱,例如“Images”

  fileconn.dir.videos.name

  代表手機中視頻目錄的名稱,例如“Video clips”

  fileconn.dir.tones.name

  代表手機中聲音目錄的名稱,例如“Sound clips”

  file.separator

  代表手機中的文件分隔符,例如“/”

  fileconn.dir.memorycard.name

  代表手機中存儲卡的名稱,例如“Memory card”

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved