Push注冊機制介紹
MIDP2.0引入了Push注冊機制,作為一種允許應用被自動啟動的方法,由預先設置的警告或者經inbound連接收到的消息。
通過這種方法,MIDlets可以用來設置處理規則事件,如定時從服務器上同步數據,或者非規則事件如一個突來的消息。
Push注冊機制由Javax.microedtion.io.PushRegistry類管理,它還是應用程序管理系統——它處理所有事件——的一部分。
警告事件通過指定MIDlet名稱和啟動時間進行注冊。對於任何MIDlet只能注冊一個警告事件,因此注冊一個新的警告會重寫注冊機制中以前的任何警告。這種情況可以被檢測到,因為若原來存在警告,注冊方法會返回被重寫的警告的時間。
無線消息API(Wireless Messaging API)可以和Push注冊機制聯合使用,通過消息監聽器來處理到來的消息,消息監聽器實現在AMS啟動MIDlet後處理消息有效載荷的邏輯。在這種情況下,MIDlet會注冊一個特定的端口號和消息類型作為啟動MIDlet的觸發器,AMS監視端口的行為,以尋找在該端口上的正確網絡請求。另外,注冊的連接可能被過濾,允許MIDlet指定只有來自特定服務器的連接作為啟動MIDlet的觸發器。
使用Push注冊機制的效果
如果警告到來時,注冊了這個警告的MIDlet正在運行中,那麼這個MIDlet會繼續運行,而警告會被忽略。如果MIDlet沒有運行,它就會被啟動。
類似地,如果inbound連接出現時,而注冊了這個連接的MIDlet也已經在運行中,MIDlet會處理那個連接(若代碼指定了,就包括任何消息的有效載荷),就不再提交給用戶。
如果沒有MIDlet在運行中,用戶會收到消息的通知,並且會被給予是否運行MIDlet的選擇。
如果另外一個MIDlet在運行中,用戶會被給予是否運行與這個消息相關的MIDlet的選擇:若選擇運行,就會終止當前運行的MIDlet。
如果收到多個消息,AMS會排隊等候到5,並且傳遞要讀取的選擇,依順序按消息進行操作,包括聯合push動作。
如果沒有應用程序被注冊為push,到來的push消息會被忽略。
方法
PushRegistry類包含了以下的方法:
l getFilter(),為連接返回一個<AllowedSender>值(可能是一個服務器IP地址、一個以逗號分割的IP地址列表,或者一個“*”表示允許任何連接)。
l getMidlet(),返回為特定的連接注冊的MIDlet名稱。
l listConnections(),返回為特定的MIDlet套件push連接列表。
l registerAlarm(),注冊一個基於定時器的觸發器來啟動MIDlet,或者若變量被設置為0,則取消對MIDlet已經存在的警告
l registerConnection(),為MIDlet注冊一個連接
l unregisterConnection(),同樣取消一個連接的注冊
異常
應該捕獲異常有:
ClassNotFoundException、ConnectionNotFoundException、IllegalArgumetException、IOException和SecurityException。
ConnectionNotFoundException和IOException可能遇到,因為請求端口或者連接類型可能不會連續可用,因此應該為這種情況編寫處理代碼。
網絡連接和push注冊機制是特別的操作,MIDlet在使用它們之前必須有正確的許可,因此需要捕獲SecurityException。
連接(Connection)
連接包括三種類型:TCP Socket,UDP數據包或者SMS。
當前在所有的Motorola手機范圍內,只有SMS是適合於inbound連接的可用類型。UDP數據包只能用於最新的手機(2005年後半年發行的,例如,V3X、E1070,等等)。從這點出發,這篇文章將不會講解TCP Socket,而對UDP數據包也只是有少許講解。
使用SMS連接
注意到以下的這點是很有用的,如果需要進一步的數據交換,在被到來的消息喚醒後,MIDlet可以初始化一個Socket或者HTTP連接。
指定的端口可以是從1到65535的范圍中的任何一個,然而下面的端口是被保留的,必須不能使用:
2805 WAP WTA安全非連接會話服務
2923 WAP WTA 安全會話服務
2948 WAP Push無連接會話服務(客戶端)
2949 WAP Push安全無連接會話服務(客戶端)
5502 Service Card Reader
5503 因特網訪問配置閱讀器
5508 動態菜單控制協議(Dynamic Menu Control Protocol)
5511 消息訪問協議(Message Access Protocol)
5512 簡單郵件通知(Simple e-mail 通知)
9200 WAP無連接會話服務
9201 WAP會話服務
9202 WAP安全無連接會話服務
9203 WAP安全會話服務
9207 WAP vCal安全
49996 SyncML OTA 配置
49999 WAP OTA配置
注意:上面的端口號不能注冊為任何其它類型的動作,否則注冊請求會失敗。參考JSR 120無線消息API(Wireless Messaging API),
使用數據包連接
開發者必須清楚,網絡上的限制條件可能會阻礙傳遞給一個正在監聽的設備的UDP/IP數據包通信量。
大部分的操作者使用DHCP(Dynamic Host Configuration Protocol, 動態主機配置協議)只為活動的用戶分配IP地址。一個活動的用戶可以是一個啟動網絡應用程序的用戶,或者是使手機建立PDP上下文的浏覽器,如果沒有建立的PDP上下文,你也不可能擁有任何IP地址。
另外,你的移動設備被(操作者)分配的實際的IP地址很可能是10.x.x.x或者192.168.x.x等保留范圍中一個,針對這些保留IP范圍的規范就是任何外部的路由器遇到這個IP地址時會丟棄數據包不再發送。
當然,也有一些情況會按照預期工作,但是最可靠的選擇是使用SMS作為MIDlet觸發器,那麼MIDlet應該建立一個支持的連接以得到預期的數據。
使用警告
警告由完整的MIDlet名稱和一個與Date.getTime()方法得到整數同樣格式的長整數(自從1970年1月1號到現在的毫秒數)指定。
注冊
Push注冊機制可以處理請求來注冊連接通過兩種方式:運行時的動態注冊和JAD文件中條目靜態注冊。
動態注冊
動態注冊是一個MIDlet在運行時通知AMS,它希望被到來的網絡連接激活或者警告事件,MIDlet應該先於事件發生退出。
注冊連接,要使用registerConnection方法:
registerConnection(String connection, String midlet, String filter)
並且可以使用this.getClass().getName()指定當前的MIDlet.
注冊警告,要使用registerAlarm方法:
registerAlarm(String midlet, long time)
並且now.getTime() + (1000 * 60 * 60)可以被用來指定警告時間,從現在開始一個小時(以毫秒形式)。
動態注冊例子:
registerConnection(“sms://:” + portNumber);
registerConnection(“datagram://:” + protNumber);
靜態注冊
如果一個連接發送者和連接類型在MIDlet安裝時可以知道,注冊請求在安裝時完成,因此被認為靜態的。靜態請求在JAD文件中使用Midlet-Push-<n>屬性定義:
MIDlet-Push-<n>: <ConnectionURL>, <MIDletClassName>, <AllowedSender>
n是一個順序數,允許聲明多於一個連接,ConnectionURL是用來監視到來的連接的URL,MIDletClassName是要啟動的MIDlet,AllowedSender是過濾器:IP地址列表或者“*”(任意地址)。SMS連接的例子:
MIDlet-Push-1: sms://:10000, TestMIDlet, *
數據包例子:
MIDlet-Push-2: datagram://:50000, TestMIDlet, *
“*”在IP地址中也可以用作通配符,所以像142.100.200.*或者142.*也可以用來指定地址組。
警告必須要動態注冊,那麼就沒有靜態注冊的等價物。
取消注冊
動態注冊可以通過使用unregisterConnection移除,只需要指定連接:
unregisterConnection(“sms://:
靜態注冊只有在安裝時可被改變,因此順序是卸載MIDlet,改變JAD屬性然後重新安裝MIDlet。卸載MIDlet總是會移除所有靜態注冊。
例子
為了確定MIDlet是否被到來的信息調用:
在startApp():
String connectsFound[];
connectsFound = PushRegistry.listConnections(true);
上面的代碼返回注冊的連接列表。
if (connectsFound == null || connectsFound.length == 0)
{
~由用戶啟動、編碼來推出或者忽略push相關動作~
}
else
{
~由inbound連接啟動,因此編碼為Push注冊機制初始化~
}
為了定時一個警告動作
在這個線程入口點的run()方法中:
private void scheduleMIDlet(long targettime)
throws ClassNotFoundException, ConnectionNotFoundException, SecurityException
{
String md = this.getClass().getName();
Date alarm = new Date();
long tm = PushRegistry.registerAlarm(md, alarm.getTime() + targettime);
在清除和釋放資源後destroyApp():
scheduleMIDlet(defaultDeltaTime);