iOS遠(yuǎn)程推送詳解

Paste_Image.png

從上圖我們可以看到:
1沐寺、應(yīng)用程序注冊(cè)消息推送林艘。
2、iOS從APNS Server獲取device token混坞,應(yīng)用程序接收device token北启。
3、應(yīng)用程序?qū)evice token發(fā)送給PUSH服務(wù)端程序拔第。
4咕村、服務(wù)端程序向APNS服務(wù)發(fā)送消息。
5蚊俺、APNS服務(wù)將消息發(fā)送給iPhone應(yīng)用程序懈涛。

關(guān)于deviceToken:

deviceToken生成:

遠(yuǎn)程通知首先要向蘋(píng)果APNs服務(wù)器注冊(cè)并且生成一個(gè)唯一的deviceToken(每個(gè)設(shè)備的客戶端都獨(dú)一無(wú)二)。根據(jù)向APNs服務(wù)器發(fā)送的Token key(包含了設(shè)備的UUID和App的Bundle Identifier)泳猬。deviceToken將會(huì)以NSData對(duì)象發(fā)送到對(duì)應(yīng)請(qǐng)求的App上批钠。然后App把此deviceToken發(fā)送給我們自己的服務(wù)器,就是所謂的Provider得封。Provider收到deviceToken以后進(jìn)行儲(chǔ)存等相關(guān)處理埋心,以后Provider根據(jù)這個(gè)deviceToken來(lái)進(jìn)行消息推送。

deviceToken用處:

deviceToken是推送服務(wù)器(Provider)在向應(yīng)用推送消息時(shí)忙上,找到對(duì)應(yīng)的設(shè)備以及該設(shè)備上對(duì)應(yīng)的應(yīng)用拷呆,從而把此推送消息推送給此應(yīng)用。

deviceToken唯一性:

deviceToken根據(jù)設(shè)備唯一標(biāo)識(shí)和客戶端唯一標(biāo)識(shí)生成疫粥。確保了deviceToken唯一茬斧。唯一性并不是說(shuō)一臺(tái)設(shè)備上的一個(gè)應(yīng)用程序永遠(yuǎn)只有一個(gè)deviceToken,當(dāng)用戶升級(jí)系統(tǒng)的時(shí)候deviceToken是會(huì)變化的梗逮。

注冊(cè)遠(yuǎn)程通知(獲取deviceToken)

注冊(cè)遠(yuǎn)程通知的方法

一般都是在App啟動(dòng)完成的時(shí)候去注冊(cè)遠(yuǎn)程通知注冊(cè)方法調(diào)用一般都在didFinishLaunchingWithOptions:方法中

- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {

// 在iOS8之前注冊(cè)遠(yuǎn)程通知的方法项秉,如果項(xiàng)目要支持iOS8以前的版本,必須要寫(xiě)此方法
UIRemoteNotificationTypetypes=UIRemoteNotificationTypeBadge|UIRemoteNotificationTypeSound|UIRemoteNotificationTypeAlert;   

[[UIApplicationsharedApplication] registerForRemoteNotificationTypes:types];

// iOS8之后注冊(cè)遠(yuǎn)程通知的方法
UIUserNotificationTypetypes=UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert;
UIUserNotificationSettings*mySettings =[UIUserNotificationSettingssettingsForTypes:types categories:nil];    
[[UIApplicationsharedApplication] registerUserNotificationSettings:mySettings];
}

處理注冊(cè)遠(yuǎn)程通知的回調(diào)方法

// 注冊(cè)成功回調(diào)方法慷彤,其中deviceToken即為APNs返回的token

- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken {  

 [self sendProviderDeviceToken:deviceToken];// 將此deviceToken發(fā)送給Provider

}

// 注冊(cè)失敗回調(diào)方法娄蔼,處理失敗情況

- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error {}

處理接收到遠(yuǎn)程通知消息分兩種情況:前臺(tái)和后臺(tái)
application: didFinishLaunchingWithOptions:此方法在程序在第一次啟動(dòng)時(shí)調(diào)用怖喻,根據(jù)方法內(nèi)代碼判斷是否有推送消息。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
 // userInfo為收到遠(yuǎn)程通知的內(nèi)容 
NSDictionary*userInfo=launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
 if (userInfo) { 
// 有推送的消息岁诉,處理推送的消息
 } 
return YES罢防;
}

