作者:Srijeeb Roy ;magic003(作者的blog:http://blog.matrix.org.cn/page/magic003)
原文:http://www.matrix.org.cn/resource/article/44/44449_Push+JAVA+Mobile.html
關(guān)鍵字:Push;JAVA;mobile

添加MIDP 2.0的Push注冊特征到你的設(shè)備應(yīng)用程序中
移動技術(shù)日漸流行。Java微小版本,或者叫Java ME(Sun的J2ME平臺的新名字),是最流行的開發(fā)移動應(yīng)用程序的技術(shù)之一。使用Java ME,我們可以在使用JVM或KVM的手持設(shè)備上運(yùn)行多種無線應(yīng)用程序。

Connected Limited Device Configuration (CLDC)被包含在Java ME中,它是面向那些只擁有有限資源,使用KVM的設(shè)備。同樣,Mobile Information Device Profile(MIDP)也被包含在Java ME中,這是一個(gè)為了在手機(jī)上運(yùn)行應(yīng)用程序的基于CLDC的profile。運(yùn)行在移動設(shè)備中的應(yīng)用程序模塊叫做MIDlet,是一個(gè)MIDP應(yīng)用程序。一個(gè)MIDlet主要是一組有序運(yùn)行的類,并且它們由運(yùn)行在移動設(shè)備中的應(yīng)用程序管理軟件(AMS)所控制。

MIDP的最新版本(2.0)引入了很多新的特征來幫助開發(fā)者建立健壯的企業(yè)級應(yīng)用程序。其中一個(gè)比較重要的特征就是push注冊機(jī)制。在Java ME應(yīng)用程序中,我們有時(shí)候需要從服務(wù)器推數(shù)據(jù),并在設(shè)備上自動啟動一個(gè)移動應(yīng)用程序,而不需要由用戶明確的啟動設(shè)備。設(shè)想一種情形,當(dāng)一個(gè)針對他/她的名字的工作條款被建立時(shí),用戶必須能自動得到通知,并且必須盡快地對此工作條款做出反應(yīng)。Java ME的push注冊機(jī)制能夠很容易地將信息推向一個(gè)Java ME應(yīng)用程序,并自動啟動該程序。在這篇文章中,我將向你展示如何將push注冊機(jī)制特征添加到你的移動應(yīng)用程序中。

Push注冊機(jī)制的行為可以被描述為如下三個(gè)步驟:

1.MIDlet在移動設(shè)備中注冊一個(gè)連同協(xié)議名稱的端口,如果任何信息到達(dá)指定的端口,并且使用相同的協(xié)議,那么AMS就將它轉(zhuǎn)交給MIDlet。注冊使用Java ME應(yīng)用程序描述符(JAD)文件靜態(tài)的完成。程序也能使用應(yīng)用程序內(nèi)置的API執(zhí)行動態(tài)注冊。

2. 從服務(wù)器,信息被發(fā)送到特定的移動設(shè)備,使用MIDlet應(yīng)用程序注冊監(jiān)聽的協(xié)議和端口。

3. 在信息被傳遞到移動設(shè)備后,AMS調(diào)用注冊了監(jiān)聽此端口和協(xié)議的MIDlet應(yīng)用程序。一旦信息被轉(zhuǎn)交到MIDlet,那么處理信息就是此應(yīng)用程序的責(zé)任了。典型的,根據(jù)信息的信息的內(nèi)容,一個(gè)應(yīng)用程序會選擇打開一個(gè)屏幕,并允許用戶與服務(wù)器進(jìn)行一些事務(wù)。

在這篇文章的例子中,為了從服務(wù)器推信息,我們將使用一個(gè)GSM(移動通信全球系統(tǒng))調(diào)制解調(diào)器。圖1較高層次地描述了我們將在此文中實(shí)現(xiàn)的場景。

image
圖1. 從服務(wù)器push SMS消息到移動設(shè)備的高層場景

在jad文件中,每一個(gè)push注冊條目都包含如下信息:MIDlet-Push-<n>: <ConnectionURL>, <MIDletClassName>, <AllowedSender>。

MIDlet-Push-<n>:push注冊屬性名稱。MIDlet套件中可以包含多條push注冊。<n>的數(shù)值從1開始,并且對于附加的條目必須使用連續(xù)的序數(shù)。第一個(gè)發(fā)現(xiàn)的缺失條目將中止列表。任何剩余的條目都會被忽略。
ConnectionURL:被Connector.open()使用的連接字符串。
MIDletClassName:負(fù)責(zé)連接的MIDlet。指定的MIDlet必須使用MIDlet-<n>記錄在描述文件或jar文件的manifest中登記過。
AllowedSender:一個(gè)指定的過濾器,????????它將限制哪些發(fā)送者能夠能正當(dāng)啟動請求的MIDlet。

MIDP 2.0 規(guī)范定義了數(shù)據(jù)報(bào)和socket帶內(nèi)連接的語法。當(dāng)其他規(guī)范為其他連接類型定義push 語義時(shí),它們必須既定義過濾器域期望的語法,又定義連接URL字符串的期望格式。

在jad文件中,一個(gè)push注冊的典型例子,使用socket連接,類似于如下:
MIDlet-Push-1: socket://:77, com.sample.SampleApplication, *.
這個(gè)示例描述符條目在77端口處保存一個(gè)流套接字,并且允許所有的發(fā)送者。

從服務(wù)器推信息到移動設(shè)別會帶來一些問題:如果我們想發(fā)送信息到一個(gè)在指定端口注冊了監(jiān)聽流套接字的特定設(shè)備,我們必須知道那個(gè)移動電話的無線網(wǎng)絡(luò)IP。因?yàn)樵跓o線網(wǎng)絡(luò)中,很多手機(jī)不使用始終連接環(huán)境(有時(shí)候,提供商不支持設(shè)備中網(wǎng)絡(luò)中的靜態(tài)IP),發(fā)送信息到設(shè)備是有問題的。如果我們不知道設(shè)備的無線IP,我們將不能使用套接字連接從服務(wù)器發(fā)送信息到設(shè)備。

