[iOS] 通知详解: iOS 10 UserNotificat
通知相关系列文章
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)
}