最近在作基於環信的及時通信項目,項目中必不可少的用到了遠程推送功能,在我解決推送問題的過程當中遇到了一些坑,同時也得到了很多的經驗. 在我的理解以及查閱資料的基礎上將遠程推送相關的知識總結以下:php
在碼代碼時咱們不該該只看到屏幕,還應該看到屏幕後面的東西. 爲了更好的理解遠程推送,首先咱們須要瞭解其原理.html
iOS app大多都是基於C/S模式開發的,也就是 客戶端/服務器模式,客戶端也就是咱們用來安裝app的手機,服務器是爲客戶端提供數據用的.由於也被稱爲Provider . 這種模式存在一個問題,那就是當app處理Terminate狀態時,二者之間是沒法進行通信的.爲了解決這個問題 蘋果所提供的一套服務稱之爲Apple Push Notification service,就是咱們所謂的APNs。服務器
咱們的設備聯網時(不管是蜂窩聯網仍是Wi-Fi聯網)都會與蘋果的APNs服務器創建一個長鏈接(persistent IP connection),當Provider推送一條通知的時候,這條通知並非直接推送給了咱們的設備,而是先推送到蘋果的APNs服務器上面,而蘋果的APNs服務器再經過與設備創建的長鏈接進而把通知推送到咱們的設備上。而當設備處於非聯網狀態的時候,APNs服務器會保留Provider所推送的最後一條通知,當設備轉換爲連網狀態時,APNs則把其保留的最後一條通知推送給咱們的設備;若是設備長時間處於非聯網狀態下,那麼APNs服務器爲其保存的最後一條通知也會丟失。Remote Notification必需要求設備連網狀態下才能收到。app
2.deviceToken的生成ide
當一個App註冊接收遠程通知時,系統會發送請求到APNs服務器,APNs服務器收到此請求會根據請求所帶的key值生成一個獨一無二的value值,也就是所謂的deviceToken,然後APNs服務器會把此deviceToken包裝成一個NSData對象發送到對應請求的App上。而後App把此deviceToken發送給咱們本身的服務器,就是所謂的Provider。Provider收到deviceToken之後進行儲存等相關處理,之後Provider給咱們的設備推送通知的時候,必須包含此deviceToken。fetch
這個時候你可能會問deviceToken究竟是什麼?有什麼用?爲何是獨一無二的?ui
// 這裏咱們用的是極光推送 編碼
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) { //能夠添加自定義categories [APService registerForRemoteNotificationTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert) categories:nil]; } else { //categories 必須爲nil [APService registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert) categories:nil]; } }
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { // Required [APService registerDeviceToken:deviceToken]; }
-(void)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions -(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
在上面的兩個方法中處理收到的遠程推送消息spa
當App收到遠程推送消息時,app不會有任何回調 ,只有用戶手動點擊通知欄裏的通知(或者是收到通知時的彈窗)纔會觸發以上兩個回調方法 .code
須要注意的是:若是當app處於前臺時收到了遠程推送通知,也會調用第二個方法,可是不會顯示通知,所以在這個方法裏須要咱們判斷程序是處於後臺仍是前臺,並選擇是否對通知進行處理.
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{ //在這裏須要判斷是否在前臺 UIApplicationState state = [[UIApplication sharedApplication] applicationState]; if (state == UIApplicationStateActive) {// 程序在前臺 // ... } else { // 程序在後臺經過點擊通知消息喚醒 // } }
iOS7以前蘋果是不持之多任務的,iOS7以後開始支持多任務即App可在後臺作一些更新UI、下載數據的操做等。若要接收到遠程推送的時候要在後臺作一些事情則須要把後臺遠程推送模式打開。
設置後臺模式方法項目對應TARGETS-Capabilities-Background Modes-Remote Notifications具體設置方法以下圖
此方法不論App處於前臺仍是後臺狀態,收到遠程推送消息的時候都會當即調用此方法。此方法須要配置後臺模式而且在推送負載中必須有content-available此key值,對應的value值爲1.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { // 在此方法中必定要調用completionHandler這個回調,告訴系統是否處理成功 UIBackgroundFetchResultNewData, // 成功接收到數據 UIBackgroundFetchResultNoData, // 沒有接收到數據 UIBackgroundFetchResultFailed // 接受失敗 if (userInfo) { completionHandler(UIBackgroundFetchResultNewData); } else { completionHandler(UIBackgroundFetchResultNoData); } }
遠程通知負載的大小根據Provider使用的API不一樣而不一樣。當使用HTTP/2 provider API時,負載最大爲4096bytes,即4kB;當使用legacy binary interface時,負載最大爲2048bytes,即2kB。當負載大小超過規定的負載大小時,APNs會拒絕發送此消息。
每一條通知的消息都會組成一個JSON字典對象,其格式以下所示,示例中的key值爲蘋果官方所用key。自定義字段的時候注意必定要避開這些key值。
{ "aps" : { "alert" : { // string or dictionary "title" : "string" "body" : "string", "title-loc-key" : "string or null" "title-loc-args" : "array of strings or null" "action-loc-key" : "string or null" "loc-key" : "string" "loc-args" : "array of strings" "launch-image" : "string" }, "badge" : number, "sound" : "string" "content-available" : number; "category" : "string" }, } aps:推送消息必須有的key alert:推送消息包含此key值,系統就會根據用戶的設置展現標準的推送信息 badge:在app圖標上顯示消息數量,缺乏此key值,消息數量就不會改變,消除標記時把此key對應的value設置爲0 sound:設置推送聲音的key值,系統默認提示聲音對應的value值爲default content-available:此key值設置爲1,系統接收到推送消息時就會調用不一樣的回調方法,iOS7以後配置後臺模式 category:UIMutableUserNotificationCategory's identifier 可操做通知類型的key值 title:簡短描述此調推送消息的目的,適用系統iOS8.2以後版本 body:推送的內容 title-loc-key:功能相似title,附加功能是國際化,適用系統iOS8.2以後版本 title-loc-args:配合title-loc-key字段使用,適用系統iOS8.2以後版本 action-loc-key:可操做通知類型key值,不詳細敘述 loc-key:參考title-loc-key loc-args:參考title-loc-args launch-image:點擊推送消息或者移動事件滑塊時,顯示的圖片。若是缺乏此key值,會加載app默認的啓動圖片。
固然以上key值並非每條推送消息都必帶的key值,應當根據需求來選擇所須要的key值,除了以上系統所提供的key值外,你還能夠自定義本身的key值,來做爲消息推送的負載,自定義key值與aps此key值並列。以下格式:
{ "aps" : { "alert" : "您有一條新的好友推薦", "badge" : 2, "sound" : "happy" }, "Id" : 222, // 自定義key值 "type" : "myType" // 自定義key值 }
推送是爲了把咱們好的資源以及最精彩內容 推送給用戶,熟練而且恰當的使用APNs能夠及時通知用戶最新動態,提升app的活躍用戶量.此次對遠程推送的研究讓我對它的運用更加熟練了.
內容若是紕漏,歡迎指正.
參考:
http://www.jianshu.com/p/4b947569a548
http://www.cocoachina.com/bbs/read.php?tid-290239-uid-441468-page-1.html