iOS、Swift

[iOS] 通知详解: iOS 10 UserNotificat

2018-11-06  本文已影响114人  流火绯瞳

通知相关系列文章
iOS10 之前通知使用介绍
[iOS] 通知详解: UIUserNotification
iOS10 相关API
[iOS] 通知详解:iOS 10 UserNotifications API
iOS10 本地/远程通知
[iOS] 通知详解: iOS 10 UserNotifications
iOS10 通知附加包
[iOS] 通知详解: iOS 10 UserNotifications -- 附加包Media Attachments
iOS10 自定义UI
[iOS] 通知详解: iOS 10 UserNotifications -- 自定义通知UI

申请通知权限并注册通知

同样,发送通知需要申请用户同意,在didFinishLaunchingWithOptions中进行权限的检测及请求权限:

extension AppDelegate: UNUserNotificationCenterDelegate {
    
    func registerAPNs10() {
        
        let center = UNUserNotificationCenter.current()
        center.delegate = self
        
        center.getNotificationSettings { (settings) in
            if settings.authorizationStatus == .notDetermined {
                // 未选择,请求授权
                center.requestAuthorization(options: [.alert, .sound, .badge]) { (result, error) in
                    if result {
                        // 用户同意
                        // 注册通知,获取deviceToken
                        self.registerForRemoteNotifications()
                    } else {
                        print(error)
                    }
                }
            } else if settings.authorizationStatus == .authorized {
                // 已授权
                // 注册通知,获取deviceToken
                self.registerForRemoteNotifications()
                
            } else if settings.authorizationStatus == .denied {
                // 拒绝,当用户拒绝后,需要在合适的时机进行提醒,而不应该是每次启动时都去提醒
                // 弹出提示框,引导用户开启
//                if let url = URL(string: UIApplication.openSettingsURLString) {
//                    if UIApplication.shared.canOpenURL(url) {
//                        UIApplication.shared.open(url, options: [:], completionHandler: nil)
//                    }
//                }
                
            }
        }
    }
    
    // 注册通知,获取deviceToken
    func registerForRemoteNotifications () {
        // 请求授权时异步进行的,这里需要在主线程进行通知的注册
        DispatchQueue.main.async {
            UIApplication.shared.registerForRemoteNotifications()

        }
    }
    
}

这里需要注意的是,申请权限的操作是异步进行的,我们需要在主线程调用注册远程通知的方法UIApplication.shared.registerForRemoteNotifications(),成功或者失败会分别调用下面的代理方法:

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

    }
//    registerForRemoteNotifications 失败的回调
    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        
    }

正常获取到deviceToken,即表示同住注册成功,即可进行正常的消息推送了。

本地通知

iOS10中本地通知的使用和之前版本使用方式区别不大,只是使用不同的API来创建通知,这里只给出一些配置的示例,其他的直接查看相关的API或者文章的介绍。

一般的本地通知

例如10s触发的本地通知,可以这样设置:

// 创建通知内容
        let content = UNMutableNotificationContent()
        
        content.title = "ios 10 local push test"
        content.subtitle = "local push subtitle"
        content.body = "这是一个iOS 10 之后的本地通知测试文本,这里显示的是消息的详细内容"
        content.sound = .default
        content.userInfo = ["info": "这里的信息是传递给app的payload内容"]
        
        // 创建触发方式,10s后触发
        let timer = UNTimeIntervalNotificationTrigger(timeInterval: 10, repeats: false)
        
        // 创建通知请求
        let req = UNNotificationRequest(identifier: "reqid", content: content, trigger: timer)
        
        // 添加请求到通知中心
        UNUserNotificationCenter.current().add(req) { (error) in
            print(error)
        }

效果:


如果是某个固定日期时间或者某个地理范围触发的通知,可以根据上面第一部分的UNNotificationTrigger创建相应的触发器,添加到请求里即可!

带有交互的本地通知

涉及到的相关类,参考第一部分的 通知快捷操作Action 部分内容。

点击事件的交互 UNNotificationAction
// 如果点击后,需要唤起app,则options选择UNNotificationActionOptions.foreground
let okAction = UNNotificationAction(identifier: "okidentifier", title: "查看", options: UNNotificationActionOptions.foreground)
        
// 如果点击后,不需要唤起app,则options选择另外两个
        let cancel = UNNotificationAction(identifier: "cancelidentifier", title: "关闭", options: UNNotificationActionOptions.destructive)
        
        let category = UNNotificationCategory(identifier: "categoryidentifier", actions: [okAction, cancel], intentIdentifiers: [], options: UNNotificationCategoryOptions.customDismissAction)
        UNUserNotificationCenter.current().setNotificationCategories(Set.init([category]))
        
        // 创建通知内容
        let content = UNMutableNotificationContent()
        
        content.title = "ios 10 local push test"
        content.subtitle = "local push subtitle"
        content.body = "这是一个iOS 10 之后的本地通知测试文本,这里显示的是消息的详细内容"
        content.sound = .default
        content.userInfo = ["info": "这里的信息是传递给app的payload内容"]
        content.categoryIdentifier = "categoryidentifier"
        
        // 创建触发方式,10s后触发
        let timer = UNTimeIntervalNotificationTrigger(timeInterval: 10, repeats: false)
        
        // 创建通知请求
        let req = UNNotificationRequest(identifier: "reqid", content: content, trigger: timer)
        
        // 添加请求到通知中心
        UNUserNotificationCenter.current().add(req) { (error) in
            print(error)
        }

点击按钮后会调用代理方法

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

只需要创建UNTextInputNotificationAction的实例,添加到category中即可:

let okAction = UNTextInputNotificationAction(identifier: "okidentifier", title: "回复", options: .foreground, textInputButtonTitle: "快捷回复", textInputPlaceholder: "请输入。。。")
        
        
        let cancel = UNNotificationAction(identifier: "cancelidentifier", title: "关闭", options: UNNotificationActionOptions.destructive)
        
        let category = UNNotificationCategory(identifier: "categoryidentifier", actions: [okAction, cancel], intentIdentifiers: [], options: UNNotificationCategoryOptions.customDismissAction)
        UNUserNotificationCenter.current().setNotificationCategories(Set.init([category]))
        
        // 创建通知内容
        let content = UNMutableNotificationContent()
        
        content.title = "ios 10 local push test"
        content.subtitle = "local push subtitle"
        content.body = "这是一个iOS 10 之后的本地通知测试文本,这里显示的是消息的详细内容"
        content.sound = .default
        content.userInfo = ["info": "这里的信息是传递给app的payload内容"]
        content.categoryIdentifier = "categoryidentifier"
        
        // 创建触发方式,10s后触发
        let timer = UNTimeIntervalNotificationTrigger(timeInterval: 10, repeats: false)
        
        // 创建通知请求
        let req = UNNotificationRequest(identifier: "reqid", content: content, trigger: timer)
        
        // 添加请求到通知中心
        UNUserNotificationCenter.current().add(req) { (error) in
            print(error)
        }

点击之后的效果:


同样,在代理方法中可获取输入的内容:

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

移除通知

// 移除某个已触发的通知
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: ["reqid"])
        
// 移除添加的通知请求       UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: ["reqid"])

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

// 移除所有通知请求       UNUserNotificationCenter.current().removeAllPendingNotificationRequests()

远程通知 APNs(Apple Push Notification Services)

远程通知在获取到通知权限后,就可以使用一般的 Payload 来发送通知。

一般消息推送的Payload模板

{
"aps":
    {
        "alert":
        {
            "title":"iOS10 标题",
            "subtitle" : "iOS10 副标题",
            "body":"这是iOS10中远程推送的消息主体内容,这里的内容会展示在消息摘要信息里,当下拉消息框,就能够看到完整的消息内容。"
        },
        "badge":1,
        "sound":"default",
        "customInfo":{"key":"这是自定义的消息内容"}
    }
}

效果图:

当app在前台运行时,同样会走willPresent notification代理方法;当app后台运行或未打开时,走didReceive response方法;没错,和本地通知走的代理方法是一样的。我们可以通过trigger的类型来判断是本地通知,还是远程通知

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 {
            // 远程通知
        } 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 {
            // 前台运行时远程通知
        } else {
            // 前台运行时本地通知
        }
        
        completionHandler(.alert)
    }

带有交互action的远程通知

只需要在请求中心添加相应的交互category,并把其identifier添加到Payload中即可;

定义所需的交互 UNNotificationAction

let okAction = UNNotificationAction(identifier: "okidentifier", title: "查看", options: UNNotificationActionOptions.foreground)
//        let okAction = UNTextInputNotificationAction(identifier: "okidentifier", title: "回复", options: .foreground, textInputButtonTitle: "快捷回复", textInputPlaceholder: "请输入。。。")
        
        
        let cancel = UNNotificationAction(identifier: "cancelidentifier", title: "关闭", options: UNNotificationActionOptions.destructive)
        
        let category = UNNotificationCategory(identifier: "categoryidentifier", actions: [okAction, cancel], intentIdentifiers: [], options: UNNotificationCategoryOptions.customDismissAction)
        UNUserNotificationCenter.current().setNotificationCategories(Set.init([category]))

此时的Payload,需要加入 category,告诉系统需要加载哪一组的交互

{
"aps":
    {
        "alert":
        {
            "title":"iOS10 标题",
            "subtitle" : "iOS10 副标题",
            "body":"这是iOS10中远程推送的消息主体内容,这里的内容会展示在消息摘要信息里,当下拉消息框,就能够看到完整的消息内容。这是一个带有交互按钮的通知。。。"
        },
        "category":"categoryidentifier",
        "badge":1,
        "sound":"default"
    }
}

带有交互按钮的远程push


如果是需要快捷回复框,只需要像本地通知一样,创建一个UNTextInputNotificationAction 实例即可!

静默通知

发送静默通知,同iOS10之前的方式一致,修改Payload如下即可:

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

需要注意的是,静默push不会走iOS10中新的代理方法,还是在原来的代理方法进行接收反馈:

 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)
    }
上一篇 下一篇

猜你喜欢

热点阅读