[iOS] 通知详解: iOS 10 UserNotifications

通知相关系列文章
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)
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,458评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,030评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,879评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,278评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,296评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,019评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,633评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,541评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,068评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,181评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,318评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,991评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,670评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,183评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,302评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,655评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,327评论 2 358

推荐阅读更多精彩内容