各種狀態(tài)下APP收到消息以及處理:

首先不管在前臺(tái)還是在后臺(tái),如果設(shè)置后臺(tái)模式為Remote Notifications
具體設(shè)置方式(或者在info.plist中配置了UIBackgroundModes):如圖
TARGETS-Capabilities-Background Modes-Remote Notifications



此時(shí)不論App處于Foreground狀態(tài)還是處于Background狀態(tài)唉侄,收到遠(yuǎn)程推送消息的時(shí)候都會(huì)立即調(diào)用此方法咒吐。

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{ }

這里引入一個(gè)概念:
**推送喚醒(remote notifications)
**iOS7以前,當(dāng)你收到推送消息時(shí)属划,你需要先打開(kāi)應(yīng)用恬叹,等待應(yīng)用從網(wǎng)絡(luò)上獲取推送的信息之后,才能將信息呈現(xiàn)出來(lái)同眯。而iOS7改變了這一過(guò)程绽昼。當(dāng)系統(tǒng)收到推送消息時(shí),不是首先提醒用戶须蜗,而是喚醒對(duì)應(yīng)的應(yīng)用硅确,讓?xiě)?yīng)用在后臺(tái)獲取對(duì)應(yīng)的信息。當(dāng)信息處理完成后明肮,再提醒用戶菱农。一個(gè)很小的改變,但是可以很大的提升用戶體驗(yàn)柿估。同樣循未,iOS系統(tǒng)也會(huì)限制這種推送消息的頻率,防止系統(tǒng)被頻繁喚醒影響續(xù)航秫舌。

此時(shí)需要更改推送的payload的妖,如果想要使用推送來(lái)喚醒應(yīng)用運(yùn)行代碼的話,需要在payload中加入content-available足陨,并設(shè)置為1嫂粟。

aps {
     content-available: 1  
     alert: {...}
 }

1.程序在前臺(tái)(Foreground)時(shí)收到推送:
如果設(shè)置remote notifications,那么先執(zhí)行相對(duì)應(yīng)的方法墨缘,在后臺(tái)收到推送也是如此星虹。
在前臺(tái)收到通知時(shí),會(huì)調(diào)用下面這個(gè)方法,可以在這個(gè)方法里面實(shí)現(xiàn)收到通知時(shí)刷新或跳轉(zhuǎn)界面的功能飒房;程序在前臺(tái)收到推送時(shí)通知欄不會(huì)彈出推送信息

-(void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo{}

2.程序在后臺(tái)時(shí)收到推送:
如果設(shè)置remote notifications搁凸,那么先執(zhí)行相對(duì)應(yīng)的方法媚值,在前臺(tái)收到推送也是如此狠毯。
如果用戶點(diǎn)擊通知欄信息進(jìn)入程序會(huì)調(diào)用情況1中的方法,所以在情況1的方法里面需要根據(jù)程序在前臺(tái)還是后臺(tái)來(lái)執(zhí)行不同操application.applicationState

3.當(dāng)程序關(guān)閉時(shí)收到推送:程序關(guān)閉時(shí)收到推送時(shí)褥芒,用戶點(diǎn)擊通知欄信息進(jìn)入應(yīng)用的時(shí)會(huì)調(diào)用

-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
 // 在此方法中一定要調(diào)用completionHandler這個(gè)回調(diào)嚼松,告訴系統(tǒng)是否處理成功
 UIBackgroundFetchResultNewData, // 成功接收到數(shù)據(jù) UIBackgroundFetchResultNoData, // 沒(méi)有接收到數(shù)據(jù) UIBackgroundFetchResultFailed // 接受失敗
 if (userInfo) { 
completionHandler(UIBackgroundFetchResultNewData);
 } else {
 completionHandler(UIBackgroundFetchResultNoData); 
}
}

可操作通知類型收到推送消息時(shí)回調(diào)方法

// 此兩個(gè)回調(diào)方法對(duì)應(yīng)可操作通知類型嫡良,具體使用方法參考以上方法很容易理解,不在詳細(xì)敘述
- (void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void(^)())completionHandler {


}
- (void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void(^)())completionHandler {


}

未讀消息數(shù)量角標(biāo)設(shè)置
設(shè)置角標(biāo)

[UIApplication sharedApplication].applicationIconBadgeNumber=badgeNum;

