iOS推送通知梳理
無(wú)論您的應(yīng)用在前臺(tái)還是后臺(tái)本地推送還是遠(yuǎn)程推送都可以用來(lái)幫助用戶獲得您應(yīng)用的最新特性信息藻懒。因此推送功能對(duì)于您的APP還是至關(guān)重要的功能,重點(diǎn)介紹遠(yuǎn)程推送咽弦,中間穿插著會(huì)捎帶介紹本地推送同時(shí)我們的重點(diǎn)還是放在APP對(duì)于推送的處理而關(guān)于后臺(tái)與APNs之間的聯(lián)系需要單獨(dú)介紹。
參考信息
Local and Remote Notification Programming Guide歸檔信息
User Notifications Framework Reference
User Notifications UI Framework Reference
應(yīng)用配置推送能力
我們需要在應(yīng)用中提前配置好各項(xiàng)能力才能享受推送帶來(lái)的便利
我們需要推送能力需要首先獲得推送的權(quán)限砂缩,
同時(shí)如果我們需要特定的推送展示特定的操作能力即給推送通知添加按鈕我們就需要提前配置推送的Categories和對(duì)應(yīng)的Action(無(wú)需啟動(dòng)進(jìn)入應(yīng)用就可以完成相應(yīng)的事件)
獲取推送權(quán)限
通常如果你需要展示通知的alert,伴隨著聲音、顯示小標(biāo)在你的app icon上三娩、展示自定義的操作按鈕在通知上時(shí)需要你在application:didFinishLaunchingWithOptions:方法之前配置好相關(guān)內(nèi)容庵芭。
UNUserNotificationCenter *userNotificationCenter = [UNUserNotificationCenter currentNotificationCenter];
userNotificationCenter.delegate = self;
// 想要發(fā)起推送首先需要向用戶發(fā)起授權(quán)請(qǐng)求 options是你需要授權(quán)的樣式 UNAuthorizationOptionProvisional是臨時(shí)通知(不會(huì)彈窗提示用戶授權(quán)而是先嘗試發(fā)送通知沒(méi)有alert和聲音只是在通知欄列表有可以在通知欄再次進(jìn)行選擇授權(quán))下面的方法只會(huì)在第一次的時(shí)候詢(xún)問(wèn)后續(xù)就不會(huì)了
[userNotificationCenter requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error) {
}];
調(diào)用上面的requestAuthorizationWithOptions:completionHandler:方法來(lái)獲得用戶的權(quán)限,如果所有的都同意則在completionHandler中g(shù)ranted返回Yes否則返回NO,該方法只會(huì)在應(yīng)用第一次調(diào)用該方法的時(shí)候彈框提醒用戶雀监,然后記錄在系統(tǒng)中在隨后的調(diào)用中則不會(huì)再次提醒双吆。之后用戶也可以在設(shè)置中重新進(jìn)行修改。
注意:在options中如果有UNAuthorizationOptionProvisional則是臨時(shí)通知会前,應(yīng)用不會(huì)提醒用戶授權(quán)而是首先嘗試安靜的發(fā)送通知好乐,它不會(huì)伴隨聲音或Banner或顯示在鎖屏頁(yè)面,它只會(huì)展示在通知中心的歷史記錄里而且包含兩個(gè)按鈕保留或關(guān)閉(即先發(fā)送通知然后由用戶決定是否授權(quán))
我們可以在設(shè)置中隨時(shí)修改通知的權(quán)限瓦宜,因此在我們需要發(fā)送本地推送前需要判斷當(dāng)前的權(quán)限蔚万。調(diào)用方法進(jìn)行獲取getNotificationSettingsWithCompletionHandler:
配置推送分類(lèi)
對(duì)于一些推送提供操作按鈕方便用戶之間進(jìn)行任務(wù)的處理,需要我們先向系統(tǒng)注冊(cè)對(duì)應(yīng)的Categories临庇。Categories定義了我們APP支持的推送類(lèi)型而且告訴了系統(tǒng)我們需要的展示成什么樣式反璃,我們可以為對(duì)應(yīng)的Categories關(guān)聯(lián)上自定義的操作。
UNNotificationAction *action1 = [UNNotificationAction actionWithIdentifier:@"OptionNone" title:@"OK-OptionNone" options:UNNotificationActionOptionNone];
UNNotificationAction *action2 = [UNNotificationAction actionWithIdentifier:@"OptionForeground" title:@"OK-OptionForeground" options:UNNotificationActionOptionForeground];
UNNotificationAction *action3 = [UNNotificationAction actionWithIdentifier:@"OptionDestructive" title:@"OK-OptionDestructive" options:UNNotificationActionOptionDestructive];
UNNotificationAction *action4 = [UNNotificationAction actionWithIdentifier:@"OptionAuthenticationRequired" title:@"OK-OptionAuthenticationRequired" options:UNNotificationActionOptionAuthenticationRequired];
UNNotificationCategory *invitationCategory = [UNNotificationCategory categoryWithIdentifier:@"INVITATION" actions:@[action1,action2,action3,action4] intentIdentifiers:@[] options:UNNotificationCategoryOptionNone];
[userNotificationCenter setNotificationCategories:[NSSet setWithObjects:invitationCategory, nil]];
如上面的代碼我們需要?jiǎng)?chuàng)建UNNotificationCategory對(duì)象苔巨,Identifier即對(duì)應(yīng)的category的唯一標(biāo)識(shí)當(dāng)你需要推送的通知與你的category對(duì)應(yīng)上則在遠(yuǎn)程推送的payload中添加category字段值就是你定義的Identifier版扩,actions是你想要的操作按鈕最多支持4個(gè),UNNotificationCategoryOptions指示如何處理對(duì)應(yīng)的推送(UNNotificationCategoryOptionCustomDismissAction在你清楚通知的時(shí)候會(huì)將事假發(fā)送給代理方法由response.actionIdentifier接收)侄泽。如果我們點(diǎn)擊了對(duì)應(yīng)的action也會(huì)在代理方法的response.actionIdentifier中拿到對(duì)應(yīng)的UNNotificationAction的identifier礁芦。
注冊(cè)遠(yuǎn)程推送
這部分應(yīng)該也是輸入關(guān)于推送的配置項(xiàng),要想獲得遠(yuǎn)程推送的能力首先需要我們的設(shè)備向APNs發(fā)起注冊(cè)悼尾,同時(shí)如果成功APNs將會(huì)返回給我們DeviceToken這是由應(yīng)用和設(shè)備唯一確定的柿扣。
// 2. 向APNs注冊(cè)遠(yuǎn)程推送通知
[[UIApplication sharedApplication] registerForRemoteNotifications];
/// 設(shè)備成功注冊(cè)遠(yuǎn)程推送成功的處理方法
/// @param application 應(yīng)用程序
/// @param deviceToken 設(shè)備token
-(void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
// 在設(shè)備獲取成功設(shè)備的 device token我們需要將它同步給我們的服務(wù)器(后臺(tái)需要將它與對(duì)應(yīng)的用戶關(guān)聯(lián))
// 不要在本地存儲(chǔ)DeviceToken 因?yàn)樵僦匮b應(yīng)用或從備份恢復(fù),或重裝系統(tǒng)后deviceToken會(huì)變化闺魏,如果你每次請(qǐng)求新的每次都會(huì)得到最新的
[self sendDeviceTokenToProviderService:deviceToken];
NSLog(@"deviceToken");
}
/// 用戶注冊(cè)遠(yuǎn)程推送通知失敗的處理方法
/// @param application 應(yīng)用
/// @param error 錯(cuò)誤信息
-(void)application:(UIApplication *)application
didFailToRegisterForRemoteNotificationsWithError:(nonnull NSError *)error {
// 當(dāng)設(shè)備沒(méi)有連接網(wǎng)絡(luò)未状,或apns不能連接,或app沒(méi)有合適的簽名權(quán)限
// 我們可以在失敗發(fā)送后設(shè)置一個(gè)標(biāo)識(shí)并在以后嘗試再次注冊(cè)
NSLog(@"deviceToken fail: %@",error.localizedDescription);
}
獲得遠(yuǎn)程推送的能力析桥,需要我們是付費(fèi)開(kāi)發(fā)者并且在apple developer頁(yè)面為對(duì)應(yīng)的app打開(kāi)了推送能力我們可以在XCode上設(shè)置該能力--前提是我們的profile 文件中具備了APS Environment Entitlement(producction生產(chǎn)環(huán)境司草,development開(kāi)發(fā)環(huán)境), 否則在注冊(cè)時(shí)候會(huì)失敗在失敗的回調(diào)中返回對(duì)應(yīng)的錯(cuò)誤
注意: 盡量在每次啟動(dòng)應(yīng)用的時(shí)候向APNs發(fā)起注冊(cè),同時(shí)收到DeviceToken后同步給app 自己的服務(wù)器泡仗。不要去存儲(chǔ)DeviceToken因?yàn)樵倌阒匮b應(yīng)用或更新系統(tǒng)后會(huì)發(fā)生變化埋虹,不同環(huán)境下的也是不同的。同時(shí)保證我們獲得最新的DeviceToken,
在APNs注冊(cè)成功后如果沒(méi)有發(fā)生變化將會(huì)在你調(diào)用注冊(cè)后很快的返回娩怎,只有在改變之后才會(huì)與APNs進(jìn)行請(qǐng)求搔课。deviceToken 長(zhǎng)度是不固定的。
在獲取失敗的方法中我們可以做一個(gè)記錄然后再合適的時(shí)機(jī)重新注冊(cè)截亦。
發(fā)送本地推送通知
本地推送由程序員在項(xiàng)目中發(fā)起來(lái)提醒用戶相關(guān)的信息爬泥,當(dāng)應(yīng)用不再前臺(tái)系統(tǒng)將會(huì)彈窗的形式提醒用戶柬讨。如果應(yīng)用在前臺(tái)系統(tǒng)提供機(jī)會(huì)在內(nèi)部直接處理。
發(fā)送本地推送的步驟:
創(chuàng)建并配置一個(gè)UNMutableNotificationContent對(duì)象
創(chuàng)建一個(gè)推送觸發(fā)器袍啡,即何時(shí)發(fā)送推送(觸發(fā)器目前包括三個(gè)時(shí)間踩官,日歷,位置)
用上面的兩個(gè)對(duì)象創(chuàng)建 UNNotificationRequest對(duì)象
調(diào)用 addNotificationRequest:withCompletionHandler:方法來(lái)發(fā)送推送葬馋。
如果需要展示對(duì)應(yīng)的Action按鈕我們要在UNMutableNotificationContent中為categoryIdentifier賦值上我們?cè)趹?yīng)用啟動(dòng)時(shí)配置的Category的identifier
定義推送的鈴聲默認(rèn)是系統(tǒng)提供的卖鲤,我們也可以自定義。
UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
content.title = [NSString localizedUserNotificationStringForKey:@"本地推送title" arguments:nil];
content.body = [NSString localizedUserNotificationStringForKey:@"本地推送的body"
arguments:nil];
content.categoryIdentifier = YLWNotificationInvitationCategoryIdentifier;
content.sound = [UNNotificationSound soundNamed:@"sound.caf"];
// 時(shí)間觸發(fā)器
UNTimeIntervalNotificationTrigger *timeTrigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:10 repeats:NO];
UNNotificationRequest* request = [UNNotificationRequest
requestWithIdentifier:[NSUUID UUID].UUIDString content:content trigger:timeTrigger];
[[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
}];
當(dāng)你想要顯示一個(gè)推送的提醒需要title和body內(nèi)容畴嘶。
UNMutableNotificationContent 覺(jué)得了推送的內(nèi)容蛋逾,UNNotificationTrigger決定了何時(shí)發(fā)起推送。UNNotificationRequest的identify保證推送的唯一性窗悯。
添加推送自定義鈴聲content.sound = [UNNotificationSound soundNamed:@"sound.caf"];導(dǎo)入不超過(guò)30s的聲音文件放入項(xiàng)目主目錄下区匣,在Build Phases 下Copy Bundle Resourceses下添加聲音文件
注意:我們可以對(duì)內(nèi)容的文字進(jìn)行本地國(guó)際化的處理,我們使用 localizedUserNotificationStringForKey:arguments:方法對(duì)文字進(jìn)行本地化蒋院,這個(gè)方法會(huì)在將要發(fā)送的時(shí)候進(jìn)行文本的替換亏钩,為什么不用NSLocalizedString是因?yàn)槲覀冇锌赡茉谕扑桶l(fā)送前修改手機(jī)的語(yǔ)言。
UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
content.title = [NSString localizedUserNotificationStringForKey:@"Hello!" arguments:nil];
content.body = [NSString localizedUserNotificationStringForKey:@"Hello_message_body"
arguments:nil];
處理接收到的推送
處理應(yīng)用在前臺(tái)的推送
當(dāng)應(yīng)用在前臺(tái)時(shí)可以安靜的處理推送或者告訴系統(tǒng)去繼續(xù)展示推送提醒欺旧,系統(tǒng)默認(rèn)是安靜的接收姑丑,如果你想讓系統(tǒng)繼續(xù)去展示推送提醒,在代理方法userNotificationCenter:willPresentNotification:withCompletionHandler: 里調(diào)用提供的completionHandler并帶入你想展示的操作辞友。
處理應(yīng)用在后臺(tái)時(shí)的推送或應(yīng)用沒(méi)有啟動(dòng)
當(dāng)你點(diǎn)擊了一個(gè)自定義按鈕操作或點(diǎn)擊推送通知栅哀,會(huì)在代理方法userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:中接收到信息
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)(void))completionHandler {
if ([response.notification.request.content.categoryIdentifier isEqualToString:@"TIMER_EXPIRED"]) {
// Handle the actions for the expired timer.
if ([response.actionIdentifier isEqualToString:@"SNOOZE_ACTION"])
{
// Invalidate the old timer and create a new one. . .
}
else if ([response.actionIdentifier isEqualToString:@"STOP_ACTION"])
{
// Invalidate the timer. . .
}
}
// Else handle actions for other notification types. . .
}
能拿到對(duì)應(yīng)的分類(lèi)信息和自定義操作信息,同時(shí)系統(tǒng)提供了兩個(gè)自定義的操作信息
UNNotificationDismissActionIdentifier 是用戶點(diǎn)擊了推送通知的清楚關(guān)閉操作
UNNotificationDefaultActionIdentifier 是用戶沒(méi)有點(diǎn)擊其他自定義按鈕來(lái)啟動(dòng)應(yīng)用(點(diǎn)擊了推送信息)
遠(yuǎn)程推送的流程簡(jiǎn)介
獲取推送能力称龙,首先需要確保應(yīng)用獲得了用戶的授權(quán)留拾,因此我們需要首先發(fā)起授權(quán)請(qǐng)求。
獲取遠(yuǎn)程推送能力我們需要向APNs發(fā)起注冊(cè)請(qǐng)求鲫尊,APNs會(huì)根據(jù)您的設(shè)備和應(yīng)用生成一個(gè)唯一的DeviceToken然后返回給您的應(yīng)用痴柔。
向APNs注冊(cè)成功后得到DeviceToken,這時(shí)我們需要將DeviceToken同步給我們應(yīng)用自己的服務(wù)器(我們后臺(tái)需要將DeviceToken與對(duì)應(yīng)的用戶信息進(jìn)行關(guān)聯(lián)方便在將來(lái)對(duì)指定的用戶進(jìn)行推送)疫向,如果注冊(cè)失敗建議我們記錄一個(gè)標(biāo)記位在合適的時(shí)候再重新發(fā)起注冊(cè)咳蔚。
當(dāng)后臺(tái)服務(wù)需要發(fā)送通知時(shí),將對(duì)應(yīng)的DeviceToken和構(gòu)建好的payload發(fā)給APNs
APNs收到發(fā)送請(qǐng)求在合適的時(shí)機(jī)發(fā)送給對(duì)應(yīng)的設(shè)備應(yīng)用搔驼。
應(yīng)用收到推送進(jìn)行處理谈火。
附加:應(yīng)用可以使用notification service app extensions來(lái)修改推送的內(nèi)容再通知分發(fā)給用戶之前。你可以使用這種類(lèi)型的擴(kuò)展來(lái)實(shí)現(xiàn)端到端加密您的應(yīng)用程序的通知匙奴,修改通知內(nèi)容之前交付堆巧,或下載額外的圖像或媒體相關(guān)的通知妄荔。
附加:應(yīng)用可以使用notification content app extensions來(lái)自定義您的應(yīng)用通知樣式泼菌。
以上就是遠(yuǎn)程推送的大體流程谍肤,了解了大體流程之后我們開(kāi)始詳細(xì)的介紹學(xué)習(xí)將推送技能熟練掌握。
配置遠(yuǎn)程推送的支持
支持遠(yuǎn)程推送可以使我們應(yīng)用在沒(méi)有運(yùn)行的狀況下也能接收到最新的數(shù)據(jù)哗伯,為了支持遠(yuǎn)程推送我們需要以下步驟:
打開(kāi)遠(yuǎn)程推送
向APNs注冊(cè)并收到一個(gè)獨(dú)有的device token
發(fā)送device token給你的服務(wù)器
實(shí)現(xiàn)接收遠(yuǎn)程推送的方法
在上面關(guān)于推送的配置中已經(jīng)介紹了遠(yuǎn)程推送的注冊(cè)流程這里不再贅述荒揣。
遠(yuǎn)程推送的處理
在上面處理接收到的推送小節(jié)中介紹了關(guān)于推送的處理,遠(yuǎn)程還是本地推送在處理上并沒(méi)有上面區(qū)別焊刹。
修改推送的內(nèi)容(Notification Service Extension)
開(kāi)發(fā)者可以利用Notification Service Extension修改推送的內(nèi)容在推送到達(dá)用戶之前系任。我們可以用Notification Service Extension來(lái)處理遠(yuǎn)程推送的payload信息。
解密發(fā)送的數(shù)據(jù)
下載圖片或其他的多媒體文件并把他們添加到對(duì)應(yīng)推送的附件
改變推送的body或title文字
添加其他的標(biāo)識(shí)或修改userInfo字典的內(nèi)容
添加Notification Service Extension到你的項(xiàng)目中
想要在應(yīng)用中的notification servie app extension處理您的遠(yuǎn)程推送虐块,必須按照要求來(lái)設(shè)計(jì)payload信息格式(如果沒(méi)有嚴(yán)格按照要求則會(huì)直接發(fā)送)俩滥。
遵循以下要求:
包含mutable-content值為1
包含alert 字典并且字典內(nèi)部含有title和body
修改推送樣式UI(Notification Content Extension)
使用Notification Content Extension來(lái)自定義通知的UI,我們可以使用categoryIdentifier字端為用戶的本地貨遠(yuǎn)程推送進(jìn)行自定義UI.
一個(gè)Notification Content Extension只能對(duì)應(yīng)一個(gè)單獨(dú)的category.我們需要在對(duì)應(yīng)的extension的info.plist中NSExtension-》NSExtensionAttributes-》UNNotificationExtensionCategory填寫(xiě)我們定義的category, 自定義UI即可贺奠。
注意:
你可能會(huì)添加多個(gè)Notification Content Extension霜旧,但是每個(gè)通知必須支持一組唯一的通知類(lèi)別,默認(rèn)UNNotificationExtensionCategory是一個(gè)string確定唯一的一個(gè)category,當(dāng)我們需要支持多個(gè)時(shí)可以將其改為Array
我們也可以隱藏不顯示默認(rèn)顯示UI(title儡率、subTitle挂据、body)通過(guò)在info.plist中添加字段UNNotificationExtensionDefaultContentHidden值為true
總結(jié)
到現(xiàn)在關(guān)于客戶端相關(guān)內(nèi)容應(yīng)該就介紹完了,自己的語(yǔ)言功底太low但還是希望能幫助到大家儿普。下一篇會(huì)介紹關(guān)于Apple Push Notification service (APNs)的內(nèi)容崎逃。