短信服務(wù)(SMS)在這種情況下派上了用場。使用SMS,我們指定目標(biāo)設(shè)備的電話號碼;因此在這種情況下,我們不需要知道設(shè)備的IP地址。但是,使用SMS作為觸發(fā)器同樣會帶來一些問題:因?yàn)镸IDP2.0規(guī)范只定義了針對數(shù)據(jù)報(bào)和套接字帶內(nèi)連接的語法,而沒有針對SMS連接的,所以不保證所有支持MIDP2.0的設(shè)備都能使用SMS作為觸發(fā)器來進(jìn)行push注冊。但無線消息API(WMA1.1)-一個(gè)在MIDP上能支持SMS的的可選包-現(xiàn)在得到很多移動設(shè)備的支持,所以有更大的可能性,SMS作為push注冊機(jī)制的觸發(fā)器將得到很多設(shè)備的支持。對于這篇文章,我使用Nokia 6600移動電話,它是支持SMS作為push注冊機(jī)制的觸發(fā)器的。

另外,從服務(wù)器發(fā)送一條SMS消息到設(shè)備不是簡單直接的,因?yàn)橛泻芏嗤緩酱嬖凇MS服務(wù)提供商提供API(或者暴露服務(wù)URL),通過這些API你能從你的服務(wù)器端應(yīng)用程序發(fā)送消息到你指定的移動電話上。但這種方法依賴于SMS服務(wù)提供商和它特殊的計(jì)劃。可選的方式是使用一個(gè)GSM調(diào)制解調(diào)器,這樣你需要使GSM調(diào)制解調(diào)器與你的服務(wù)器端應(yīng)用程序進(jìn)行交互。在這篇文章中,我將使用一個(gè)開源的產(chǎn)品,SMSLib for Java V1.0(原名jSMSEngine),它能使GSM調(diào)制解調(diào)器與你的Java服務(wù)器端程序進(jìn)行交互。

另一個(gè)在此需要注意的要點(diǎn)是一條簡單的SMS消息將不會激活MIDlet。我們必須發(fā)送SMS消息到MIDlet注冊監(jiān)聽的特定的端口。因此被用來發(fā)送SMS消息的軟件(或SMS服務(wù)提供商)必須能夠?qū)⑺l(fā)送到設(shè)備指定的端口。SMSLib for Java v1.0 支持這一功能。

當(dāng)我們使用GSM調(diào)制解調(diào)器方案,我們必須了解GSM調(diào)制解調(diào)器將在內(nèi)部使用SIM(訂戶識別模塊)卡來發(fā)送SMS消息。SIM卡依賴于某個(gè)移動服務(wù)提供商。因此每條SMS短信將帶來與從常規(guī)GSM移動電話發(fā)送消息同樣的花費(fèi)。正相反,對于一個(gè)企業(yè)級應(yīng)用(依賴于服務(wù)計(jì)劃),通過提供商的SMS網(wǎng)關(guān)發(fā)送批量SMS消息會被證實(shí)更節(jié)省開銷。但是,如果應(yīng)用程序不需要發(fā)送大量SMS消息來出發(fā)MIDlet,那么GSM調(diào)制解調(diào)器方案會是有效的開銷,并能從移動服務(wù)提供商那里取消特殊的批量SMS服務(wù)依賴。

雖然我建議為了近期的產(chǎn)品使用購買一個(gè)單獨(dú)的GSM調(diào)制解調(diào)器,但是測試此行為不要求夠買。通常地,很多GSM移動電話模型帶有一個(gè)內(nèi)置的GSM調(diào)制解調(diào)器。那些移動模型中的任何一個(gè)都能夠作為GSM調(diào)制解調(diào)器,來代替單獨(dú)的調(diào)制解調(diào)器。在這篇文章中,我使用另外一個(gè)Nokia 6600移動電話,而不是一個(gè)單獨(dú)的GSM調(diào)制解調(diào)器,因?yàn)镹okia 6600有一個(gè)內(nèi)置的GSM調(diào)制解調(diào)器。