這個(gè)方法可以設(shè)置應(yīng)用程序的角標(biāo)的數(shù)值献酗。但是當(dāng)程序關(guān)閉時(shí)寝受,收到推送后我們就不能改變角標(biāo)數(shù)值了。所以建議讓服務(wù)端推送過(guò)來(lái)的信息里加上'badge' = 88這個(gè)鍵值對(duì)來(lái)確定角標(biāo)的顯示數(shù)值罕偎。這樣程序在后臺(tái)還是關(guān)閉很澄,只要顯示服務(wù)端傳給我們的角標(biāo)值就好了。
不過(guò)當(dāng)我們閱讀完一條消息的時(shí)需要告訴服務(wù)器颜及,并且將[UIApplication sharedApplication].applicationIconBadgeNumber減一甩苛。

當(dāng)客戶端殺死情況走本地推送(當(dāng)客戶端開(kāi)啟走—(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions)。

 if (launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]) {
        
        // 當(dāng)被殺死狀態(tài)收到本地通知時(shí)執(zhí)行的跳轉(zhuǎn)代碼
        UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
        NSDictionary *infoDict = [mnResource parseJSONStringToNSDictionary:notification.userInfo[@"info"]];

            [self.delegate diaplayAlertWhenReceivePushInfo:infoDict];
     
  }

到現(xiàn)在為止做iOS 推送也差不多算入行了吧(都是用的個(gè)推)
昨天調(diào)試個(gè)推送也讓我蛋疼俏站,調(diào)試了一晚上讯蒲,其他系統(tǒng)的沒(méi)什么問(wèn)題,就有個(gè)手機(jī)是iOS 10.0.2的系統(tǒng)肄扎,不知道為什么走不通apns墨林。

遇到這些問(wèn)題不要慌,先定為到問(wèn)題犯祠。下面列舉自己踩過(guò)的個(gè)推方面的坑:

1.打包的證書(shū)與個(gè)推后臺(tái)的證書(shū)環(huán)境不一致旭等,導(dǎo)致推送失敗。
2.服務(wù)端忘記設(shè)置了個(gè)推安卓和ios的key衡载,沒(méi)有區(qū)分辆雾,所以會(huì)向客戶端下發(fā)兩條推送,那是我解析的時(shí)候是蒙蔽的月劈,json解析出來(lái)怎么會(huì)有兩種key完全不同的字典度迂。這時(shí)候alert很大幾率顯示null且不能跳轉(zhuǎn),因?yàn)槟憬馕霾怀鰜?lái)猜揪。
3.上面那種講到的情況惭墓,自己分析應(yīng)該是

這里在說(shuō)明一點(diǎn)在使用個(gè)推的時(shí)候上傳個(gè)推平臺(tái)的.p12要和打包的證書(shū)環(huán)境一致哦(生產(chǎn)環(huán)境和調(diào)試環(huán)境)
參考:http://www.reibang.com/p/4b947569a548

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市而姐,隨后出現(xiàn)的幾起案子腊凶,更是在濱河造成了極大的恐慌,老刑警劉巖拴念,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钧萍,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡政鼠,警方通過(guò)查閱死者的電腦和手機(jī)风瘦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)公般,“玉大人万搔,你說(shuō)我怎么就攤上這事胡桨。” “怎么了瞬雹?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵昧谊,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我酗捌,道長(zhǎng)呢诬,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任胖缤,我火速辦了婚禮馅巷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘草姻。我一直安慰自己钓猬,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布撩独。 她就那樣靜靜地躺著敞曹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪综膀。 梳的紋絲不亂的頭發(fā)上澳迫,一...
    開(kāi)封第一講書(shū)人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音剧劝,去河邊找鬼橄登。 笑死,一個(gè)胖子當(dāng)著我的面吹牛讥此,可吹牛的內(nèi)容都是我干的拢锹。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼萄喳,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼卒稳!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起他巨,我...
    開(kāi)封第一講書(shū)人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤充坑,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后染突,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體捻爷,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年份企,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了也榄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡薪棒,死狀恐怖手蝎,靈堂內(nèi)的尸體忽然破棺而出榕莺,到底是詐尸還是另有隱情俐芯,我是刑警寧澤棵介,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站吧史,受9級(jí)特大地震影響邮辽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜贸营,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一吨述、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧钞脂,春花似錦揣云、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至阎毅,卻和暖如春焚刚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背扇调。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工矿咕, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人狼钮。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓碳柱,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親熬芜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子士聪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容