[iOS] 通知詳解: iOS 10 UserNotifications

通知相關(guān)系列文章
iOS10 之前通知使用介紹
[iOS] 通知詳解: UIUserNotification
iOS10 相關(guān)API
[iOS] 通知詳解:iOS 10 UserNotifications API
iOS10 本地/遠(yuǎn)程通知
[iOS] 通知詳解: iOS 10 UserNotifications
iOS10 通知附加包
[iOS] 通知詳解: iOS 10 UserNotifications -- 附加包Media Attachments
iOS10 自定義UI
[iOS] 通知詳解: iOS 10 UserNotifications -- 自定義通知UI

申請(qǐng)通知權(quán)限并注冊(cè)通知

同樣,發(fā)送通知需要申請(qǐng)用戶同意,在didFinishLaunchingWithOptions中進(jìn)行權(quán)限的檢測(cè)及請(qǐng)求權(quán)限:

extension AppDelegate: UNUserNotificationCenterDelegate {
    
    func registerAPNs10() {
        
        let center = UNUserNotificationCenter.current()
        center.delegate = self
        
        center.getNotificationSettings { (settings) in
            if settings.authorizationStatus == .notDetermined {
                // 未選擇,請(qǐng)求授權(quán)
                center.requestAuthorization(options: [.alert, .sound, .badge]) { (result, error) in
                    if result {
                        // 用戶同意
                        // 注冊(cè)通知,獲取deviceToken
                        self.registerForRemoteNotifications()
                    } else {
                        print(error)
                    }
                }
            } else if settings.authorizationStatus == .authorized {
                // 已授權(quán)
                // 注冊(cè)通知,獲取deviceToken
                self.registerForRemoteNotifications()
                
            } else if settings.authorizationStatus == .denied {
                // 拒絕,當(dāng)用戶拒絕后,需要在合適的時(shí)機(jī)進(jìn)行提醒,而不應(yīng)該是每次啟動(dòng)時(shí)都去提醒
                // 彈出提示框,引導(dǎo)用戶開(kāi)啟
//                if let url = URL(string: UIApplication.openSettingsURLString) {
//                    if UIApplication.shared.canOpenURL(url) {
//                        UIApplication.shared.open(url, options: [:], completionHandler: nil)
//                    }
//                }
                
            }
        }
    }
    
    // 注冊(cè)通知,獲取deviceToken
    func registerForRemoteNotifications () {
        // 請(qǐng)求授權(quán)時(shí)異步進(jìn)行的,這里需要在主線程進(jìn)行通知的注冊(cè)
        DispatchQueue.main.async {
            UIApplication.shared.registerForRemoteNotifications()

        }
    }
    
}

這里需要注意的是,申請(qǐng)權(quán)限的操作是異步進(jìn)行的,我們需要在主線程調(diào)用注冊(cè)遠(yuǎn)程通知的方法UIApplication.shared.registerForRemoteNotifications(),成功或者失敗會(huì)分別調(diào)用下面的代理方法:

// registerForRemoteNotifications 成功的回調(diào),獲取到token
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        
        let deviceStr = deviceToken.map { String(format: "%02hhx", $0) }.joined()
        
        print(deviceStr)

    }
//    registerForRemoteNotifications 失敗的回調(diào)
    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        
    }

正常獲取到deviceToken,即表示同住注冊(cè)成功,即可進(jìn)行正常的消息推送了。

本地通知

iOS10中本地通知的使用和之前版本使用方式區(qū)別不大,只是使用不同的API來(lái)創(chuàng)建通知,這里只給出一些配置的示例,其他的直接查看相關(guān)的API或者文章的介紹。

一般的本地通知

例如10s觸發(fā)的本地通知,可以這樣設(shè)置:

// 創(chuàng)建通知內(nèi)容
        let content = UNMutableNotificationContent()
        
        content.title = "ios 10 local push test"
        content.subtitle = "local push subtitle"
        content.body = "這是一個(gè)iOS 10 之后的本地通知測(cè)試文本,這里顯示的是消息的詳細(xì)內(nèi)容"
        content.sound = .default
        content.userInfo = ["info": "這里的信息是傳遞給app的payload內(nèi)容"]
        
        // 創(chuàng)建觸發(fā)方式,10s后觸發(fā)
        let timer = UNTimeIntervalNotificationTrigger(timeInterval: 10, repeats: false)
        
        // 創(chuàng)建通知請(qǐng)求
        let req = UNNotificationRequest(identifier: "reqid", content: content, trigger: timer)
        
        // 添加請(qǐng)求到通知中心
        UNUserNotificationCenter.current().add(req) { (error) in
            print(error)
        }

效果:


如果是某個(gè)固定日期時(shí)間或者某個(gè)地理范圍觸發(fā)的通知,可以根據(jù)上面第一部分的UNNotificationTrigger創(chuàng)建相應(yīng)的觸發(fā)器,添加到請(qǐng)求里即可!

帶有交互的本地通知

涉及到的相關(guān)類,參考第一部分的 通知快捷操作Action 部分內(nèi)容。

點(diǎn)擊事件的交互 UNNotificationAction
// 如果點(diǎn)擊后,需要喚起app,則options選擇UNNotificationActionOptions.foreground
let okAction = UNNotificationAction(identifier: "okidentifier", title: "查看", options: UNNotificationActionOptions.foreground)
        
// 如果點(diǎn)擊后,不需要喚起app,則options選擇另外兩個(gè)
        let cancel = UNNotificationAction(identifier: "cancelidentifier", title: "關(guān)閉", options: UNNotificationActionOptions.destructive)
        
        let category = UNNotificationCategory(identifier: "categoryidentifier", actions: [okAction, cancel], intentIdentifiers: [], options: UNNotificationCategoryOptions.customDismissAction)
        UNUserNotificationCenter.current().setNotificationCategories(Set.init([category]))
        
        // 創(chuàng)建通知內(nèi)容
        let content = UNMutableNotificationContent()
        
        content.title = "ios 10 local push test"
        content.subtitle = "local push subtitle"
        content.body = "這是一個(gè)iOS 10 之后的本地通知測(cè)試文本,這里顯示的是消息的詳細(xì)內(nèi)容"
        content.sound = .default
        content.userInfo = ["info": "這里的信息是傳遞給app的payload內(nèi)容"]
        content.categoryIdentifier = "categoryidentifier"
        
        // 創(chuàng)建觸發(fā)方式,10s后觸發(fā)
        let timer = UNTimeIntervalNotificationTrigger(timeInterval: 10, repeats: false)
        
        // 創(chuàng)建通知請(qǐng)求
        let req = UNNotificationRequest(identifier: "reqid", content: content, trigger: timer)
        
        // 添加請(qǐng)求到通知中心
        UNUserNotificationCenter.current().add(req) { (error) in
            print(error)
        }

點(diǎn)擊按鈕后會(huì)調(diào)用代理方法

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        print(response.actionIdentifier)
    }
快捷回復(fù)輸入框的action UNTextInputNotificationAction

只需要?jiǎng)?chuàng)建UNTextInputNotificationAction的實(shí)例,添加到category中即可:

let okAction = UNTextInputNotificationAction(identifier: "okidentifier", title: "回復(fù)", options: .foreground, textInputButtonTitle: "快捷回復(fù)", textInputPlaceholder: "請(qǐng)輸入。。。")
        
        
        let cancel = UNNotificationAction(identifier: "cancelidentifier", title: "關(guān)閉", options: UNNotificationActionOptions.destructive)
        
        let category = UNNotificationCategory(identifier: "categoryidentifier", actions: [okAction, cancel], intentIdentifiers: [], options: UNNotificationCategoryOptions.customDismissAction)
        UNUserNotificationCenter.current().setNotificationCategories(Set.init([category]))
        
        // 創(chuàng)建通知內(nèi)容
        let content = UNMutableNotificationContent()
        
        content.title = "ios 10 local push test"
        content.subtitle = "local push subtitle"
        content.body = "這是一個(gè)iOS 10 之后的本地通知測(cè)試文本,這里顯示的是消息的詳細(xì)內(nèi)容"
        content.sound = .default
        content.userInfo = ["info": "這里的信息是傳遞給app的payload內(nèi)容"]
        content.categoryIdentifier = "categoryidentifier"
        
        // 創(chuàng)建觸發(fā)方式,10s后觸發(fā)
        let timer = UNTimeIntervalNotificationTrigger(timeInterval: 10, repeats: false)
        
        // 創(chuàng)建通知請(qǐng)求
        let req = UNNotificationRequest(identifier: "reqid", content: content, trigger: timer)
        
        // 添加請(qǐng)求到通知中心
        UNUserNotificationCenter.current().add(req) { (error) in
            print(error)
        }

點(diǎn)擊之后的效果:


同樣,在代理方法中可獲取輸入的內(nèi)容:

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        print(response.actionIdentifier)
        
        if let input = response as? UNTextInputNotificationResponse {
            print(input.userText)
        }
        
        completionHandler()
    }

移除通知

// 移除某個(gè)已觸發(fā)的通知
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: ["reqid"])
        
// 移除添加的通知請(qǐng)求       UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: ["reqid"])

// 移除所有已執(zhí)行的通知
UNUserNotificationCenter.current().removeAllDeliveredNotifications()