現(xiàn)在,讓我們開發(fā)一個(gè)實(shí)例程序,是我們能夠從一個(gè)Java服務(wù)器端應(yīng)用程序發(fā)送一條SMS消息到一個(gè)移動電話的指定端口,并自動啟動移動設(shè)備中的一個(gè)MIDlet。

使用push注冊特征開發(fā)客戶端MIDlet

為了開發(fā)客戶端,我們使用Sun Java Wireless Toolkit(原名為J2ME Wireless Toolkit)。我使用版本2.2。這個(gè)產(chǎn)品是免費(fèi)的,可以從Sun的網(wǎng)站下載。為了安裝和運(yùn)行此工具包,你必須在你的機(jī)器上裝有J2SE 1.4.2_02或更新的版本。

我使用Windows 2000 Professional 操作系統(tǒng)。

安裝Sun的工具包后,按照如下描述的步驟:

1.從開始菜單打開KToolBar:選擇程序,然后J2ME Wireless Toolkit 2.2,然后KToolbar。將會打開一個(gè)應(yīng)用程序窗口,如圖2所以。

image
圖2. 打開KToolbar

2.現(xiàn)在,在剛才打開的窗口中點(diǎn)擊新建工程圖標(biāo)。會打開一個(gè)彈出窗口;在那里你可以指定工程名稱和MIDlet類名。在工程名稱中輸入MySamplePushRegistryProject,在MIDlet類名中輸入com.sample.MySamplePushRegistry。

image
圖3. 新建一個(gè)工程

3.在步驟2后,會自動出現(xiàn)另一個(gè)彈出窗口,它將允許你設(shè)定項(xiàng)目的其他設(shè)置。確保你在API 選擇標(biāo)簽中。在此標(biāo)簽中,從目標(biāo)平臺下拉菜單中選擇JTWI(如果還沒有選擇)。同樣確保CLDC 1.0單選按鈕被選中。不要鉤選Mobile Media API多選框(因?yàn)椴粫褂萌魏胃嗝襟w有關(guān)的API)。請參考圖4。

image
圖4. 設(shè)置API首選項(xiàng)

4.現(xiàn)在進(jìn)入push注冊標(biāo)簽。點(diǎn)擊添加按鈕。將會出現(xiàn)一個(gè)彈出窗口。在連接URL域中輸入sms://:50001,在類域中輸入com.sample.MySamplePushRegistry,在允許發(fā)送者域中輸入*。請參考圖5。

image
圖5 設(shè)置push注冊的屬性

5.在步驟4后,一個(gè)條目將會被加入到父窗口中。如圖6所示。

image
圖6. 設(shè)置push注冊的屬性(續(xù))

6.現(xiàn)在進(jìn)入許可標(biāo)簽。單擊添加按鈕。從許可樹中選擇javax/microedtion/io/Connector/sms并單擊OK。重復(fù)相同????????的步驟來添加許可javax/wireless/messaging/sms/receive 和 javax/microedtion/io/PushRegistry。

7.在步驟6后,三項(xiàng)許可將被添加到應(yīng)用程序中。如圖7所示。

image
圖7. 添加許可

8.現(xiàn)在進(jìn)入用戶定義標(biāo)簽。這里,我們添加用戶定義的變量,這將包含SMS端口。從我們的程序,我們查閱此用戶定義變量來讀取SMS端口。在此標(biāo)簽中,單擊添加按鈕。打開一個(gè)彈出窗口。輸入SMS-Port作為屬性名稱。選擇OK。出現(xiàn)了最初的彈出的窗口。輸入50001作為SMS-Port的值。如圖8所示。

image
圖8. 添加定制屬性SMS-Port

9.現(xiàn)在,在設(shè)置窗口中單擊OK。這個(gè)動作將帶回到KToolbar。

10.在步驟9后,如果你觀察由以上步驟產(chǎn)生的jad文件,C:/WTK22/apps/MySamplePushRegistryProject/bin/MySamplePushRegistryProject.jad(假設(shè)J2ME Wireless Toolkit 2.2被裝在目錄C:/WTK22中),你會找到在前面步驟中設(shè)定的完整配置。所有條目中最重要的一個(gè)如下:MIDlet-Push-1: sms://:50001, com.smaple.MySamplePushRegistry, *. 此條目確保你的應(yīng)用程序監(jiān)聽50001端口上的SMS消息。

現(xiàn)在,讓我們著眼于MIDlet應(yīng)用程序的代碼。這里,我僅僅提供MIDlet的一部分代碼片斷。 請看資源來下載在此應(yīng)用程序中使用的所有代碼。

