Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 高級開發 >> Android中WAP PUSH的實現分析

Android中WAP PUSH的實現分析

編輯:高級開發

1 WAP PUSH 流程簡介

  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>

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved