天天看點

Android推送方式比較(轉)

推送方式的基礎知識

  當我們開發需要和伺服器互動的應用程式時,基本上都需要擷取伺服器端的資料,比如《地震及時通》就需要及時擷取伺服器上最新的地震資訊。要擷取伺服器 上不定時更新的資訊一般來說有兩種方法,第一種是用戶端使用Pull(拉)的方式,隔一段時間就去伺服器上擷取資訊,看是否有更新的資訊出現。第二種就是 伺服器使用Push(推送)的方式,當伺服器端有新資訊了,則把最新的資訊Push到用戶端上。

  雖然Pull和Push兩種方式都能實作擷取伺服器端更新資訊的功能,但是明顯來說Push is better than pull。因為Pull方式更費用戶端的網絡流量,更主要的是費電量。

  在開發Android和iPhone應用程式時,我們往往需要從伺服器不定的向手機用戶端即時推送各種通知消息,iPhone上已經有了比較簡 單的和完美的推送通知解決方案,可是Android平台上實作起來卻相對比較麻煩,最近利用幾天的時間對Android的推送通知服務進行初步的研究。

  在Android手機平台上,Google提供了C2DM(Cloudto Device Messaging)服務,起初我就是準備采用這個服務來實作自己手機上的推送功能。

  Android Cloud to Device Messaging (C2DM)是一個用來幫助開發者從伺服器向Android應用程式發送資料的服務。該服務提供了一個簡單的、輕量級的機制,允許伺服器可以通知移動應用 程式直接與伺服器進行通信,以便于從伺服器擷取應用程式更新和使用者資料。C2DM服務負責處理諸如消息排隊等事務并向運作于目标裝置上的應用程式分發這些 消息。

C2DM操作過程圖:

Android推送方式比較(轉)

但是經過一番研究發現,這個服務存在很大的問題:

1)C2DM内置于Android的2.2系統上,無法相容老的1.6到2.1系統;

2)C2DM需要依賴于Google官方提供的C2DM伺服器,由于國内的網絡環境,這個服務經常不可用,如果想要很好的使用,我們的App Server必須也在國外,這個恐怕不是每個開發者都能夠實作的;

  有了上述兩個使用上的制約,導緻我最終放棄了這個方案,不過我想利用另外一篇文章來詳細的介紹C2DM的架構以及用戶端和App Server的相應設定方法,可以作為學習與參考之用。

  即然C2DM無法滿足我們的要求,那麼我們就需要自己來實作Android手機用戶端與App Server之間的通信協定,保證在App Server想向指定的Android裝置發送消息時,Android裝置能夠及時的收到。下面我來介紹幾種常見的方案:

1)輪詢(Pull):應用程式應當階段性的與伺服器進行連接配接并查詢是否有新的消息到達,你必須自己實作與伺服器之間的通信,例如消息排隊等。而且你還要考慮輪詢的頻率,如果太慢可能導緻某些消息的延遲,如果太快,則會大量消耗網絡帶寬和電池。

2)SMS(Push):在Android平台上,你可以通過攔截SMS消息并且解析消息内容來了解伺服器的意圖。這是一個不錯的想法,我就見過采 用這個方案的應用程式。這個方案的好處是,可以實作完全的實時操作。但是問題是這個方案的成本相對比較高,你很難找到免費的短消息發送網關,關于這個方案 的實作。

3)持久連接配接(Push):這個方案可以解決由輪詢帶來的性能問題,但是還是會消耗手機的電池。Apple的推送服務之是以工作的很好,是因為每一 台手機僅僅保持一個與伺服器之間的連接配接,事實上C2DM也是這麼工作的。不過這個方案也存在不足,就是我們很難在手機上實作一個可靠的服務。 Android作業系統允許在低記憶體情況下殺死系統服務,是以你的通知服務很可能被作業系統Kill掉了。

  前兩個方案存在明顯的不足,第三個方案也有不足,不過我們可以通過良好的設計來彌補,以便于讓該方案可以有效的工作。畢竟,我們要知道GMail,GTalk以及GoogleVoice都可以實作實時更新的。

采用MQTT協定實作Android推送

  MQTT是一個輕量級的消息釋出/訂閱協定,它是實作基于手機用戶端的消息推送伺服器的理想解決方案。

wmqtt.jar 是IBM提供的MQTT協定的實作。你可以從如下站點下載下傳它。你可以将該jar包加入你自己的Android應用程式中。

Really Small Message Broker (RSMB) ,他是一個簡單的MQTT代理,同樣由IBM提供。預設打開1883端口,應用程式當中,它負責接收來自伺服器的消息并将其轉發給指定的移動裝置。

采用XMPP協定實作Android推送

  這是我在項目中采用的方案。事實上Google官方的C2DM伺服器底層也是采用XMPP協定進行的封裝。

  XMPP(可擴充通訊和表示協定)是基于可擴充标記語言(XML)的協定,它用于即時消息(IM)以及線上探測。這個協定可能最終允許網際網路使用者向網際網路上的其他任何人發送即時消息。

  androidpn是一個基于XMPP協定的java開源Android push notification實作。它包含了完整的用戶端和伺服器端。經過源代碼研究我發現,該伺服器端基本是在另外一個開源工程openfire基礎上修改實作的,不過比較郁悶的是androidpn的文檔是由韓語寫的,是以整個研究過程基本都是讀源碼。

  androidpn 用戶端需要用到一個基于java的開源XMPP協定包asmack,這個包同樣也是基于openfire下的另外一個開源項目smack,不過我們不需要 自己編譯,可以直接把androidpn用戶端裡面的asmack.jar拿來使用。用戶端利用asmack中提供的XMPPConnection類與服 務器建立持久連接配接,并通過該連接配接進行使用者注冊和登入認證,同樣也是通過這條連接配接,接收伺服器發送的通知。

  androidpn伺服器端也是java語言實作的,基于openfire開源工程,不過它的Web部分采用的是spring架構,這一點與 openfire是不同的。Androidpn伺服器包含兩個部分,一個是偵聽在5222端口上的XMPP服務,負責與用戶端的 XMPPConnection類進行通信,作用是使用者注冊和身份認證,并發送推送通知消息。另外一部分是Web伺服器,采用一個輕量級的HTTP伺服器, 負責接收使用者的Web請求。伺服器架構如下:

  最上層包含四個組成部分,分别是SessionManager,Auth Manager,PresenceManager以及Notification Manager。SessionManager負責管理用戶端與伺服器之間的會話,Auth Manager負責用戶端使用者認證管理,Presence Manager負責管理用戶端使用者的登入狀态,NotificationManager負責實作伺服器向用戶端推送消息功能。

  這個解決方案的最大優勢就是簡單,我們不需要象C2DM那樣依賴作業系統版本,也不會擔心某一天Google伺服器不可用。利用XMPP協定我們還可以進一步的對協定進行擴充,實作更為完善的功能。

  采用這個方案,我們目前隻能發送文字消息,不過對于推送來說一般足夠了,因為我們不能指望通過推送得到所有的資料,一般情況下,利用推送隻是告訴手機端伺服器發生了某些改變,當用戶端收到通知以後,應該主動到伺服器擷取最新的資料,這樣才是推送服務的完整實作。

總結

  現在使用XMPP協定進行推送的方式慢慢多了,主要是原因是比較簡單,我後面的博文将會寫一些相關androidpn伺服器的内容。本人的其中一個軟 件<足球即時比分>,計劃進行更新,從之前的拉(Pull)方式改為 推(Push)方式,我相信這樣将會減小伺服器的壓力,并且比分更新将會更新加及時。