iOS10新增加了一個(gè)UserNotificationKit(用戶(hù)通知框架)來(lái)整合通知相關(guān)的API,下面簡(jiǎn)單介紹一下新特性。
1.豐富了推送內(nèi)容:現(xiàn)在可以設(shè)置推送的title、subtitle、body 以及符合大小的圖片、音頻、視頻等附件內(nèi)容。
2.可以操作管理通知:可以對(duì)通知進(jìn)行查看、更新、刪除。
3.優(yōu)雅的展示方式:可以設(shè)置應(yīng)用在前臺(tái)展示通知。
對(duì)iOS10而言,UserNotificationKit(用戶(hù)通知框架)是一種系統(tǒng)層面的UI展示,遠(yuǎn)程通知APNS只是通知的一種觸發(fā)方式,UserNotificationKit的重要意義在于統(tǒng)一了Remote(遠(yuǎn)程通知)和Local(本地通知)。
本地通知
UserNotificationKit的基本使用流程
1.注冊(cè)通知: 獲取相關(guān)權(quán)限,注冊(cè)APNS
2.發(fā)送通知: 創(chuàng)建通知并發(fā)起通知請(qǐng)求
3.處理通知: 處理通知回調(diào),查找,移除,更新等

1. 注冊(cè)通知
UNUserNotificationCenter 用以管理與通知相關(guān)的行為。如果想要使用通知的話,必須先獲取用戶(hù)的授權(quán),才可使用 requestAuthorization 方法。
// 請(qǐng)求通知權(quán)限
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound, .badge]) {
(accepted, error) in
if !accepted {
print("用戶(hù)不允許消息通知")
}else {
print("用戶(hù)允許消息通知");
}
}
2.發(fā)送通知
發(fā)送通知主要包括通知的內(nèi)容:
1.設(shè)置推送內(nèi)容
// 設(shè)置推送內(nèi)容
let content = UNMutableNotificationContent()
content.title = "測(cè)試標(biāo)題"
content.subtitle = "測(cè)試副標(biāo)題"
content.body = "測(cè)試內(nèi)容"
content.badge = 2
content.categoryIdentifier = "categoryIdentifier" //category標(biāo)識(shí),操作策略
content.sound = UNNotificationSound.default
// Media Attachments 發(fā)送附件:圖片,音頻,視頻
通過(guò)本地磁盤(pán)上的文件 URL 創(chuàng)建一個(gè) UNNotificationAttachment 對(duì)象,然后將這個(gè)對(duì)象放到數(shù)組中賦值給 content 的 attachments 屬性:
let imageName = "icon_goods"
guard let imageURL = Bundle.main.url(forResource: imageName, withExtension: "png") else { return }
let attachment = try! UNNotificationAttachment(identifier: imageName, url: imageURL, options: .none)
content.attachments = [attachment]
2.設(shè)置通知觸發(fā)器(4種觸發(fā)器)
UNPushNotificationTrigger 觸發(fā)APNS服務(wù),系統(tǒng)自動(dòng)設(shè)置(這是區(qū)分本地通知和遠(yuǎn)程通知的標(biāo)識(shí))
UNTimeIntervalNotificationTrigger 一段時(shí)間后觸發(fā)
UNCalendarNotificationTrigger 指定日期觸發(fā)
UNLocationNotificationTrigger 根據(jù)位置觸發(fā),支持進(jìn)入某地或者離開(kāi)某地或者都有。
// UNTimeIntervalNotificationTrigger 延時(shí)觸發(fā)
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
// UNCalendarNotificationTrigger 定時(shí)執(zhí)行
let dateComponents = NSDateComponents()
let hour = "21"
let minute = "23"
dateComponents.hour = Int(hour)!
dateComponents.minute = Int(minute)!
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents as DateComponents, repeats: false)
3.添加通知
//設(shè)置請(qǐng)求標(biāo)識(shí)符
let requestIdentifier = "categoryIdentifier"
//設(shè)置一個(gè)通知請(qǐng)求
let request = UNNotificationRequest(identifier: requestIdentifier,
content: content, trigger: trigger)
//將請(qǐng)求添加到發(fā)送中心
UNUserNotificationCenter.current().add(request) { error in
if error == nil {
print("添加推送成功!")
}
}
4.通知策略(category+action)
action:設(shè)置標(biāo)識(shí)(identifier)、按鈕標(biāo)題(title)、按鈕選項(xiàng)(options)
options:
UNNotificationActionOptionAuthenticationRequired 執(zhí)行前需要解鎖確認(rèn)
UNNotificationActionOptionDestructive 顯示高亮(紅色)
UNNotificationActionOptionForeground 將會(huì)引起程序啟動(dòng)到前臺(tái)
action 有2種類(lèi)型:
UNNotificationAction 普通按鈕樣式
UNTextInputNotificationAction 輸入框樣式
//把category添加到通知中心
center.setNotificationCategories([newsCategory])
//創(chuàng)建category
let newsCategory: UNNotificationCategory = {
let intoAppAction = UNNotificationAction(
identifier: "id",
title: "進(jìn)入應(yīng)用",
options: [.foreground])
let ignoreAction = UNNotificationAction(
identifier: "destructive",
title: "忽略",
options: [.destructive])
return UNNotificationCategory(identifier:"categoryIdentifier",
actions: [intoAppAction,ignoreAction],
intentIdentifiers: [], options: [.customDismissAction])
}()
3.處理通知
常規(guī)處理
在創(chuàng)建通知請(qǐng)求時(shí),我們已經(jīng)指定了標(biāo)識(shí)符。iOS10中我們可以通過(guò)標(biāo)識(shí)符來(lái)管理處理通知。UserNotificationKIt提供了一系列API ,通過(guò)request的identifier,進(jìn)行通知的查找、更新、刪除。這個(gè)標(biāo)識(shí)是用來(lái)區(qū)分這個(gè)通知和其他通知的。
1.查找通知
// 獲取所有等待遞送的通知
UNUserNotificationCenter.current().getPendingNotificationRequests { (request) in
}
// 獲取所有已經(jīng)遞送的通知
UNUserNotificationCenter.current().getDeliveredNotifications { (noti) in
}
2.更新通知
遠(yuǎn)程推送可以進(jìn)行通知的更新
更新:center 的 addNotificationRequest:withCompletionHandler: 方法在 id 不變的情況下重新添加,就可以刷新原有的推送。
3.刪除通知/取消通知
//刪除已經(jīng)遞送的通知
UNUserNotificationCenter.current().removeAllDeliveredNotifications()
//刪除所有等待遞送的通知
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
//刪除特定已經(jīng)遞送的通知(identifier)
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: ['Identifier'])
//刪除特定等待遞送的通知(identifier)
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: ["Identifier"])
通知的回調(diào)處理UNUserNotificationCenterDelegate
UNUserNotificationCenter遵循UNUserNotificationCenterDelegate代理
//在應(yīng)用內(nèi)展示通知
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)
{
completionHandler([.alert, .sound,.badge])
// 如果不想顯示某個(gè)通知,可以直接用空 options 調(diào)用 completionHandler:
// completionHandler([])
}
//對(duì)通知進(jìn)行響應(yīng),收到通知響應(yīng)時(shí)的處理工作,用戶(hù)與你推送的通知進(jìn)行交互時(shí)被調(diào)用;
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
completionHandler()
}
當(dāng)打開(kāi)應(yīng)用時(shí)移除小紅點(diǎn)
func applicationWillEnterForeground(_ application: UIApplication) {
// 可以在此處移除通知
NoticeManeger().removeNotice()
application.applicationIconBadgeNumber = 0
}
Notification Extension
iOS 10 中添加了很多 extension,作為應(yīng)用與系統(tǒng)整合的入口。與通知相關(guān)的 extension 有兩個(gè):Service Extension 和 Content Extension。前者可以讓我們有機(jī)會(huì)在「接收到推送之后、展示推送之前」對(duì)通知內(nèi)容進(jìn)行修改;后者可以用來(lái)自定義通知視圖的樣式。
Service Extension(只對(duì)遠(yuǎn)程推送APNS的通知起效, 這里不做詳細(xì)介紹)
Service Extension:可以對(duì)推送進(jìn)行處理,更改、替換原有的內(nèi)容。他可以對(duì)通知內(nèi)容進(jìn)行加密,也可以給推送展示內(nèi)容添加附件(比如照片、背景音樂(lè)),使得內(nèi)容更加豐富。
Content Extension:可以用來(lái)自定義通知的詳細(xì)頁(yè)面視圖
1.創(chuàng)建NotificationContent,會(huì)生成NotificationViewController類(lèi),storyboard和info.plist
2.必須實(shí)現(xiàn)didReceive方法,
3.MainInterface.storyboard可以對(duì)UI進(jìn)行修改,
4.Info.plist。可以通過(guò) Info.plist 控制通知詳細(xì)視圖的尺寸,以及是否顯示原始的通知;UNNotificationExtensionCategory要對(duì)應(yīng)center注冊(cè)時(shí)的Identifier;