public class MySamplePushRegistry extends MIDlet
?? implements CommandListener, Runnable, MessageListener {
??
?? //....
??
?? public void startApp() {
??????smsPort = getAppProperty("SMS-Port");
??????String smsConnection = "sms://:" + smsPort;
??????if (smsconn == null) {
???????? try {
????????????smsconn = (MessageConnection)
?????????????? Connector.open(smsConnection);

????????????smsconn.setMessageListener(this);
???????? } catch (IOException ioe) {
????????????ioe.printStackTrace();
???????? }
??????}
??????display.setCurrent(resumeScreen);
?? }
?? public void notifyIncomingMessage(MessageConnection conn) {
??????if (thread == null) {
???????? thread = new Thread(this);
???????? thread.start();
??????}
?? }????
?? public void run() {
??????try {
???????? msg = smsconn.receive();
???????? if (msg != null) {
????????????if (msg instanceof TextMessage) {

?????????????? content.setString(((TextMessage)msg).getPayloadText());
????????????}
????????????display.setCurrent(content);
???????? }
??????} catch (IOException e) {
???????? e.printStackTrace();
??????}
?? }
?? //other methods to follow
}


在這個(gè)片斷中,如下要點(diǎn)值得注意:類MySamplePushRegistry集成了MIDlet。這個(gè)類實(shí)現(xiàn)了CommandListener,Runnable和MessageListener接口。在MIDlet的startApp()方法中,我們使用getAppProperty()方法得到SMS-Port屬性的值。我們也使用Generic Connection Framework(GCF)創(chuàng)建了一個(gè)連接來監(jiān)聽SMS消息。GCF的Connector類的open()方法創(chuàng)建了SMS連接。如果一個(gè)消息到達(dá)了,notifyIncomingMessage()方法會被調(diào)用,它會創(chuàng)建和啟動一個(gè)線程(如果還沒有被創(chuàng)建)。在線程的run()方法中,程序等待一條消息(smsconn.receive())。當(dāng)消息被接受到,我們得到原始的消息并在Alert類中設(shè)定消息。在現(xiàn)實(shí)生活的應(yīng)用程序中,用戶通常打開一個(gè)屏幕來處理消息。

一旦你的代碼準(zhǔn)備好了,使用KToolbar中的創(chuàng)建圖標(biāo)來創(chuàng)建它。在編譯和無錯(cuò)誤預(yù)驗(yàn)證創(chuàng)建之后,你需要把應(yīng)用程序打包成一個(gè)JAR。為了完成這個(gè)任務(wù),選擇工程菜單,然后包,然后創(chuàng)建包。

在把應(yīng)用程序部署到真實(shí)設(shè)備之前,我們先測試程序是否在模擬器中運(yùn)轉(zhuǎn)正確。選擇工程菜單,然后通過OTA運(yùn)行。這個(gè)步驟實(shí)際上是模擬MIDlet的over-the-air安裝。圖9的順序圖描述了全部的過程。保持此模擬器窗口打開。

image
圖9. 通過over the air方法在模擬器中安裝應(yīng)用程序

現(xiàn)在,在KToolbar中進(jìn)入文件菜單,并選擇Utilities。得到一個(gè)彈出窗口,如圖10所示。

image
圖10. 打開Utilities

單擊WMA,然后打開控制臺。打開了另一個(gè)彈出窗口:

image
圖11. 打開WMA Utilities 控制臺

在窗口中選擇發(fā)送SMS按鈕。窗口的內(nèi)容將會改變,如圖12所示。在選擇客戶端區(qū)域內(nèi)選擇+5550000作為電話號碼。在端口文本框中,輸入50001。在消息域中,輸入Hi Test Message。現(xiàn)在單擊發(fā)送按鈕。

image
圖12. 從Utilities發(fā)送SMS消息

如果在以上步驟中,每一件事都運(yùn)行良好,那么模擬器窗口,如圖13所示,將會顯示一個(gè)消息到達(dá)了模擬移動電話,告訴用戶消息到達(dá)到了,并等到批準(zhǔn)。

image
圖13. 模擬器MIDlet被SMS消息激活

如果你在模擬器上選擇Yes,MIDlet會自動啟動,”Hi Test Message”會顯示在模擬器中,如圖14所示。

image
圖14. 模擬器MIDlet接受到SMS

接下來的步驟事在真實(shí)設(shè)備上安裝MIDlet。你可以使用OTA安裝應(yīng)用程序。詳細(xì)內(nèi)容請查閱Sun的工具包文檔。除了OTA,我們可以電纜/紅外線/藍(lán)牙技術(shù)來安裝MIDlet,如果設(shè)備支持那些選項(xiàng)。作為一個(gè)客戶端設(shè)備,我使用Nokia 6600,這是支持紅外線技術(shù)的,并且因?yàn)槲矣幸粋€(gè)紅外線適配器,我使用紅外線技術(shù)在Nokia 6600中安裝MIDlet。

如果以上步驟運(yùn)行良好,你的客戶端應(yīng)用程序就準(zhǔn)備就緒了。現(xiàn)在是時(shí)候來開發(fā)服務(wù)器端應(yīng)用程序了,實(shí)際上,它將發(fā)送SMS消息給監(jiān)聽50001端口的MIDlet。

開發(fā)服務(wù)器端應(yīng)用程序來將SMS消息發(fā)送到特定的設(shè)備端口
如前所述,為了開發(fā)服務(wù)器端與GSM調(diào)制解調(diào)器交互的的代碼,我使用開源的SMSLib for Java, 它使用關(guān)注指令(AT指令)與GSM調(diào)制解調(diào)器進(jìn)行交互。它同時(shí)也使用Java通信API或RxTx與使用的操作系統(tǒng)通信,并與外部設(shè)備(GSM調(diào)制解調(diào)器)交談來發(fā)送AT指令。

為了發(fā)送消息到指定的端口,用戶數(shù)據(jù)和協(xié)議數(shù)據(jù)單元(PDU)的用戶數(shù)據(jù)標(biāo)題指示(UDHI)域都必須被修改。SMSLib在內(nèi)部完成了它,所以發(fā)送SMS消息引起的復(fù)雜度都被包裝在SMSLib的代碼內(nèi)。如果你對觀察消息是如何被正確發(fā)送的感興趣,你可以獨(dú)自仔細(xì)檢查SMSLib的代碼。

按照如下的步驟來完成服務(wù)器的編碼和部署:

1.從SMSLib網(wǎng)站下載SMSLib代碼。下載時(shí),確保你下載的是SMSLib-Java-v1.0.1.zip。SMSLib for Java可以跟Java通信API或RxTx一起使用。最近,Sun撤消了了對Java通信API Windows版的支持,所以使用RxTx會更好。但如果你已經(jīng)有了Java通信API,你同樣可以用它和SMSLib一起運(yùn)行。在這篇文章中,我將詳述以上兩種運(yùn)行實(shí)例程序的方法。

2.以Java通信API 2.0作為開始,首先,確保你已經(jīng)正確安裝了API。解壓javacomm20-win32.zip。在commapi子目錄中,你將找到如下文件:
&#61548;????????javax.comm.properties
&#61548;????????win32com.dll
&#61548;????????comm..jar


把javax.comm.properties拷貝到你的Java運(yùn)行時(shí)環(huán)境的lib目錄中。把win32com.dll拷貝到你的JRE的bin目錄中。當(dāng)運(yùn)行任何使用SMSLib的程序時(shí),確保comm.jar在classpath中。

為了保證Java通信API被正確的安裝了,從命令框中進(jìn)入到commapi\samples\BlackBox目錄中。按如下方式設(shè)置PATH變量:以我為例,JRE的家目錄為C:\j2sdk1.4.2_03\jre。根據(jù)你的JRE設(shè)置做相應(yīng)的改變。

設(shè)置PATH=.;c:\j2sdk1.4.2_03\jre\bin;。現(xiàn)在,使用如下命令來運(yùn)行Java 黑盒程序:
java -classpath .;../../comm..jar;BlackBox.jar; BlackBox。

如果Java通信API被正確的安裝了,那么如圖15所示,會出現(xiàn)一個(gè)顯示你機(jī)器的可用串口(COM端口)的Swing窗口。關(guān)閉窗口之后,命令框?qū)恍└憧捎玫腃OM端口相關(guān)的行,如下面的示例命令提示輸出所示。記住,依賴于你的PC上的可用端口,Swing窗口和命令行提示的內(nèi)容可能會有變化。但重要的是,如果你能夠看到GUI和在命令提示框中的如下行(就象下面所示),你可以假設(shè)Java通信API已經(jīng)正確安裝了。在這個(gè)測試之后,關(guān)閉Swing窗口來中止黑盒程序。

image
圖15. 測試Java通信API的安裝

實(shí)例命令提示框輸出:
COM1:??PORT_OWNED
COM2:??PORT_OWNED
Closing port 1 (COM2)
Closing COM2
Closing port 0 (COM1)
Closing COM1


3.現(xiàn)在,是時(shí)候把GSM調(diào)制解調(diào)器連接到你的電腦上了。我使用一部Nokia 6600移動電話作為GSM調(diào)制解調(diào)器。Nokia 6600沒有串口連接器(COM端口連接器)。但是,它提供了紅外線技術(shù)連接到電腦,然后作為GSM調(diào)制解調(diào)器。如果你有一部有串口直接連接器的電話,那樣使用起來會更簡單。一般地,????????實(shí)際的GSM調(diào)制解調(diào)器會提供串口連接器。但是如果你的設(shè)備缺少串口連接器,但包含一個(gè)內(nèi)置的GSM調(diào)制解調(diào)器并能使用紅外線或藍(lán)牙技術(shù)連接,這種選擇也能起作用。

