做Android和Ios消息推送一年了,有經驗也有教訓,抽空總結一下,由於我負責的是服務端的工作,所以偏重服務端的介紹。
Ios推送的原理可以用下圖概括:
圖中,Provider是指某個iPhone軟件的Push服務器。
APNS 是Apple Push Notification Service(Apple Push服務器)的縮寫,是蘋果的服務器。
上圖可以分為三個階段。
第一階段:應用程序把要發送的消息、目的iPhone的標識打包,發給APNS。
第二階段:APNS在自身的已注冊Push服務的iPhone列表中,查找有相應標識的iPhone,並把消息發到iPhone。
第三階段:iPhone把發來的消息傳遞給相應的應用程序, 並且按照設定彈出Push通知。
在實現ios消息推送之前,需要了解兩個概念:deviceToken和playload。
deviceToken類似於設備的身份證,可以定位app安裝的設備。
playload是json格式的消息載體,格式是:{"aps":{"sound":"Sent.wav","alert":"","badge":1}},當然也可以自定義參數,但是大小不能超過256個字節。
准備好deviceToken和playload之后,接下來需要與APNS建立SSL連接,APNS提供了兩個接口地址,分別是生產環境(gateway.push.apple.com)和測試環境(gateway.sandbox.push.apple.com),端口號都是2195。
當連接建立好之后,把deviceToken,playload和identifier以二進制流的形式發送給ANPS,可以維持該連接,發送多個有效的playload。由於apns是異步的,所以不會立即返回結果。
圖一:消息格式

當apns成功接收消息后,不會返回任何信息,只有當apns處理失敗時,才會返回錯誤信息(見圖二),第一位是數字8,第二位是狀態碼,Identifier是消息ID。
圖二:錯誤的信息格式:

開發中應避免每發送一次推送通知就建立、關閉一次連接。頻繁的建立、關閉連接可能會被
APNS
認為是
DOS
攻擊,從而拒絕發送
provider
的推送通知發送請求。
在JAVA中,可以使用第三方開源框架javapns給ios設備推送消息,只需簡單幾行代碼即可實現,避免了復雜的socket連接建立與消息封裝。
但是在使用過程中,發現javapns2.2版本兩個嚴重的bug,會造成消息的阻塞和重復發送,目前我們已經修改了javapns的源碼,修復了這兩個問題。
1.失敗消息重發機制:
javapns對於失敗消息有個重發機制,假設推送了5條消息,分別是:1,2,3,4,5,如果第3條消息失敗了,則javapns會把第3條以后的消息,也就是4,5重新推送。
看源碼:
List<PushedNotification> notificationsToResend = new ArrayList<PushedNotification>(); boolean foundFirstFail = false; for (PushedNotification notification : pushedNotifications.values()) { if (foundFirstFail || !notification.isSuccessful()) { if (foundFirstFail) notificationsToResend.add(notification); else { foundFirstFail = true; skippedNotification = notification; }
} }
2.消息的存儲機制:
javapns會把所有推送的消息保存在內存中,只有與apns的長連接斷開時才會清除這些消息,如果與apns的長連接始終未斷開,則這些在內存中的消息是不會被清除掉的。如果推送的消息比較多,日積月累,ios推送服務就出問題了,消息不能正常推送,必須重啟消息推送服務。
解決這兩個問題的辦法需要修改javapns的源碼。
在實際使用過程中,我們也發現,如果給apns在短時間內頻繁推送相同內容,ios設備的提醒機制就會混亂,這是apns的問題,我們無法解決,只能盡量避免出現這種情況。