iOS12新特性
Grouped notifications 推送分組
Notification content extensions 推送內(nèi)容擴(kuò)展中的可交互和動(dòng)態(tài)更改Action
Notification management 推送消息的管理
Provisional authorization 臨時(shí)授權(quán)
Critical alerts 警告性質(zhì)的推送
########1.推送分組
自動(dòng):蘋(píng)果會(huì)優(yōu)先根據(jù)threadIdentifier進(jìn)行分組,否則則會(huì)根據(jù)應(yīng)用分組;
按App:設(shè)置按App,則自定義會(huì)失效,會(huì)根據(jù)應(yīng)用分組;
關(guān)閉:使用無(wú)分組樣式;
content.threadIdentifier = UUID().uuidString
2. 摘要Summary
當(dāng)蘋(píng)果把消息歸攏到一起時(shí),比如會(huì)顯示:有xxx條消息來(lái)自xxx。具體文案根據(jù)自己設(shè)置。
也可以通過(guò) let summaryFormat = NSString.localizedUserNotificationString(forKey: "NOTIFICATION_SUMMARY", arguments: nil) 來(lái)進(jìn)行本地化服務(wù)
let likeAction = UNNotificationAction(
identifier: "likeAction",
title: "Like",
options: [.authenticationRequired])
let reactAction = UNNotificationAction(
identifier: "reactAction",
title: "React",
options: [.authenticationRequired])
if #available(iOS 12.0, *) {
return UNNotificationCategory(identifier:"categoryIdentifier",
actions: [likeAction,reactAction],
intentIdentifiers: [],
hiddenPreviewsBodyPlaceholder:"新的消息",
categorySummaryFormat:"還有%u條來(lái)自%@的消息",
options: [.customDismissAction])
}