為了在沒有物理COM端口的情況下,在功能上實(shí)現(xiàn)COM端,你必須將一個(gè)虛擬的COM端口映射到你的紅外線或藍(lán)牙連接上。SMSLib需要一個(gè)兼容的GSM電話或GSM調(diào)制解調(diào)器。如果提供了調(diào)制解調(diào)器的能力,大多數(shù)GSM電話都能被使用。SMSLib使用串行連接(物理或模擬,比如藍(lán)牙,紅外線,USB等)來與GSM調(diào)制解調(diào)器通信。通過Nokia 6600, 你可以使用SMSLib來發(fā)送SMS消息,但是因?yàn)镹okia 6600把傳入的消息儲存在記憶卡里而不是SIM卡中,使用這種模式將不能接受到這些消息。同樣,Nokia 6600不允許從記憶卡中使用AT指令來讀取消息。但是,我們僅僅需要發(fā)送SMS消息來激活我們的MIDlet,Nokia 6600能夠成功的完成這些(不需要接收SMS消息)。對于使用紅外線或藍(lán)牙技術(shù)連接的電話來說,最重要的是將紅外線或藍(lán)牙連接映射到一個(gè)虛擬COM端口。參考你的移動電話的文檔,查明它是否支持虛擬COM端口映射。

以我為例,我在我的PC上安裝了Nokia PC 套件。為了從我的PC連接Nokia 6600,我使用一個(gè)外部USB紅外適配器。因此,為了這種情況,我也在PC上安裝了紅外線驅(qū)動。

現(xiàn)在,我用PC上的USB端口連接到外部紅外適配器。在Nokia 6600設(shè)備上,我選擇菜單,然后連接,然后調(diào)制解調(diào)器。通過紅外線連接的選項(xiàng)在調(diào)制解調(diào)器下面。現(xiàn)在,我選擇選項(xiàng)“連接”,并把移動電話放在紅外適配器的有效范圍之內(nèi)。

4.下一步是驗(yàn)證從PC,我們能夠使用AT指令訪問GSM調(diào)制解調(diào)器。為此,選擇開始菜單,然后程序,然后附件,然后通信,然后超級終端。會打開一個(gè)對話框,并請求一個(gè)邏輯名稱。提供任何你愿意提供的名字。為了方便,我提供名字“GSM Modem”。選擇OK。

image
圖16. 打開超級終端

5.另一個(gè)彈出窗口出現(xiàn)。在使用連接的下拉菜單中,選擇COM端口名稱(虛擬的或?qū)嶋H的),GSM調(diào)制解調(diào)器將通過此端口連接到PC。以我為例,是COM4。

image
圖17. 在超級終端中選擇COM端口

6.在下一個(gè)對話框中(COM端口的屬性),只需單擊OK。

7.現(xiàn)在,你會被帶到一個(gè)窗口,你將在此窗口中輸入一些命令(以我們?yōu)槔覀儗⑤斎階T指令)。輸入如下命令來測試連通性-但是記住,當(dāng)你輸入指令的時(shí)候,不會在控制臺中寫入任何東西:AT+CPMS=?。

要點(diǎn):不要在超級終端中輸入任何未知的命令。這可能會永久性損壞你的移動設(shè)備或擦去所有的數(shù)據(jù)。

如果一切順利,你將能看到一些輸出,如圖18所示。輸出可能會不盡相同,但是沒有輸出,輸出錯(cuò)誤,或終端沒有響應(yīng)都代表這連通性的錯(cuò)誤。

image
圖18. 在超級終端中執(zhí)行AT指令

8.現(xiàn)在從呼叫菜單,使用斷開連接命令從超級終端斷開連接。

9.完成了如上的步驟后,我們可以準(zhǔn)備寫Java示例程序了。此程序?qū)l(fā)送SMS消息到我們剛才配置的的GSM調(diào)制解調(diào)器的指定端口上:

import org.smslib.*;

public class SendMessageWithPortsSMSLib {
?? public static void main(String[] args) {
??????CService srv = new CService("COM4", 9600, "", "");
??????System.out.println("SendMessage(): sample application.");
??????System.out.println("??Using " + srv._name + " v" + srv._version);
??????try {
???????? srv.setSimPin("0000");
???????? srv.connect();
???????? srv.setSmscNumber("");
???????? COutgoingMessage msg =
????????????new COutgoingMessage("+9198301...", "Message from smslib API.");
???????? msg.setMessageEncoding(CMessage.MESSAGE_ENCODING_7BIT);
???????? msg.setSourcePort(0);
???????? msg.setDestinationPort(50001);
???????? srv.sendMessage(msg);
???????? srv.disconnect();
??????}
??????catch (Exception e) {
???????? e.printStackTrace();
??????}
??????System.exit(0);
?? }
}


