Android實現推送方式解決方案 - 長鏈接+心跳機制(MQTT協議)

本文介紹在Android中實現推送方式的基礎知識及相關解決方案。推送功能在手機開發中應用的場景是越來起來了,不說別的,就咱們手機上的新聞客戶端就時不j時的推送過來新的消息,很方便的閱讀最新的新聞信息。這種推送功能是好的一面,可是也會常常看到不少推送過來的垃圾信息,這就讓咱們感到厭煩了,關於這個咱們就不能多說什麼了,畢竟不少商家要作廣告。本文就是來探討下Android中實現推送功能的一些解決方案,也但願可以起到拋磚引玉的做用。^_^php

 

  1.推送方式基礎知識: html

  在移動互聯網時代之前的手機,若是有事情發生須要通知用戶,則會有一個窗口彈出,將告訴用戶正在發生什麼事情。多是未接電話的提示,日曆的提醒,或是一封新的彩信。推送功能最先是被用於Email中,用來提示咱們新的信息。因爲時代的發展和移動互聯網的熱潮,推送功能更加地普及,已經再也不僅僅用在推送郵件了,更多地用在咱們的APP中了。java

 

  當咱們開發須要和服務器交互的應用程序時,基本上都須要獲取服務器端的數據,好比《地震應急通》就須要及時獲取服務器上最新的地震信息。要獲取服務器上不定時更新的信息,通常來講有兩種方法:第一種是客戶端使用Pull(拉)的方式,就是隔一段時間就去服務器上獲取一下信息,看是否有更新的信息出現。第二種就是 服務器使用Push(推送)的方式,當服務器端有新信息了,則把最新的信息Push到客戶端上。這樣,客戶端就能自動的接收到消息。 android

 

  雖然Pull和Push兩種方式都能實現獲取服務器端更新信息的功能,可是明顯來講Push方式比Pull方式更優越。由於Pull方式更費客戶端的網絡流量,更主要的是費電量,還須要咱們的程序不停地去監測服務端的變化。  git

 

  在開發Android和iPhone應用程序時,咱們每每須要從服務器不定的向手機客戶端即時推送各類通知消息。咱們只須要在Android或IPhone的通知欄處向下一拉,就展開了Notification Panel,能夠集中一覽各類各樣通知消息。目前IOS平臺上已經有了比較簡單的和完美的推送通知解決方案,我會在之後詳細介紹IPhone中的解決方案,但是Android平臺上實現起來卻相對比較麻煩。github

  最近利用幾天的時間對Android的推送通知服務進行初步的研究,也但願能和你們共同探討一下。spring

 

  2. 幾種常見的解決方案實現原理:api

  1)輪詢(Pull)方式:應用程序應當階段性的與服務器進行鏈接並查詢是否有新的消息到達,你必須本身實現與服務器之間的通訊,例如消息排隊等。並且你還要考慮輪詢的頻率,若是太慢可能致使某些消息的延遲,若是太快,則會大量消耗網絡帶寬和電池。服務器

 

  2)SMS(Push)方式:在Android平臺上,你能夠經過攔截SMS消息而且解析消息內容來了解服務器的意圖,並獲取其顯示內容進行處理。這是一個不錯的想法,我就見過採用這個方案的應用程序。這個方案的好處是,能夠實現徹底的實時操做。可是問題是這個方案的成本相對比較高,咱們須要向移動公司繳納相應的費用。咱們目前很難找到免費的短消息發送網關來實現這種方案。微信

 

  3)持久鏈接(Push)方式:這個方案能夠解決由輪詢帶來的性能問題,可是仍是會消耗手機的電池。IOS平臺的推送服務之因此工做的很好,是由於每一臺手機僅僅保持一個與服務器之間的鏈接,事實上C2DM也是這麼工做的。不過剛纔也講了,這個方案存在着不少的不足之處,就是咱們很難在手機上實現一個可靠的服務,目前也沒法與IOS平臺的推送功能相比。

 

  Android操做系統容許在低內存狀況下殺死系統服務,因此咱們的推送通知服務頗有可能就被操做系統Kill掉了。 輪詢(Pull)方式和SMS(Push)方式這兩個方案也存在明顯的不足。至於持久鏈接(Push)方案也有不足,不過咱們能夠經過良好的設計來彌補,以便於讓該方案能夠有效的工做。畢竟,咱們要知道GMail,GTalk以及GoogleVoice均可以實現實時更新的。

  

  3.第一種解決方案:C2DM雲端推送功能。

  在Android手機平臺上,Google提供了C2DM(Cloudto Device Messaging)服務,起初我就是準備採用這個服務來實現本身手機上的推送功能,並將其帶入本身的項目中。 

 

  Android Cloud to Device Messaging (C2DM)是一個用來幫助開發者從服務器向Android應用程序發送數據的服務。該服務提供了一個簡單的、輕量級的機制,容許服務器能夠通知移動應用程序直接與服務器進行通訊,以便於從服務器獲取應用程序更新和用戶數據。C2DM服務負責處理諸如消息排隊等事務並向運行於目標設備上的應用程序分發這些消息。關於C2DM具體使用過程,你們能夠去查閱相關的資料,在這裏先讓咱們瞭解下大體方案狀況。

 

  下面是C2DM操做過程示例圖:

   

 

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

  1)C2DM內置於Android的2.2系統上,沒法兼容老的1.6到2.1系統;

 

  2)C2DM須要依賴於Google官方提供的C2DM服務器,因爲國內的網絡環境,這個服務常常不可用,若是想要很好的使用,咱們的App Server必須也在國外,這個恐怕不是每一個開發者都可以實現的;

 

  3) 不像在iPhone中,他們把硬件系統集成在一塊了。因此對於咱們開發者來講,若是要在咱們的應用程序中使用C2DM的推送功能,由於對於不一樣的這種硬件廠商平臺,好比摩托羅拉、華爲、中興作一個手機,他們可能會把Google的這種服務去掉,尤爲像在國內就不少這種,把Google這種原生的服務去掉。買了一些像什麼山寨機或者是華爲這種國產機,可能Google的服務就沒有了。而像在國外出的那些可能會內置。

 

  有了上述幾個方面的制約,致使我最終放棄了這個方案,不過我想利用另一篇文章來詳細的介紹C2DM的框架以及客戶端和App Server的相應設置方法,能夠做爲學習資源讓咱們有個參考的資料。 即然C2DM沒法知足咱們的要求,那麼咱們就須要本身來實現Android手機客戶端與App Server之間的通訊協議,保證在App Server想向指定的Android設備發送消息時,Android設備可以及時的收到。

 

  4. 第二種解決方案:MQTT協議實現Android推送功能。

  採用MQTT協議實現Android推送功能也是一種解決方案。MQTT是一個輕量級的消息發佈/訂閱協議,它是實現基於手機客戶端的消息推送服務器的理想解決方案。

  wmqtt.jar 是IBM提供的MQTT協議的實現。咱們能夠從這裏https://github.com/tokudu/AndroidPushNotificationsDemo)下載該項目的實例代碼,而且能夠找到一個採用PHP書寫的服務器端實現https://github.com/tokudu/PhpMQTTClient)。

 

  架構以下圖所示:

      

 

  wmqtt.jar 是IBM提供的MQTT協議的實現。咱們能夠從以下站點下載http://www-01.ibm.com/support/docview.wss?rs=171&uid=swg24006006)它。咱們能夠將該jar包加入本身的Android應用程序中。

 

  5.第三種解決方案:RSMB實現推送功能。

  Really Small Message Broker (RSMB) ,他是一個簡單的MQTT代理,一樣由IBM提供,其查看地址是:http://www.alphaworks.ibm.com/tech/rsmb。缺省打開1883端口,應用程序當中,它負責接收來自服務器的消息並將其轉發給指定的移動設備。

 

  SAM是一個針對MQTT寫的PHP庫。咱們能夠從這個http://pecl.php.net/package/sam/download/0.2.0地址下載它.

  send_mqtt.php是一個經過POST接收消息而且經過SAM將消息發送給RSMB的PHP腳本。 

 

  6. 第四種解決方案:XMPP協議實現Android推送功能。

  這是我但願在項目中採用的方案,由於目前它是開源的,對於其簡單的推送功能它仍是可以實現的。咱們能夠修改其源代碼來適應咱們的應用程序。

  事實上Google官方的C2DM服務器底層也是採用XMPP協議進行的封裝。XMPP(可擴展通信和表示協議)是基於可擴展標記語言(XML)的協議,它用於即時消息(IM)以及在線探測。這個協議可能最終容許因特網用戶向因特網上的其餘任何人發送即時消息。關於XMPP協議我在上篇博文中已經介紹,你們能夠參考下文章:http://www.cnblogs.com/hanyonglu/archive/2012/03/04/2378956.html

 

  androidpn是一個基於XMPP協議的java開源Android push notification實現,我會在之後的博文中詳細介紹androidpn。它包含了完整的客戶端和服務器端。通過源代碼研究我發現,該服務器端基本是在另一個開源工程openfire基礎上修改實現的,不過比較鬱悶的是androidpn的文檔是由韓語寫的,因此整個研究過程基本都是讀源碼。

 

  這是androidpn的項目主頁:http://sourceforge.net/projects/androidpn/

 

  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也存在一些不足之處:

  1. 好比時間過長時,就再也收不到推送的信息了。

  2. 性能上也不夠穩定。

    3. 若是將消息從服務器上推送出去,就再也不管理了,無論消息是否成功到達客戶端手機上。

 

  等等,總之,androidpn也有不少的缺點。若是咱們要使用androidpn,則還須要作大量的工做。

  至於詳細使用過程,咱們會在下個博文中再給你們介紹。

 

  7.第五種解決方案:使用第三方平臺。

  第三方平臺有商用的也有免費的,咱們能夠根據實現狀況使用。關於國內的第三方平臺,我感受目前比較不錯的就是極光推送。關於極光推送目前是免費的,咱們能夠直接使用。關於詳細狀況,你們能夠查看它的主頁:http://www.jpush.cn/index.jsp,這裏再也不詳細描述。

  

  關於國外的第三方平臺我也見過幾個:http://www.push-notification.org/。有興趣的朋友能夠查閱相關信息。使用第三方平臺就須要使用別人的服務器,關於這點,你懂的。

 

  8.第六種解決方案:本身搭建一個推送平臺。

  這不是一件輕鬆的工做,固然能夠根據各自的須要採起合適的方案。

 

  好了,以上是關於在Android中實現推送方式的基礎知識及相關解決方案。

參考:

 

http://www.infoq.com/cn/articles/baidu-android-cloud-push

http://www.cnblogs.com/hanyonglu/archive/2012/03/04/2378971.html

 

1、推送服務簡介

 

消息推送,顧名思義,是由一方主動發起,而另外一方與發起方以某一種方式創建鏈接並接收消息。在Android開發中,這裏的發起方咱們把它叫作推送服務器(Push Server),接收方叫作客戶端(Client)。相比經過輪詢來獲取新消息或通知,推送不管是在對客戶端的資源消耗仍是設備耗電量來講都比輪詢要好,因此,目前絕大多數須要及時消息推送的App都採用Push的方式來進行消息通知。

push

身在天朝,置身牆內!Android生態系統本來提供了相似於Apple iOS推送服務APNSGCM(Google Cloud Messaging for Android),之前叫C2DM,可是因爲某些緣由,致使這項服務在國內不是很好使,爲了彌補這個不足,而且我朝各大同胞又想使用Android推送服務,因此國內各大平臺陸續推出了GCM的替代品,今天要介紹的就是其中一家,由百度提供的雲推送。另外,國內作消息推送服務的還有極光推送和個推等,他們的客戶包括新浪微博、淘寶等國內一線大公司。

推送的實現技術簡單來講就是利用Socket維持Client和Server間的一個TCP長鏈接,經過這種方式能大大下降由輪詢方式帶來的Device的耗電量和數據訪問流量。目前,百度雲推送提供的推送服務支持的單一消息體大小是4k,若是超過4k,則建議在消息內攜帶服務請求URL進行二次請求。目前,百度雲推送針對Android端提供通知推送,文本消息推送以及富媒體推送。

2、使用場景

1. 單播消息推送

Push Server向指定的設備(Device)或是用戶(User)推送消息,一個用戶對應一個userID,一個User可能擁有多臺Device,咱們但願向同一個userID推送消息時,他全部綁定了userID的Device都能收到消息。百度雲推送給出的解決方案是經過Client向Push Server註冊,並在Client端的監聽端口取得Push Server返回的 channelIDuserIDchannelID指定一個終端,在向Push Server註冊的過程當中,Device能夠發送IMIE碼或者UUID做爲惟一標示,在Push Server註冊後再返回給Client生成的channelIDuserID。這兩個ID獲取到後由開發者自行維護,註冊完畢後,Push Server維護一個註冊設備列表,這個列表維護了userIDchannelID以及與Device對應的關係,當須要向指定的設備或用戶推送消息時,Push Server會首先遍歷這個設備列表,經過這兩個ID來作惟一性判斷並找到須要推送消息的Device,而後就能夠進行消息推送了。

push

實例:用戶A發表問題時,記錄問題id及其對應的A的userID(或channelID),用戶B發表問題回答時,經過服務端API向問題id對應的userID(或channelID)指向的Device推送答案。

2. 分組消息推送

百度雲推送經過對Client設置標籤(Tag)的方式來進行用戶分組,Tag的產生方式能夠是由Client維護也能夠由Server收集,Push Server針對不一樣的Tag進行推送過濾,最終將消息推送到指定的Client。不管是由Client主動設置的Tag仍是由Server根據用戶使用習慣收集的,都由Push Server進行統一管理,在基於Tag的分組消息推送實現上,Push Server首先根據指定Tag從全部Tag下遍歷出的對應的已註冊的Device,從而能夠得到與Device對應的userIDchannelID,繼而能夠針對指定Tag進行分組消息推送。對比單播消息推送,分組消息推送在推送週期上勢必要長一些,而且在待推消息列表的維護上也須要作一些處理,哪些消息是推送成功的,哪些是失敗的,這須要接收消息推送的Client在接收到消息後給Push Server一個消息回執,這樣就保證了消息送達的準確性,若是消息推送失敗,則分組列表裏的待推消息會繼續推送,直到推送消息成功。另外,在消息推送的實時性上,分組消息推送對比單播消息推送會根據分組消息隊列的前後存在一個消息接收的延時,比如如今微信公衆帳號的推送,就是一個分組消息推送的實例,在消息接收的時效性上對比單播推送存在必定的延時性。

另外,還有一類消息推送使用場景,就是廣播消息,該類型能夠理解爲分組消息的一個特列,即向全部的Tag對應的Client推送消息。廣播消息是對全體集合的一個消息推送,在消息隊列維護和消息推送時效性上比單個或幾個Tag的分組推送成本要高。

實例:給應用提供喜愛設置頁面,用戶勾選不一樣的類別,觸發對應Tag的設置,這種方式是由Client主動維護Tag。或者用戶閱讀了某個類別的圖書,觸發對應Tag的設置,在服務端,給指定類別的圖書設置Tag,後續會根據服務端收集的Tag給應用推送該Tag下的新書信息,這種方式就是由服務端來維護Tag分組。

3、百度雲推送Android_SDK

百度提供了完整的Demo幫助開發者集成雲推送服務,推送服務SDK經過.jar包和.so文件的方式能夠集成到咱們本身的工程中。在此以前,須要到百度開發者中心進行應用註冊並獲取API Key,這個做爲使用推送服務應用的惟一標示,具體流程我就不贅述了,須要使用的話能夠直接訪問百度開發者中心進行查看。

下面主要看看Android_SDK的總體概覽和內部運行機制:

structure

上圖是百度雲推送Android_SDK的框架圖,經過SDK能夠繞過複雜的Push HTTP/HTTPS API直接和Push服務器進行交互,主要提供以下功能:

  • Push服務初始化以及Client註冊綁定
  • 建立或刪除標籤(Tag)
  • 接收Push Server的通知並提供自定義展示消息方式
  • 推送統計分析功能,包括通知的點擊和刪除統計以及應用使用狀況統計
  • 富媒體推送

在Android端,總共實現了三個Receiver和一個Service,其中,一個Receiver是用來處理註冊綁定後接收服務端返回的channelID等信息:

 
<receiver android:name="com.baidu.android.pushservice.RegistrationReceiver" android:process=": bdservice_v1"<intent-filter> <action android:name="com.baidu.android.pushservice.action.METHOD " /> <action android:name="com.baidu.android.pushservice.action.BIND_SYNC " /> </intent-filter> <intent-filter> <action android:name="android.intent.action.PACKAGE_REMOVED"/> <data android:scheme="package" /> </intent-filter> </receiver>

第二個Receiver是用於接收系統消息以保證PushService正常運行:

</pre></td><td class="code" style="margin:0px; padding:0px; border:0px; font-family:inherit; font-style:inherit; line-height:inherit; font-size:18px; vertical-align:middle; width:1279px"><pre style="white-space:pre-wrap; word-wrap:break-word"><code class="xml" style="margin:0px; padding:0.8em; border:0px; font-style:inherit; line-height:1.45em; vertical-align:baseline; overflow-y:hidden; display:block; overflow-x:auto;  font-family:Menlo,Monaco,'Andale Mono','lucida console','Courier New',monospace!important"><span class="line" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline"><span class="nt" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline; font-weight:bold!important; color:rgb(38,139,210)!important"><receiver</span> <span class="na" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline; color:rgb(38,139,210)!important">android:name=</span><span class="s" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline; color:rgb(42,161,152)!important">"com.baidu.android.pushservice.PushServiceReceiver"</span> <span class="na" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline; color:rgb(38,139,210)!important">android:process=</span><span class="s" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline; color:rgb(42,161,152)!important">": bdservice_v1"</span><span class="nt" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline; font-weight:bold!important; color:rgb(38,139,210)!important">></span>
</span><span class="line" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline"><span class="nt" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline; font-weight:bold!important; color:rgb(38,139,210)!important"><intent-filter></span>
</span><span class="line" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline"><span class="nt" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline; font-weight:bold!important; color:rgb(38,139,210)!important"><action</span> <span class="na" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline; color:rgb(38,139,210)!important">android:name=</span><span class="s" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline; color:rgb(42,161,152)!important">"android.intent.action.BOOT_COMPLETED"</span> <span class="nt" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline; font-weight:bold!important; color:rgb(38,139,210)!important">/></span>
</span><span class="line" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline"><span class="nt" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline; font-weight:bold!important; color:rgb(38,139,210)!important"><action</span> <span class="na" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline; color:rgb(38,139,210)!important">android:name=</span><span class="s" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline; color:rgb(42,161,152)!important">"android.net.conn.CONNECTIVITY_CHANGE"</span> <span class="nt" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline; font-weight:bold!important; color:rgb(38,139,210)!important">/></span>
</span><span class="line" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline"><span class="nt" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline; font-weight:bold!important; color:rgb(38,139,210)!important"><action</span> <span class="na" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline; color:rgb(38,139,210)!important">android:name=</span><span class="s" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline; color:rgb(42,161,152)!important">"com.baidu.android.pushservice.action.notification.SHOW"</span> <span class="nt" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline; font-weight:bold!important; color:rgb(38,139,210)!important">/></span> <span class="nt" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline; font-weight:bold!important; color:rgb(38,139,210)!important"><action</span> <span class="na" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline; color:rgb(38,139,210)!important">android:name=</span><span class="s" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline; color:rgb(42,161,152)!important">"com.baidu.android.pushservice.action.media.CLICK"</span> <span class="nt" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline; font-weight:bold!important; color:rgb(38,139,210)!important">/></span>
</span><span class="line" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline"><span class="nt" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline; font-weight:bold!important; color:rgb(38,139,210)!important"></intent-filter></span>
</span><span class="line" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline"><span class="nt" style="margin:0px; padding:0px; border:0px; font-family:inherit; line-height:inherit; vertical-align:baseline; font-weight:bold!important; color:rgb(38,139,210)!important"></receiver></span>
</span></code>

第三個Receiver就是開發者本身實現的用來接收並處理推送消息:

 
<receiver android:name="your.package.PushMessageReceiver"<intent-filter> <!-- 接收 push 消息 --> <action android:name="com.baidu.android.pushservice.action.MESSAGE" /> <!-- 接收 bind、setTags 等 method 的返回結果 --> <action android:name="com.baidu.android.pushservice.action.RECEIVE" /> </intent-filter> </receiver>

一個Service就是在後臺運行的用於保障與Push Server維持長鏈接並作相關處理的後臺服務:

 
<service android:name="com.baidu.android.pushservice.PushService" android:exported="true"android:process=" bdservice_v1"/> <!-- push service end -->

在開發者本身須要處理的廣播接收器中,能夠對接收到的推送消息進行處理,Push消息經過 action爲com.baidu.android.pushservice.action.MESSAGE的Intent把數據發送給客戶端your.package.PushMessageReceiver,消息格式由應用本身決定,PushService只負責把服務器下發的消息以字符串格式透傳給客戶端。接口調用回調經過action爲com.baidu.android.pushservice.action.RECEIVE的Intent 返回給your.package.PushMessageReceiver。

PushMessageReceiver.java

 
/** * Push消息處理receiver * @Author Ryan * @Create 2013-8-6 下午5:59:38 */ public class PushMessageReceiver extends BroadcastReceiver public static final String TAG PushMessageReceiver.class.getSimpleName(); @Override public void onReceive(final Context contextIntent intentif (intent.getAction().equals(PushConstants.ACTION_MESSAGE)) //獲取消息內容 String message intent.getExtras().getString(PushConstants.EXTRA_PUSH_MESSAGE_STRING); //消息的用戶自定義內容讀取方式 Log.i(TAG"onMessage: " message); else if (intent.getAction().equals(PushConstants.ACTION_RECEIVE)) {//處理綁定等方法的返回數據 //PushManager.startWork()的返回值經過PushConstants.METHOD_BIND獲得//獲取方法 final String method intent .getStringExtra(PushConstants.EXTRA_METHOD); //方法返回錯誤碼。若綁定返回錯誤(非0),則應用將不能正常接收消息。 //綁定失敗的緣由有多種,如網絡緣由,或access token過時。 //請不要在出錯時進行簡單的startWork調用,這有可能致使死循環。 //能夠經過限制重試次數,或者在其餘時機從新調用來解決。 final int errorCode intent.getIntExtra(PushConstants.EXTRA_ERROR_CODEPushConstants.ERROR_SUCCESS); //返回內容 final String content new Stringintent.getByteArrayExtra(PushConstants.EXTRA_CONTENT)); //用戶在此自定義處理消息,如下代碼爲demo界面展現用 Log.d(TAG"onMessage: method : " method); Log.d(TAG"onMessage: result : " errorCode); Log.d(TAG"onMessage: content : " content); }

經過在入口Activity的onCreate方法中進行推送服務的註冊綁定後,便可在推送管理後臺或是本身的應用服務器上進行消息推送的操做了。

 
PushManager.startWork(getApplicationContext(),PushConstants.LOGIN_TYPE_API_KEY"you_api_key");

另外,雲推送提供php、java等Server端的SDK供開發者在本身的服務器上實現推送服務進行定製化管理和操做。

4、單服務單通道機制

百度雲推送實現了單服務單通道的機制,若是在一臺Device上安裝了多款Push SDK的應用,不會爲每一個應用都建立PushService,而是會採用多應用共享一個PushService的模式。這樣既能減小資源消耗也能下降網絡流量。PushService運行於一個獨立進程,沒有和主進程運行於同一進程,因此主進程不須要常駐內存,當有新的Push消息時,PushService會經過Intent發送消息給主進程進行處理。經過Intent,以指定目標應用包名的方式,發送私有消息給應用。應用即不能接收不屬於本身的消息,也不能截取別人的消息,同時又下降了消耗,以下爲示意圖:

structure

後記:現在,國內提供Android推送服務的還有不少家,例如個推和極光推送等,實現的原理大同小異,開發者能夠根據自身須要進行選擇。身在天朝,置身牆內,用不到GCM,就創造Android Push Service for China自給,或者,出走!

相關文章
相關標籤/搜索