`
guoxinzz
  • 浏览: 428793 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

开发高可移植性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规范列表

名称

内容

JSR118

MIDP2.1规范。定义了MIDP相关的接口,高级UI,低级UI,RMS,网络相关的APIs

JSR82

定义了蓝牙接口相关的APIs

JSR135

MobileMediaAPI,定义了多媒体相关开发的组件APIs

JSR172

1.一个轻量级的标准XML解析器
2.WebServices的远程调用API
  其中这个JSR172实现的轻量级的XML解析器是JAXP1.2(JavaAPIforXMLProcessing)的一个子集。我们可以查看WTK提供的API看到j2me-xml提供的类一共只有12个,这说明这个轻量级的XML解析器是适合在移动电话这种资源受限设备上运行的。

JSR75

JSR75(PDAOptionalPackagesfortheJ2METMPlatform)中定义了两个可选包:
PIM(ThePersonalInformationManagement)API,提供对个人信息数据的访问,一般包括名片夹,日历项,和待办事项。
FC(TheFileConnection)APIs,提供对本地文件系统的访问。

JSR177

安全APIs

JSR211

ContentHander内容处理APIs,可以调用此API打开相应的文件,比如你可以打开jar安装文件,打开mp3。

JSR239

OpenGL@ES。主要用于图形相关操作

JSR179

LocationAPIs主要是用于LBS服务

JSR180

SIPAPIs

SIP是一个应用层的信令控制协议。用于创建、修改和释放一个或多个参与者的会话。这些会话可以好似Internet多媒体会议、IP电话或多媒体分发。会话的参与者可以通过组播(multicast)、网状单播(unicast)或两者的混合体进行通信

JSR184

Mobile3DGraphicsAPIs,3D图形开发。

JSR229

手机支付APIs

JSR234

手机高级多媒体支持,可以支持更丰富的多媒体操作

JSR238

国际化支持APIs

JSR248

JSR248:MobileServiceArchitectureMSA移动服务架构。

MSAforCLDC规范定义了移动电话上的下一代Java平台,当然是基于CLDC的J2ME平台。

MSAforCLDC的目的是为了减少J2ME平台的API分裂,为开发者定义一个高操作性的应用程序和服务环境。

JTWI(JavaTechnologyforWirelessIndustry,JSR185)定义了一系列的规范来强制实现JTWI规范的设备必须实现某些JSR,例如MIDP2.0,WMA和MMAPI等。MSAforCLDC可以认为是JTWI的第2版,它规定了一个高度集中的J2ME平台运行环境。

检查JSR支持

  检查JSR的支持简单的方式有两种:

1. 是通过System.getProperty("property_name")的方式进行判断,一般如果存在相关的APIs支持,它会返回一个非null字符串。

检测代码

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->System.getProperty(property_key);


public String getInfo(String info) {

if (info == null) {

return "<unknown>";

}
else {

return info;

}

}

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

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->private boolean hasClassExit(String aClassName) {

try {

Class.forName(aClassName);

return true;

}
catch (Exception e) {

return false;

}

}

  上面的检测代码相对比较简单,而且也容易理解,关键是那些JSR 支持的属性名称,或者APIs的写法。

  下面是部分属性名称,仅供参考。

Systemproperty

Description

Value

microedition.platform

DefinedinCLDC1.0andCLDC1.1.

microedition.encoding

AlwaysreturnsISO-8859-1.

microedition.configuration

DefinedinCLDC1.0andCLDC1.1.

microedition.profiles

依赖于底层实现

microedition.locale*

JSR37

依赖于底层实现

microedition.commports

依赖于底层实现

microedition.hostname

localhost

microedition.profiles

MIDP2.0

file.separator

文件分割符

依赖于底层实现(/,/)

microedition.pim.version

JSR75

1.0

microedition.smartcardslots

JSR177

依赖于底层实现

microedition.location.version

JSR179

1.0

microedition.sip.version

JSR180

1.0

microedition.m3g.version

JSR184

1.0

microedition.jtwi.version

JSR185

1.0

wireless.messaging.sms.smsc

JSR205

依赖于底层实现

wireless.messaging.mms.mmsc

JSR205

依赖于底层实现

CHAPI-Version

JSR211

JSR211

Nokia的一些系统参数

com.nokia.network.access

网络参数

pd-GSM

pd.EDGE-EDGE

pd.3G-3G

pd.HSDPA-3G

csd-GSMCSD/HSCSD

bt_pan-BluetoothPANnetwork

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个值

NetworkID

网络简称

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()来得到它,代码片断如下:

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->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

  下面是简单的测试环境的代码,有经验的朋友可以很容易就就跑起来。

代码片段


<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->/**

* 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

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->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" );

}


}

附表:属性表

1MMAPI属性

属性名称

属性作用

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代表不支持

2WirelessMessagingAPI属性

属性名称

属性作用

wireless.messaging.sms.smsc

代表手机发送短信时的短信服务中心号码

3FileConnectionAPI

属性名称

属性作用

fileconn.dir.photos

代表手机中存储照片和其它图片的目录,例如“file:///c:/Myfiles/Images/”

fileconn.dir.videos

代表手机中存储视频的目录,例如“file:///c:/Myfiles/Videoclips/”

fileconn.dir.tones

代表手机中存储声音的目录,例如“file:///c:/Myfiles/Tones/”

fileconn.dir.memorycard

代表手机中存储卡的根目录。例如“file:///d:/”

fileconn.dir.private
(NokiaS40不支持)

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

fileconn.dir.photos.name

代表手机中图片目录的名称,例如“Images”

fileconn.dir.videos.name

代表手机中视频目录的名称,例如“Videoclips”

fileconn.dir.tones.name

代表手机中声音目录的名称,例如“Soundclips”

file.separator

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

fileconn.dir.memorycard.name

代表手机中存储卡的名称,例如“Memorycard”

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics