Android中WAP PUSH的实现分析

1 WAP PUSH 流程简介

WAP Push分为两种:SI(Service Initiate) 和SL(Service Load)。都是服务器端向客户端推送消息的一种方式。

SI是服务器通过网关采用OTA协议把信息发送到手机,手机存储解析并存储信息,然后提示给用户。

在接收到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>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值