iOS10新增加了一個UserNotificationKit(用戶通知框架)來整合通知相關的API,UserNotificationKit框架增加了很多令人驚喜的特性:
- 更加豐富的推送內容:現在可以設置推送的title、subtitle、body 以及符合大小的圖片、音頻、視頻等附件內容。
- 更好的通知管理:現在可以對通知進行查看、更新、刪除了。
- 更優雅的展示方式:可以設置應用在前臺展示通知。
對iOS10而言,UserNotificationKit(用戶通知框架)是一種系統層面的UI展示,遠程通知APNS只是通知的一種觸發方式,UserNotificationKit的重要意義在于統一了Remote(遠程通知)和Local(本地通知)。
UserNotificationKit 基本流程
UserNotificationKit使用大概分為以下幾個過程:
- 注冊通知: 獲取相關權限,注冊APNS
- 發送通知: 創建通知并發起通知請求
- 處理通知: 處理通知回調,對通知進行額外的操作
首先你需要向用戶請求通知權限,在取得權限后注冊通知;
然后你可以創建一個通知并發起推送,當然對于遠程推送APNS而言,你還需要注冊DeviceToken;
在接受到推送通知后可以根據app的運行情況決定是否展示通知,當然你也可以通過一系列的回調接口對通知進行處理加工。
注冊通知
請求權限
iOS 10 進一步消除了本地推送和遠程推送的區別,因為兩者在申請權限的時候都是在打斷用戶的行為。因此iOS 10統一了推送權限的申請:
//iOS8以下
[application registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound];
//iOS8 - iOS10
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge categories:nil]];
//iOS10
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
UNAuthorizationOptions options = UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert;
[center requestAuthorizationWithOptions:options completionHandler:^(BOOL granted, NSError * _Nullable error) {
}
//iOS10 swift
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]{ granted, error in
}
推送設置
iOS 10 還可以實時獲取用戶當前的推送的設置:
//可以獲取的設置參數
@available(iOS 10.0, *)
open class UNNotificationSettings : NSObject, NSCopying, NSSecureCoding {
open var authorizationStatus: UNAuthorizationStatus { get }
open var soundSetting: UNNotificationSetting { get }
open var badgeSetting: UNNotificationSetting { get }
open var alertSetting: UNNotificationSetting { get }
open var notificationCenterSetting: UNNotificationSetting { get }
open var lockScreenSetting: UNNotificationSetting { get }
open var carPlaySetting: UNNotificationSetting { get }
open var alertStyle: UNAlertStyle { get }
}
//獲取設置
UNUserNotificationCenter.current().getNotificationSettings {
settings in
print(settings.authorizationStatus) // .authorized | .denied | .notDetermined
print(settings.badgeSetting) // .enabled | .disabled | .notSupported
}
在有些情況下,可以對推送權限設置進行檢查。
APNS:DeviceToken
一旦獲得用戶權限后,你就可以在應用中發送本地通知了。不過對于APNS而言,你還需要申請DeviceToken,把DeviceToken傳遞給服務器,然后服務器根據DeviceToken發送到對應的用戶。
//向APNSS請求deviceToken:
UIApplication.shared.registerForRemoteNotifications()
//回調
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
print("Get Push token: \(deviceToken)")
}
發送通知
本地通知發送的基本流程
1.設置推送內容
2.設置通知觸發器
3.添加通知
1.設置推送內容
let content = UNMutableNotificationContent()
content.title = "Time Interval Notification" //推送內容標題
content.subtitle = "My first notification" //推送內容子標題
content.body = "My first notification"http:// 推送內容body
content.categoryIdentifier = "categoryIdentifier" //category標識,操作策略
2.設置通知觸發器
有4種觸發器
UNPushNotificationTrigger 觸發APNS服務,系統自動設置(這是區分本地通知和遠程通知的標識)
UNTimeIntervalNotificationTrigger 一段時間后觸發
UNCalendarNotificationTrigger 指定日期觸發
UNLocationNotificationTrigger 根據位置觸發,支持進入某地或者離開某地或者都有。
//設置5秒后觸發
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
//每周三,13點觸發
var components:DateComponents = DateComponents()
components.weekday = 4;//周三
components.hour = 13;//13點
let triggerDateComponents = UNCalendarNotificationTrigger(dateMatching: components, repeats: true);
//這個點,100米范圍內,進入觸發。
let Coordinate2:CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: 39, longitude: 116);
let region:CLCircularRegion = CLCircularRegion(center: Coordinate2, radius: 100, identifier: "center")
region.notifyOnEntry = true;
region.notifyOnExit = false;
let triggerRegion = UNLocationNotificationTrigger(region: region, repeats: true);
3.添加通知
//先創建一個請求
let request = UNNotificationRequest(identifier: requestIdentifier, content: content, trigger: trigger)
//將請求添加到發送中心
UNUserNotificationCenter.current().add(request) { error in
if error == nil {
print("Time Interval Notification scheduled: \(requestIdentifier)")
}
}
APNS:Payload
iOS 10之前的推送內容比較單一,僅僅支持一段文字的消息推送,最好帶上badge和sound,以及一些自定義的字段內容,而在iOS 10中,Apple豐富了推送內容,并且增加了更多的顯示方式。
//iOS 10 之前的基礎Payload:
{
"aps":{
"alert":{
"body": "This is a message"
},
"sound":"default",
"badge":1
}
}
//iOS 10 基礎Payload:
{
"aps":{
"alert":{
"title":"I am title",
"subtitle":"I am subtitle",
"body":"I am body"
},
"sound":"default",
"badge":1
}
}
title和subtitle并不是必須的。
處理通知
常規處理
在創建通知請求時,我們已經指定了標識符。iOS10中我們可以通過標識符來管理處理通知。通UserNotificationKIt的一系列API 你可以做到: 查找、更新和刪除通知。其中關鍵在于request的identifier,即在創建的時候的指定的通知的標識符。
查找通知
//獲取所有等待遞送的通知
UNUserNotificationCenter.current().getPendingNotificationRequests { (request) in
}
//獲取所有已經遞送的通知
UNUserNotificationCenter.current().getDeliveredNotifications { (noti) in
}
更新通知
遠程推送可以進行通知的更新,在使用 center 的 addNotificationRequest:withCompletionHandler: 向 APNS提交請求時,在 HTTP/2 的 header 中 apns-collapse-id key 的內容將被作為該推送的標識符進行使用。多次推送同一標識符的通知即可進行更新。
//先創建一個請求
let request = UNNotificationRequest(identifier: requestIdentifier, content: content, trigger: trigger)
//重新添加通知
UNUserNotificationCenter.current().add(request) { error in
if error == nil {
print("Time Interval Notification scheduled: \(requestIdentifier)")
}
}
刪除通知/取消通知
//使用這個API來移除通知 還有一系列相似的API
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: dentifiers)
//取消還未展示的本地通知
UNUserNotificationCenter.current().add(request) { error in
if error != nil {
print("Notification request added: \(identifier)")
}
}
delay(2) {
let newTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
let newRequest = UNNotificationRequest(identifier: identifier, content:newContent, trigger: newTrigger)
UNUserNotificationCenter.current().add(newRequest) { error in
if error != nil {
print("Notification request updated: \(identifier)")
}
}
}
通知的回調:UNUserNotificationCenterDelegate
UNUserNotificationCenterDelegate提供了兩個方法處理通知。兩個方法分別對應如何在應用內展示通知,和收到通知響應時要如何處理的工作。
//在應用內展示通知
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)
{
completionHandler([.alert, .sound])
// 如果不想顯示某個通知,可以直接用空 options 調用 completionHandler:
// completionHandler([])
}
//對通知進行響應,收到通知響應時的處理工作,用戶與你推送的通知進行交互時被調用;
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
completionHandler()
}
Notification Extension
iOS 10 中添加了很多 extension,作為應用與系統整合的入口。與通知相關的 extension 有兩個:Service Extension 和 Content Extension。前者可以讓我們有機會在「接收到推送之后、展示推送之前」對通知內容進行修改;后者可以用來自定義通知視圖的樣式。
Service Extension
Service Extension可以對推送進行處理,更改、替換原有的內容。他可以對通知內容進行加密,也可以給推送展示內容添加附件(比如照片、背景音樂),使得內容更加豐富。
//NotificationService 的模板已經為我們進行了基本的實現:
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
// 1 讓你可以在后臺處理接收到的推送,傳遞修改后的的內容給 contentHandler,然后展示
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
if let bestAttemptContent = bestAttemptContent {
if request.identifier == "mutableContent" {
bestAttemptContent.body = "\(bestAttemptContent.body), onevcat"
}
contentHandler(bestAttemptContent)
}
}
// 2 在在你獲得的一小段運行代碼的時間內沒有調用 contentHandler 的話,系統會調用這個方法。可以在這里傳肯定不會出錯的內容,或者他會默認傳遞原始的推送內容。
override func serviceExtensionTimeWillExpire() {
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
}
Service Extension 現在只對遠程推送APNS的通知起效,你可以在推送 payload 中增加一個 mutable-content 值為 1 的項來啟用內容修改
{
aps : {
alert : "New Message",
mutable-content : 1
},
encrypted-content : "#myencryptedcontent"
}
Media Attachments
iOS 10 的另一個亮眼功能是多媒體的推送,開發者能夠直接在推送的通知內容里面傳遞多媒體資源,在客戶端進行直接的展示,極大豐富了推送內容的可讀性和趣味性。
為本地通知添加添加多媒體內容
通過本地磁盤上的文件 URL 創建一個 UNNotificationAttachment 對象,然后將這個對象放到數組中賦值給 content 的 attachments 屬性:
let content = UNMutableNotificationContent()
content.title = "Hey guys"
content.body = " body "
if let imageURL = Bundle.main.url(forResource: "image", withExtension: "jpg"),
let attachment = try? UNNotificationAttachment(identifier: "imageAttachment", url: imageURL, options: nil)
{
content.attachments = [attachment]
}
為遠程推送添加多媒體內容
只需要在推送的 payload 中指定需要加載的資源地址,這個地址可以是應用 bundle 內已經存在的資源,也可以是網絡的資源。不過因為在創建 UNNotificationAttachment 時我們只能使用本地資源,所以如果多媒體還不在本地的話,我們需要先將其下載到本地。在完成 UNNotificationAttachment 創建后,我們就可以和本地通知一樣,將它設置給 attachments 屬性,然后調用 contentHandler 了。
{
"aps":{
"alert":{
"title":"Image Notification",
"body":"Show me an image from web!"
},
"mutable-content":1 //表示我們會在接收到通知時對內容進行更改
},
"image": "https://img1.baidu.com.jpg"http://指明了目標圖片的地址
}
- 如果你想在遠程推送來的通知中顯示應用 bundle 內的資源的話,要注意 extension 的 bundle 和 app main bundle 并不是一回事兒。你可以選擇將圖片資源放到 extension bundle 中,也可以選擇放在 main bundle 里。總之,你需要保證能夠獲取到正確的,并且你具有讀取權限的 url。
- UNNotificationContent 的 attachments 雖然是一個數組,但是系統只會展示第一個 attachment 對象的內容。不過你依然可以發送多個 attachments,然后在要展示的時候再重新安排它們的順序,以顯示最符合情景的圖片或者視頻。
Notification Actions
iOS 8 和 9 中 Apple 引入了可以交互的通知,這是通過將一簇 action 放到一個 category 中,將這個 category 進行注冊,最后在發送通知時將通知的 category 設置為要使用的 category 來實現的。這些action的API在iOS10 中被統一。
注冊Actions
private func registerNotificationCategory() {
let saySomethingCategory: UNNotificationCategory = {
// 1 創建 action 即一項交互操作
let inputAction = UNTextInputNotificationAction(
identifier: "action.input",
title: "Input", // 是交互按鈕的內容
options: [.foreground], // options 可以讓該 action 成為一條可在前臺執行的 action
textInputButtonTitle: "Send",
textInputPlaceholder: "What do you want to say...")
let goodbyeAction = UNNotificationAction(
identifier: "action.goodbye",//,推送消息的其中的identifier
title: "Goodbye",
options: [.foreground])
let cancelAction = UNNotificationAction(
identifier: "action.cancel",
title: "Cancel",
options: [.destructive])
//2. 創建 category
return UNNotificationCategory(identifier:"saySomethingCategory", actions: [inputAction, goodbyeAction, cancelAction], intentIdentifiers: [], options: [.customDismissAction])
}()
// 3 把 category 添加到通知中心:
UNUserNotificationCenter.current().setNotificationCategories([saySomethingCategory])
}
// 4 觸發方式
//遠程通知觸發方式
{
aps : {
alert : "Welcome to WWDC !",
category : "saySomethingCategory" //和第二步identifier:"saySomethingCategory一致
}
}
//本地通知觸發方式 Local Notifications 只需要在創建 contnet 的時候指定 和第二步identifier 即可
content.categoryIdentifier = "saySomethingCategory";
通過上面的三個步驟我們已經創建了一個category
作者:曲年
鏈接:http://www.lxweimin.com/p/567abab2098f
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。