在如上的代碼片斷中,我們首先使用4個(gè)參數(shù)來創(chuàng)建類CService的一個(gè)實(shí)例。第一個(gè)參數(shù)為COM端口的名稱。(以我為例,這里是COM4,因?yàn)槲业腉SM調(diào)制解調(diào)器是連接到一個(gè)虛擬的COM端口的。確保根據(jù)你的COM端口名稱來改變這里的值。)第二個(gè)參數(shù)指定波特率。當(dāng)調(diào)制解調(diào)器連接時(shí)你會發(fā)現(xiàn)這一限制。第三個(gè)參數(shù)指定移動/GSM調(diào)制解調(diào)器的構(gòu)成。第四個(gè)參數(shù)指定模式。在一個(gè)特定的構(gòu)成和模式需要不同的AT指令集來與GSM調(diào)制解調(diào)器交互的地方,第三和第四參數(shù)有時(shí)啟動很重要的作用。例如,對于Sony Ericsson模式,需要一個(gè)不同的AT指令集和邏輯;因此,伴隨著jSMSEngine發(fā)行版,你能找到一個(gè)單獨(dú)的對于Sony Ericsson的處理包。對于特定類型的構(gòu)成和模式,jSMSEngine有不同的處理包。對于Nokia,缺省的處理包對于Nokia 6600 和我們的目的已經(jīng)足夠好了。因此,我沒有對第三和第四個(gè)參數(shù)指定任何值。

CService被初始化之后,我們使用connect()方法連接到GSM調(diào)制解調(diào)器。我們設(shè)置SMSC數(shù)字(SMS中心數(shù)字)為空。這會被SIM卡得到。在那之后,我們使用類CoutgoingMessage()創(chuàng)建一個(gè)發(fā)出的消息。COutgoingMessage()的構(gòu)造函數(shù)需要兩個(gè)參數(shù):發(fā)送消息的設(shè)別數(shù)字和消息本身。在一個(gè)典型的實(shí)際的應(yīng)用程序中,一些類似于數(shù)字代碼的指示符會被作為SMS消息發(fā)送;根據(jù)那個(gè)代碼,在MIDlet端會發(fā)生一些動作。另外一個(gè)要點(diǎn)是setDestinationPort()方法,在這里我們設(shè)定目標(biāo)端口。

圖19展示了詳細(xì)的建立過程。

image
圖19. 詳細(xì)的建立過程

重要注解:SMSLib在CLogger.java中使用了J2SE 5.0的API。CLogger.java中有一行使用PrintStream的構(gòu)造函數(shù),并用java.io.File類型作為參數(shù)。這個(gè)PrintStream類中的構(gòu)造函數(shù)從J2SE 5.0才有支持。但是由于我使用J2SE 1.4,我把那一行從:stream = new PrintStream(new File(filename)); 改成:stream = new PrintStream(new FileOutputStream(filename));

改變之后,我構(gòu)建了SMSLib提供的源代碼,并創(chuàng)建了新的JAR使用JRE 1.4.2。

10.為了編譯示例程序,確保在你的classpath中有新的JAR(是你在修改CLogger代碼后生成的)和comm.jar。然后編譯示例應(yīng)用程序。

11.編譯完成之后,運(yùn)行應(yīng)用程序。確保之前步驟提到的JAR在classpath中。如果一切順利,你能夠看到你安裝在另外一個(gè)設(shè)備中MIDlet已經(jīng)自動啟動了,并顯示你的消息。

現(xiàn)在,讓我們看看如何使用RxTx來代替Java通信API 2.0。你可以從SMSLib下載RxTx。當(dāng)使用RxTx的時(shí)候,我們需要注意如下幾點(diǎn):

1.拷貝RXTXComm.jar到(JDKDIR)\jre\lib\ext目錄,拷貝rxtxSerial.dll文件到(JDKDIR)\jre\bin目錄。
2.為了使用,SMSLib同Java通信API一起打包,但是進(jìn)行一小部分的代碼修改,我們也能讓它跟RxTx一起使用。為了讓SMSLib同RxTx一起使用,修改CSerialDriver.java并刪除行javax.comm.*;。添加行import gnu.io.*;。然后重新生成。
3.RxTx也支持Win32。當(dāng)我寫這篇文章的時(shí)候,RxTx能很好的支持物理串行連接,但是對于“虛擬”串行端口則有些例外,例如,通過藍(lán)牙/紅外線/USB連接模擬串行端口。但是,在顯示生活的情況中,你不會使用一個(gè)移動電話作為調(diào)制解調(diào)器,而是一個(gè)真實(shí)的GSM調(diào)制解調(diào)器,它將通過真實(shí)的COM(串行)端口來連接。這將不會成為問題。現(xiàn)在,以我為例,在發(fā)送SMS消息時(shí)我接受到了一些錯(cuò)誤,因?yàn)槲业募t外線連接有一個(gè)虛擬的端口映射。為了消除那些錯(cuò)誤,我在CSerialDriver中注釋掉了一些行。特別的,找到outStream.flush();,注釋掉,然后重新生成。
4.現(xiàn)在,按照上面列表中的步驟3開始。在步驟11中,確保當(dāng)運(yùn)行SendMessageWithPortsSMSLib的時(shí)候,在你的classpath中有最近生成的JAR(對于RxTx的改變),同時(shí)保證使用RXTXcomm.jar和rxtxSerial.dll文件代替Java通信API的comm.jar和相應(yīng)的dll文件。

注意的要點(diǎn):因?yàn)镾MSLib使用Java通信API,或者RxTx,這些會對操作系統(tǒng)進(jìn)行本地調(diào)用,我建議不要將這些代碼直接嵌入到應(yīng)用程序服務(wù)器或Web服務(wù)器。一個(gè)可選的解決方案是將這些代碼嵌入到一個(gè)單獨(dú)的RMI(遠(yuǎn)程方法調(diào)用)服務(wù)器或Web service服務(wù)器,然后從應(yīng)用服務(wù)器來訪問他。但是,因?yàn)槲覀兪褂肎SM調(diào)制解調(diào)器,SMS的發(fā)送速度很低;所以如果我們直接調(diào)用接口(RMI或Web service),最好使用異步設(shè)計(jì)。例如,當(dāng)你試著發(fā)送一條消息到設(shè)備,將必須的信息(移動號碼,端口,消息等)放到一個(gè)Java消息服務(wù)隊(duì)列中。寫一個(gè)消息驅(qū)動的bean來采集消息,然后使用一個(gè)Web service來調(diào)用服務(wù)(嵌入在SMS發(fā)送代碼中)。

我談到了一種可行的方式;你可以選擇任何最適合你的架構(gòu)的設(shè)計(jì)。但是當(dāng)做任何決定的時(shí)候,緊記如下兩點(diǎn):

使用GSM調(diào)制解調(diào)器,發(fā)送SMS消息的速度不是很快(依賴與你選擇的GSM調(diào)制解調(diào)器和SMS服務(wù)提供商)
SMSLib使用Java通信API或RxTx,這將對操作系統(tǒng)發(fā)生本地調(diào)用

雖然我建議使用兩個(gè)Nokia 6600移動設(shè)置(一個(gè)作為GSM調(diào)制解調(diào)器,另一個(gè)作為Java ME客戶端),你可以僅僅使用一個(gè)來測試此行為。首先,把MIDlet安裝在設(shè)備上。然后使用相同的設(shè)備作為GSM調(diào)制解調(diào)器。當(dāng)發(fā)送SMS消息時(shí),把消息發(fā)送到與你作為發(fā)送消息的GSM調(diào)制解調(diào)器的移動設(shè)備相同的移動號碼上。在這中情況下,發(fā)送者和接收者移動電話是相同的。

總 結(jié)
在這篇文章中,你學(xué)到了如何使用push注冊特征來寫Java ME應(yīng)用程序。同時(shí),你也學(xué)到了如何從服務(wù)器發(fā)送一條SMS消息,然后自動啟動MIDlet。為了僅僅測試push注冊特征,你可以使用兩部支持MIDP 2.0和WMA1.1的手機(jī)(不需要服務(wù)器端SMS push),和Sun Java Wireless Toolkit提供的SMSSend和SMSRecieve示例程序。但是在實(shí)際應(yīng)用程序中,你可能需要從服務(wù)器發(fā)送SMS消息,而不是從另一個(gè)MIDlet。

在本文中展示的代碼片斷不是很復(fù)雜;搭建環(huán)境的步驟卻很復(fù)雜。但是一旦正確地搭建了環(huán)境,你會很興奮的看到使用服務(wù)器端SMS push,push注冊特征在真實(shí)的設(shè)備上運(yùn)行。如果你在使用SMSLib時(shí)遇到任何問題,你總是可以發(fā)布問題和向SMSLib用戶組請求幫助。最后,我要感謝SMSLib項(xiàng)目的所有者Thanasis Delenikas分享了一些關(guān)于SMSLib最近開發(fā)中的有價(jià)值的信息。

關(guān) 于 作 者
Srijeeb Roy擁有印度加爾各答Jadavpur大學(xué)計(jì)算機(jī)科學(xué)和工程學(xué)的學(xué)士學(xué)位。他目前作為技術(shù)架構(gòu)師,在Tata Consultancy Services Limited公司的一個(gè)基于Java EE的項(xiàng)目中工作。他在Java/Java EE的領(lǐng)域中工作了6年以上,在IT工業(yè)擁有總共多余7年的經(jīng)驗(yàn)。他為他的公司和客戶開發(fā)了多個(gè)Java的內(nèi)部框架。他也工作在多個(gè)其他的領(lǐng)域,比如Forte,CORBA和Java ME。

資??源
下載文章中的源代碼:
http://www.javaworld.com/javaworld/jw-04-2006/push/jw-0417-push.zip
下載Sun Java Wireless Toolkit:
http://java.sun.com/products/sjwtoolkit/
下載SMSLib:
http://smslib.org/
RxTx主頁:
http://rxtx.org/