我們的IOS行動裝置 App要實現訊息推送,告訴使用者有多少條訊息未讀,類似的效果(笑果),特把APNS和Erlang相關解決方案筆記於此備忘.
首先解決三者的信任關係,Provider(APP Server)的開發方要從Apple Dev Center獲得SSL認證, 每個認證一個應用,甚至開發和生產環境的認證都要分別申請. Provider要在APNs中進行認證註冊,目前註冊使用的是應用程式的唯一標識(bundle identifier).Provider Connection的是對應到指定應用的,certificate中包含了應用程式的標識資訊(bundle ID),APNs維護了一個廢棄列表,如果一個Provider上了名單,APNs就會移除對該應用的信任. Provider和APNs通訊協定是二進位協議,使用TCP流協議建立SSL(TLS)安全連線,官方文檔稱這種信任為Connection Trust. 對於使用者裝置APNs使用的是Token Trust.使用者安裝一個APP的時候,如果APP需要訊息推送功能通常在安裝成功之後會經由使用者裝置發起註冊請求,使用者裝置將此請求轉寄到APNs, APNs產生唯一的device certificate,其中包含了device token.Device Token 中包含了裝置的唯一標識,使用Token key加密Device Token返回到Device.使用者裝置把device token返回給發起註冊請求的應用程式,應用程式把Device Token的資訊傳遞給Provider.使用者裝置上安裝的APP從APNs 獲得device token之後每一次串連到ANPs都要提供這個token. APNs解密device token並驗證這個token是從串連過來的裝置產生的:APNs保證實際串連過來的裝置標識和certificate檔案中裡麵包含的標識一致. Provider提交到APNS的notification兩個必要的資訊:把什麼訊息投遞給誰,即包含裝置標識(Device Token)和實際訊息體(Payload).APNS使用token Key解密token,從中提取裝置ID來決定最終訊息投遞到哪個裝置.Device Token有一個非常貼切的類比:手機號,它包含的資訊可以讓APNs來定位安裝了指定應用的裝置.APNs還使用Device Token來路由訊息,Payload的訊息組織形式是類JSON的,它包含的資訊包括推送給裝置什麼內容以及如何提示;Payload內容大小限制是 256 bytes. 注意:Device Token和裝置的UDID不是一回事,使用者恢複系統,重裝都會導致device token變化. APNs有一個 Feedback Service的設計,它維護應用訊息推送失敗的裝置列表,如果應用已經卸載了就無法投遞成功,這樣Feedback Service裡面就會有記錄.Provider的開發方應定期從該服務拉取這個失敗列表來調整自己的發送行為:不要再給一個總是失敗的裝置推送訊息了.如果裝置離線,notification會在APNs上儲存有限的一段時間,裝置上線之後完成推送.如果裝置離線期間同一個應用推送了多條notification,那麼只會儲存最新的notification,如果裝置長期離線,任何離線訊息都會被拋棄掉.這樣如果iPhone掉海裡面,需要推送給它的訊息在到期之後就會被清理掉,不會長久佔用APNs的資源. 經過上面的分析基本可以列出Erlang實現訊息推送的技術要點了:[1] JSON資料解析構造 mochijson mochijson2之類的模組就可以搞定 mochijson:encode --> list_to_binary[2] SSL http://www.erlang.org/doc/man/ssl.html[3] 二進位協議實現 (Apple Binary Iterface)Packet = [<<1:8, MsgId/binary, Expiry:4/big-unsigned-integer-unit:8, 32:16/big,
BinToken/binary,
PayloadLength:16/big,
BinPayload/binary>>] [5] 維護TCP串連,重連機制 按照上面的要點完成了基本的驗證之後,在Github上找到了開源項目apns4erl (地址:https://github.com/inaka/apns4erl),這個項目對APNS服務做了良好的實現和封裝.下面介紹下apns4erl的使用: 認證製作: APP Server和Apple Server中間建立信任關係需要通過各種認證,apns4erl作者在項目中提供了產生認證的指令碼,不過在項目首頁提到.cer和.p12檔案產生pem認證的指令碼地址是錯的,實際位置是:https://github.com/inaka/apns4erl/blob/master/priv/test_certs 執行下面的指令碼就一步一步即可: -p priv/- - priv/temp/key-- priv/temp/key-enc.pem - priv/temp/-inform der - - priv/temp//temp/cert.pem priv/temp/key.pem > priv/-rf priv/
下面是測試代碼,注意send_badge/1方法就是我們需要的效果:---include(-include(->?//->?APNS_NAME, , ->== = = = ->->->, [Data]).
APNS相關資料: [0] iOSDeveloper Library: Apple Push Notification Service (APNS)https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html#//apple_ref/doc/uid/TP40008194-CH100-SW9 [1] Apple Push Notification Services in iOS 6 Tutorial http://www.raywenderlich.com/32960/apple-push-notification-services-in-ios-6-tutorial-part-1 [2] Apple Push Notification Services in iOS 6 Tutorial 中文
http://www.raywenderlich.com/zh-hans/24732 [3] iOS 和 Android 的後台推送原理各是什嗎?有什麼區別? http://www.zhihu.com/question/20667886 [4] 蘋果產品是如何?推送功能的呢? http://www.zhihu.com/question/20049505 [5] 為什麼 Android 的後台推送不如 iOS 的推送使用廣泛? http://www.zhihu.com/question/19899490 [6] Is the device token as unique as the device ID? http://stackoverflow.com/questions/6927011/is-the-device-token-as-unique-as-the-device-id [7] If the user restores backup data to a new device or computer, or reinstalls the operating system, the device token changes. https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/IPhoneOSClientImp.html [8] Apple Push Notifications with Erlang http://bravenewmethod.wordpress.com/2011/02/16/apple-push-notifications-with-erlang/ [9] Sending Apple Push Notifications with Erlanghttps://uwe-arzt.de/2011/03/04/sending-apple-push-notifications-with-erlang/ 最後小圖一張: