編輯:高級開發
WAP Push分為兩種:SI(Service Initiate) 和SL(Service Load)。都是服務器端向客戶端推送消息的一種方式。
先看SI:
‘圖發不上來’
圖1.1
服務器通過網關采用OTA協議把信息發送到手機,手機存儲解析並存儲信息,然後提示給用戶。
而SL流程如下:
‘圖發不上來’
圖1.2
在接收到SL消息後,同樣也會存儲並提示用戶(視情況具體對待),區別在於客戶端會主動調用浏覽器打開SL中附帶的連接。
2 WAP PUSH消息體剖析
下面我們以SL為例,來看看WAP PUSH的消息。
一個SL的WAP PUSH消息主體大致如下:
< !--
Service Loading (SL) Document Type Definition.
SL is an XML language. Typical usage:
< ?XML version="1.0"?>
< !DOCTYPE sl PUBLIC "-//WAPFORUM//DTD SL 1.0//EN"
"http://www.wapforum.org/DTD/sl.dtd">
< sl>
href %URI; #REQUIRED
action (execute-low|execute-high|cache) "execute-low"
< /sl>
大家都看到了,其實內容很少,包括一個連接和一個action控制執行的優先級。
由於考慮到節約網絡數據的傳輸,往往都是將這些文本轉化為WBXML格式再進行傳輸。WBXML是一種壓縮的二進制表示方式,有嚴格的定義。對於標簽和屬性,定義如下表:
Tag Name Token
sl 5
Attribute Name Attribute Value Prefix Token
action execute-low 5
action execute-high 6
action cache 7
href 8
href http:// 9
href http://www. A
href https:// B
href https://www. C
Attribute Value Token
.com/ 85
.edu/ 86
.Net/ 87
.org/ 88
文本中的對應Tag和Attribute value會被Token代替,以減少文本大小。我們看下面一段內容:
< ?XML version="1.0"?>
< !DOCTYPE sl PUBLIC "-//WAPFORUM//DTD SL 1.0//EN"
"http://www.wapforum.org/DTD/sl.dtd">
接上頁
< sl href="http://www.xyz.com/ppaid/123/abc.wml">< /sl>
總共有159個字節。
我們使用WBXML格式來表示,如下表對應關系:
Token Stream Description
02 Version number - WBXML version 1.2
06 SL 1.0 Public IdentifIEr
6A Charset=UTF-8 (MIBEnum 106)
00 String table length
05 sl, with attributes
0A Token for "href="http://www."
03 Inline string follows
‘x’, ‘y’, ‘z’, 00 String
85 Token for ".com/"
03 Inline string follows
‘p’, ‘p’, ‘a’, ‘i’, ‘d’, ‘/’, ‘1’, ‘2’, ‘3’, ‘/’, ‘a’, ‘b’, ‘c’, ‘.’, ‘w’, ‘m’, ‘l’, 00 String
01 END (of sl attribute list)
這樣一來,就是:
02 06 6A 00 05 0A 03 'x' 'y' 'z' 00 85 03 'p' 'p' 'a'
'i' 'd' '/' '1' '2' '3' '/' 'a' 'b' 'c' '.' 'w' 'm' 'l' 00 01
總共才需要32個字節, 大大減少了數據量。
以上的只是消息主體內容,在傳輸過來的時候,還需要加上一些附加的信息,如
mimeType: 表示是SI還是SL, application/vnd.wap.sic或者 application/vnd.wap.slc (text/vnd.wap.sl).
transactionId: 用於分段發送大數據量的消息, 這些消息具有相同的trasactionId.
pduType: 未識別
header: 附加信息,用於標示特定的業務。
3 android中解析WAP PUSH
按照以上所述,網絡傳輸過來的是WBXML數據,通常我們需要按照Token表對應的進行解析,才可以得到XML格式的正文,從而獲取href和 action。 慶幸的是android中在framework層的WapPushOverSms.Java中已經完成了對消息的部分解析,把mimeType, trasactionId, pduType, header 和 data分離出來,放在intent的傳遞參數中了。看以下代碼:
private void dispatchWapPdu_PushCO(byte[] pdu, int transactionId, int pduType,
int headerStartIndex, int headerLength) {
byte[] header = new byte[headerLength];
System.arraycopy(pdu, headerStartIndex, header, 0, header.length);
接上頁
Intent intent = new Intent(Intents.WAP_PUSH_RECEIVED_ACTION);
intent.setType(WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_CO);
intent.putExtra("transactionId", transactionId);
intent.putExtra("pduType", pduType);
intent.putExtra("header", header);
intent.putExtra("data", pdu);
mSmsDispatcher.dispatch(intent, "android.permission.RECEIVE_WAP_PUSH");
}
我們在應用層只需要添加對WAP_PUSH_RECEIVED_ACTION的監聽,便可獲取到這個WAP PUSH。 下面以接收中國移動DCD業務的WAP PUSH為例,看看是如何實現的。
需要寫一個DcdWapPushReceiver.Java:
public class DcdWapPushReceiver extends BroadcastReceiver {
private static final String LOGTAG = "DcdPushReceiver";
public static final String CONTENT_MIME_TYPE_B_PUSH_SL = "application/vnd.wap.slc";
public static final String APPLICATION_DCD_ID = "application/x-oma-DCD:DCD.ua";
public void onReceive(Context context, Intent intent) {
//only deal with SL WAP PUSH
if (intent.getAction().equals(WAP_PUSH_RECEIVED_ACTION)
&& CONTENT_MIME_TYPE_B_PUSH_SL.equals(intent.getType())) {
// Start a new AsyncTask to process the data.
if (APPLICATION_DCD_ID.equals(getAppIdFromIntent(intent))) {
new ReceivePushTask(context).execute(intent);
}
}
}
/*
* get application id from intent header.
* < ==header sample==>
* B0 B4 87 AF application/x-oma-DCD:DCD.ua 00 Encoding-Version 00
*/
public static String getAppIdFromIntent(Intent intent) {
byte[] header = intent.getByteArrayExtra("header");
if (header == null) {
return null;
}
String str = new String(header);
int start = str.indexOf("application/");
if (start > 0) {
接上頁
//application id end with 00.
int end = str.indexOf(0x00);
if (end > 0) {
str = str.substring(start, end);
return str;
}
}
return null;
}
private class ReceivePushTask extends AsyncTask< Intent, Void, Void> {
private Context mContext;
public ReceivePushTask(Context context) {
mContext = context;
}
protected Void doInBackground(Intent... intents)
{
Intent intent = intents[0];
// step1. obtain wbXML data from intent.
byte[] pushData = intent.getByteArrayExtra("data");
String wbXMLData = "";
for (byte by: pushData) {
wbxmlData = wbXMLData + by + " ";
}
Debug.print("wap push data = "+wbXMLData);
// step2. pass the data to WapPushParser and get the parsing result.
DcdWapPushParser parser = new DcdWapPushParser(pushData);
DcdWapPushMsg pushMsg = null;
if (CONTENT_MIME_TYPE_B_PUSH_SL.equals(intent.getType())) {
pushMsg = parser.parse(DcdWapPushMsg.WAP_PUSH_TYPE_SL);
}
if (null == pushMsg) {
Debug.error("Invalid WAP PUSH data");
return null;
}
//get href
String href = pushMsg.getAttributeValueString(DcdWapPushMsg.WAP_PUSH_PROJECTION_HREF);
Debug.print("href = " + href);
Intent i = new Intent(mContext, DcdCmService.class);
//step3. sync invoked by wap push, so set sync type to SVR
//i.putExtra("syncType", DcdCmService.SYNC_TYPE_SVR);
//i.putExtra("href", href);
Bundle bundle = new Bundle();
bundle.putBoolean(DcdCmService.NOTIFICATION_WAPPUSH, true);
bundle.putString("syncType", DcdRequest.REQUEST_TYPE_SVR);
bundle.putString("href", href);
接上頁
i.putExtras(bundle);
//start sync service
mContext.startService(i);
return null;
}
}
}
在androidManifest.XML中注冊這個接收器:
< receiver android:name=".contentmanager.DcdWapPushReceiver">
< intent-filter>
< action android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" />
< data android:mimeType="application/vnd.wap.slc" />
< /intent-filter>
< /receiver>
android下一代版本蜂巢(Honeycomb)到底是Android 2.4還是android 3.0呢?到目前為止這種爭論可以告一段落了。近日,可能是受到蜂巢(Ho
繼PHP for android實現之後,微軟.Net for android,也就是MonoDroid,也將馬上進入Beta測試階段,最終的MonoDroid產品將在
在做android游戲MagicBubble開發的時候,在連通兩個Bubbles的時候,Bubble會以水泡爆破的情形消失。筆者的思路是這樣的:在FrameLayout
很多人對android2.0已經十分期待了,鑒於強大的功能性以及快速。android未來的市場將是十分廣闊的。搭載Android2.0源碼的摩托羅拉Droid手機已經上