// 移除所有通知請(qǐng)求       UNUserNotificationCenter.current().removeAllPendingNotificationRequests()

遠(yuǎn)程通知 APNs(Apple Push Notification Services)

遠(yuǎn)程通知在獲取到通知權(quán)限后,就可以使用一般的 Payload 來(lái)發(fā)送通知。

一般消息推送的Payload模板

{
"aps":
    {
        "alert":
        {
            "title":"iOS10 標(biāo)題",
            "subtitle" : "iOS10 副標(biāo)題",
            "body":"這是iOS10中遠(yuǎn)程推送的消息主體內(nèi)容,這里的內(nèi)容會(huì)展示在消息摘要信息里,當(dāng)下拉消息框,就能夠看到完整的消息內(nèi)容。"
        },
        "badge":1,
        "sound":"default",
        "customInfo":{"key":"這是自定義的消息內(nèi)容"}
    }
}

效果圖:

當(dāng)app在前臺(tái)運(yùn)行時(shí),同樣會(huì)走willPresent notification代理方法;當(dāng)app后臺(tái)運(yùn)行或未打開(kāi)時(shí),走didReceive response方法;沒(méi)錯(cuò),和本地通知走的代理方法是一樣的。我們可以通過(guò)trigger的類型來(lái)判斷是本地通知,還是遠(yuǎn)程通知

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        print(response.actionIdentifier)
        
        if let input = response as? UNTextInputNotificationResponse {
            print(input.userText)
        }
        
        if response.notification.request.trigger is UNPushNotificationTrigger {
            // 遠(yuǎn)程通知
        } else {
            // 本地通知
        }
        
        completionHandler()
    }
    
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        
        print(notification.request.content.categoryIdentifier)
        let userInfo = notification.request.content.userInfo
        
        print(userInfo)
        if notification.request.trigger is UNPushNotificationTrigger {
            // 前臺(tái)運(yùn)行時(shí)遠(yuǎn)程通知
        } else {
            // 前臺(tái)運(yùn)行時(shí)本地通知
        }
        
        completionHandler(.alert)
    }

帶有交互action的遠(yuǎn)程通知

只需要在請(qǐng)求中心添加相應(yīng)的交互category,并把其identifier添加到Payload中即可;

定義所需的交互 UNNotificationAction

let okAction = UNNotificationAction(identifier: "okidentifier", title: "查看", options: UNNotificationActionOptions.foreground)
//        let okAction = UNTextInputNotificationAction(identifier: "okidentifier", title: "回復(fù)", options: .foreground, textInputButtonTitle: "快捷回復(fù)", textInputPlaceholder: "請(qǐng)輸入。。。")
        
        
        let cancel = UNNotificationAction(identifier: "cancelidentifier", title: "關(guān)閉", options: UNNotificationActionOptions.destructive)
        
        let category = UNNotificationCategory(identifier: "categoryidentifier", actions: [okAction, cancel], intentIdentifiers: [], options: UNNotificationCategoryOptions.customDismissAction)
        UNUserNotificationCenter.current().setNotificationCategories(Set.init([category]))

此時(shí)的Payload,需要加入 category,告訴系統(tǒng)需要加載哪一組的交互

{
"aps":
    {
        "alert":
        {
            "title":"iOS10 標(biāo)題",
            "subtitle" : "iOS10 副標(biāo)題",
            "body":"這是iOS10中遠(yuǎn)程推送的消息主體內(nèi)容,這里的內(nèi)容會(huì)展示在消息摘要信息里,當(dāng)下拉消息框,就能夠看到完整的消息內(nèi)容。這是一個(gè)帶有交互按鈕的通知。。。"
        },
        "category":"categoryidentifier",
        "badge":1,
        "sound":"default"
    }
}

帶有交互按鈕的遠(yuǎn)程push


如果是需要快捷回復(fù)框,只需要像本地通知一樣,創(chuàng)建一個(gè)UNTextInputNotificationAction 實(shí)例即可!

靜默通知

發(fā)送靜默通知,同iOS10之前的方式一致,修改Payload如下即可:

{"aps":{"content-available":"1","extinfo": {"info": "Test remote info"}}}

需要注意的是,靜默push不會(huì)走iOS10中新的代理方法,還是在原來(lái)的代理方法進(jìn)行接收反饋:

 func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        
        let state = UIApplication.shared.applicationState
        
        var msg = ""
        
        if state == .active {
            // qiantai
            
            msg += "active"
        } else {
            // houtai
            msg += "inactive"
        }
        
        print("Receive remote notification at \(msg)")
        print(userInfo)
        
        let info = ["dele":"zhe shi ling yi ge push!",
                    "info": userInfo] as [String : Any]
        
        TestSingle.shared.info = info
        completionHandler(.noData)
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容