3.推送內(nèi)容擴(kuò)展中的可交互和動(dòng)態(tài)更改Action
比如設(shè)置喜歡action,點(diǎn)贊action,用戶(hù)點(diǎn)擊action時(shí),可以在UI進(jìn)行變化;
在Content Extension類(lèi)中實(shí)現(xiàn)下面的方法
func didReceive(_ notification: UNNotification) {
}
func didReceive(_ response: UNNotificationResponse, completionHandler completion: @escaping (UNNotificationContentExtensionResponseOption) -> Void) {
}
具體功能實(shí)現(xiàn)根據(jù)功能需求。
4.隱式推送
隱式推送目的是為了保護(hù)用戶(hù)隱私。當(dāng)用戶(hù)設(shè)置了隱式推送,只能在通知中心中查看消息,鎖定屏幕時(shí),沒(méi)有橫屏展示,也沒(méi)有標(biāo)記和聲音。
具體設(shè)置:1.可以在設(shè)置-通知,只打開(kāi)消息中心;
2.可以在有消息推送過(guò)來(lái)時(shí),左滑有個(gè)管理按鈕,設(shè)置隱式推送或者顯式推送;
值得注意的是,當(dāng)我們請(qǐng)求通知權(quán)限時(shí),有個(gè)provisional屬性,如果設(shè)置了該屬性,則用戶(hù)在通知中心中會(huì)收到消息,但是會(huì)有一個(gè)用戶(hù)選擇的權(quán)限,用戶(hù)可以選擇繼續(xù)接收,或者關(guān)閉。點(diǎn)擊繼續(xù)接收時(shí),也可以設(shè)置隱式推送,或者顯式推送。
//請(qǐng)求通知權(quán)限
center.requestAuthorization(options: [.alert, .sound, .badge,.provisional]) {
(accepted, error) in
if !accepted {
print("用戶(hù)不允許消息通知")
}
}