UserNotifications
UserNotificationsUI
Human Interface Guidelines - Notifications
Local and Remote Notification Programming Guide
Introduction to Notifications
Advanced Notifications
What's New in the Apple Push Notification Service
Rich Notifications
Best Practices and What’s New in User Notifications
从iOS 10开始,与通知有关的API发生了不小的变化,在使用时,除了需要导入独立的UserNotifications框架之外,还需要获取用户授权:
import UIKit
import UserNotifications
class ViewController: UIViewController {
/// 用于标记通知权限(默认为false)
var isGrantedNotificationAccess = false
override func viewDidLoad() {
super.viewDidLoad()
// 获取通知权限
UNUserNotificationCenter.current().requestAuthorization(options: [.badge, .sound, .alert]) { (granted, error) in
// 当用户点击“Allow”时,granted的值为true,
// 当用户点击“Don't Allow”时,granted的值为false
self.isGrantedNotificationAccess = granted
// 如果没有获取到用户授权,就会执行下面的代码
if !granted {
// 可以考虑在这里执行一个弹窗,提示用户获取通知权限
print("需要获取通知权限才能发送通知.")
}
}
}
}
不管你是发送本地通知,还是远程通知,它本身就是一种中断用户的行为,因此,将是否需要接收通知的权限交还给用户,可以最大限度的提升用户体验:
一、通知的基本使用
点击“Allow”,获取发送通知的权限,以便后续顺利进行相应的演示。来到Main.storyboard文件中,布局几个按钮,然后给它们拖线。然后回到ViewController文件中,在拖线代码中实现相应的功能:
// MARK: - 发送通知
@IBAction func sendNotifications(_ sender: UIButton) {
// 如果获取到发送通知的权限
if isGrantedNotificationAccess {
// 创建通知的内容
let content = UNMutableNotificationContent()
// 设置通知默认提示音
content.sound = UNNotificationSound.default()
// 设置通知的标题
content.title = "紧急通知"
// 设置通知的内容
content.body = "起床啦!你老婆跟人跑了!😳😳😳😳😳"
/** 创建通知触发器 */
let dateComponents: Set<Calendar.Component> = [.second, .minute, .hour]
var date = Calendar.current.dateComponents(dateComponents, from: Date())
date.second = date.second! + 3
let trigger = UNCalendarNotificationTrigger(dateMatching: date, repeats: false)
// 创建发送通知请求的标识符
let identifier = "message.yourWifeRanAway"
// 创建发送通知其的请求,并且将其添加到通知中心
addNotification(identifier, content, trigger)
}
}
/// 用于创建发送通知的请求, 并将其添加到通知中心
func addNotification(_ identifier: String, _ content: UNMutableNotificationContent, _ trigger: UNNotificationTrigger?) {
// 创建通知发送请求
let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger)
// 将通知发送请求添加到发送中心
UNUserNotificationCenter.current().add(request) { (error) in
if error != nil {
print("error adding notification: \(String(describing: error?.localizedDescription))")
}
}
}
在获取到通知权限之后,就可以创建通知了。创建通知的步骤一般为:①、创建通知的内容并设置相应的属性(content);②、创建通知的触发器(trigger);③、创建发送通知请求的标识符(identifier)。完成上面三个步骤以后,就可以创建通知发送请求并将其添加到通知中心了。运行程序,点击发送通知按钮并将程序退到后台:
如果你喜欢的话,还可以把创建通知内容的代码封装到一个方法中。另外,如果觉得上面创建通知触发器的代码过于冗余,还可以使用UNTimeIntervalNotificationTrigger(timeInterval: , repeats: )函数:
// MARK: - 又发通知
@IBAction func otherNotifications(_ sender: UIButton) {
// 如果获取到发送通知授权
if isGrantedNotificationAccess {
// 调用createNotificationContent
let content = createNotificationContent()
// 创建通知触发器
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5.0, repeats: false)
// 创建发送通知请求的标识符
let identifier = "message.yourWifeRanAgain"
// 创建发送通知其的请求,并且将其添加到通知中心
addNotification(identifier, content, trigger)
}
}
/// 创建通知的内容
func createNotificationContent() -> UNMutableNotificationContent {
// 创建通知内容
let content = UNMutableNotificationContent()
// 在App图标上显示通知数量
content.badge = 5
// 设置通知默认提示音
content.sound = UNNotificationSound.default()
// 设置通知标题
content.title = "再次通知"
// 设置通知内容
content.body = "再不起床,你老婆真跟人跑了!😂😂😂😂😂"
// 设置本地通知的userInfo
content.userInfo = ["name": "Enrica"]
return content
}
和上面发送通知的代码相比,这里在创建通知内容时,额外的设置了两个属性,一个是badge,另外一个是userInfor。运行程序,效果和上面是一样的:
除了在后台会接收到通知之外,锁屏状态下也是可以收到通知的。点击“又发通知”按钮之后,快速按钮command + L键进入锁屏状态,依然可以收到通知,并且点击通知可以快速预览:
二、应用内(前台)通知
上面演示的,都是程序退到后台的情况,接下来,我们来演示一下,应用程序在前台时接收通知的情况。来到viewDidLoad方法中,设置通知中心的代理,然后遵守UNUserNotificationCenterDelegate协议,实现协议中的相关方法:
override func viewDidLoad() {
super.viewDidLoad()
// 获取通知权限
UNUserNotificationCenter.current().requestAuthorization(options: [.badge, .sound, .alert]) { (granted, error) in
// 当用户点击“Allow”时,granted的值为true,
// 当用户点击“Don't Allow”时,granted的值为false
self.isGrantedNotificationAccess = granted
// 如果没有获取到用户授权,就会执行下面的代码
if !granted {
// 可以考虑在这里执行一个弹窗,提示用户获取通知权限
print("需要获取通知权限才能发送通知.")
}
}
// 设置UNUserNotificationCenter的代理
UNUserNotificationCenter.current().delegate = self
}
// MARK: - UNUserNotificationCenterDelegate
extension ViewController: UNUserNotificationCenterDelegate {
// 实现代理方法
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
// UNNotificationPresentationOptions的值有3个,但是前台通知不需要badge
completionHandler([.alert, .sound])
}
}
因为是在前台接收通知,所以不需要badge,只需要设置alert和sound就可以了。运行程序,点击“发送通知”按钮,然后等一会儿就能看到通知了:
接下来,我们要看一下通知中心中已存在但是还未经展示的通知请求,以及已经展示过的通知请求。分别实现viewPendingNotifications(_ sender: )方法和viewDeliveredNotifications(_ sender: )方法:
// MARK: - 查看等待通知
@IBAction func viewPendingNotifications(_ sender: UIButton) {
// 从通知中心获取所有还未展示的通知请求
UNUserNotificationCenter.current().getPendingNotificationRequests { (requestList) in
// 查看当前还有多少个通知未展示
print("\(Date()) -- 还有\(requestList.count)个通知请求未经展示。")
// 遍历通知请求列表
for request in requestList {
print("未展示通知请求的标识符为: \(request.identifier), 内容为: \(request.content.body)")
}
}
}
// MARK: - 查看已发送通知
@IBAction func viewDeliveredNotifications(_ sender: UIButton) {
// 从通知中心获取已经展示过的通知
UNUserNotificationCenter.current().getDeliveredNotifications { (notifications) in
// 查看当前有多少个通知已经展示过了
print("\(Date()) -- 已经展示了\(notifications.count)个通知。")
// 遍历已经展示过的通知
for notification in notifications {
print("已展示通知请求的标识符为: \(notification.request.identifier), 内容为: \(notification.request.content.body)")
}
}
}
getPendingNotificationRequests(completionHandler: @escaping ([UNNotificationRequest]) -> Swift.Void)函数可以获取通知中心里面所有等待触发的通知,而getDeliveredNotifications(completionHandler: @escaping ([UNNotification]) -> Swift.Void)函数可以获取通知中心里面所有已经展示完成的通知。程序运行以后,快速点击“发送通知”按钮和“又发通知”按钮,在通知展示出来之前,迅速点击“查看等待通知按钮”。等所有的通知都展示完成之后,再点击“查看已发送通知”按钮,控制台会打印如下信息:
三、更新通知
如果我们重复点击“发送通知”按钮,或者“又发通知”按钮,在通知被展示出来之前,点击“查看等待通知”按钮时,你会发现此时只有一条未经展示的通知。原因是,我们通知的内容并没有发生更改,所以不管你点击多少次,它永远都只是一条通知。为了实现每点击一次,重新发送一条通知,我们需要在点击的过程中修改通知的内容:
/// 用于更改通知的内容
fileprivate var index = 0
// MARK: - 又发通知
@IBAction func otherNotifications(_ sender: UIButton) {
// 如果获取到发送通知授权
if isGrantedNotificationAccess {
// 调用createNotificationContent
let content = createNotificationContent()
// 修改content的subtitle
index += 1
content.subtitle = "你老婆跑了\(index)次!🙄🙄🙄🙄🙄"
// 创建通知触发器
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5.0, repeats: false)
// 创建发送通知请求的标识符
let identifier = "message.yourWifeRanAgain.\(index)" // 因为更改了通知的内容,所以标识符也要修改
// 创建发送通知其的请求,并且将其添加到通知中心
addNotification(identifier, content, trigger)
}
}
运行程序,连续点击“又发通知”按钮,然后快速点击“查看等待通知”按钮,你会在控制台看到n条等待的通知,并且最后展示的时候,你点了多少下,系统就会推送多少条通知:
在上面的演示代码中,我们只是通过简单修改通知的标识符来实现连续推送多条通知,接下来,我们要演示一下,通过点击“更新即将显示的通知”按钮来改变处于等待状态(也就是在通知中心里面创建了发送通知请求,但是还未展示出来)通知的内容:
/// 用于更新即将显示通知的内容(body)
let catchUp = ["还有这种事?", "不能让她跑了!赶紧起床追", "抱着衣服追...☺️☺️☺️", "边追边穿衣服...😱😱😱😱", "还好来得及,赶紧追!"]
// MARK: - 更新即将显示的通知
@IBAction func renewNextNotification(_ sender: UIButton) {
// 从通知中心获取所有未经展示的通知
UNUserNotificationCenter.current().getPendingNotificationRequests { (requests) in
// 取出通知中心里面未经展示通知列表中的第一个
if let request = requests.first {
// 如果该通知请求的标识符前缀为message.yourWifeRanAgain
if request.identifier.hasPrefix("message.yourWifeRanAgain") {
// 那么就修改通知的内容
self.updateNotification(request)
} else {
// 如果该通知请求的标识符前缀不是message.yourWifeRanAgain,则执行拷贝
let content = request.content.mutableCopy() as! UNMutableNotificationContent
// 创建通知请求,并且将其添加到通知中心
self.addNotification(request.identifier, content, request.trigger)
}
}
}
}
/// 更新即将显示通知的内容
func updateNotification(_ request: UNNotificationRequest) {
// 获取所有标识符前缀为"message.yourWifeRanAgain"的请求
if request.identifier.hasPrefix("message.yourWifeRanAgain") {
// 根据userInfo中的键取出对应的值,并且将其强转成真实的类型
var stepNumber = request.content.userInfo["index"] as! Int
// 取余运算,能保证stepNumber的值永远都在有效的范围之内,可以防止数组越界
stepNumber = (stepNumber + 1 ) % catchUp.count // catchUp总共只有4个
// 创建更新通知的内容
let updatedContent = createNotificationContent()
// 更新内容(根据stepNumber的值去数组catchUp中取出对应的值)
updatedContent.body = catchUp[stepNumber]
// 更新userInfo
updatedContent.userInfo["index"] = stepNumber
// 更新子标题
updatedContent.subtitle = request.content.subtitle
// 创建通知请求,并且将其添加到通知中心
addNotification(request.identifier, updatedContent, request.trigger)
}
}
简单的来说一下上面的代码。因为我们要通过点击“更新即将显示的通知”按钮来改变通知中心里面已经存在,但是还未展示出来通知的内容,所以我们定义了一个字符串儿数组catchUp,它里面存放的字符串儿在我们后面更改通知内容的时候要用到。renewNextNotification(_ : )这个方法就是点击按钮时执行的代码,而updateNotification(_ : )这个方法就是具体执行更改通知内容的代码。先重复点击“又发通知”按钮,然后快速点击“查看等待通知”按钮,看看通知中心有多少条等待展示的通知,并且这些通知的具体内容是什么:
从控制台打印出来的结果来看,通知的内容全部为“再不起床,你老婆真跟人跑了!😂😂😂😂😂”。接下来要快速点击“更新即将显示通知的内容”按钮。注意!考验你手速的时候到了,一定要在通知被展示出来之前点击,因为一旦通知被展示出来了,再点击“更新即将显示通知的内容”按钮就没有效果了。并且,前面点击了多少次“又发通知”按钮,后面最好是点击多少次“更新即将显示的通知”按钮:
从上面通知展示出来的结果来看,3条通知的内容分别被修改为“不能让她跑了!赶紧追”、“还好来得及,赶紧追!”和“还有这种事?”。这几条内容都是从数组catchUp中随机取出来的。
四、移除通知
只要通知还未展示出来,我们就可以通过removePendingNotificationRequests(withIdentifiers identifiers: )函数将其从通知中心移除:
// MARK: - 移除通知
@IBAction func removeNotifications(_ sender: UIButton) {
// 从通知中心获取所有还未展示的通知请求
UNUserNotificationCenter.current().getPendingNotificationRequests { (requests) in
if let request = requests.first {
// 根据所给的标识符,移除所有与之对应的还未展示的通知
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [request.identifier])
}
// 一次性移除所有的通知
// UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
}
}
上面那个函数是通过通知的标识符来移除对应的通知,其实还可以用removeAllPendingNotificationRequests()函数一次性移除所有未经展示的通知。可以快速点击发送通知的按钮,然后点击“查看等待通知”按钮查看通知中心有多少个未经展示的通知,最后在通知展示之前点击“移除通知”按钮来移除它们:
五、可交互通知
从iOS 8之后,通知里面就可以进行交互了,不过在此之前你需要先进行注册,而且最好是在程序已启动时就进行相应的注册。来到AppDelegate文件中,先导入头文件UserNotifications,然后在application(_ : , didFinishLaunchingWithOptions : ) -> Bool这个函数中进行注册:
/// 设置通知的category
func setCategories() {
/** 1、创建action */
// 可输入文本的action
let textInputAction = UNTextInputNotificationAction(identifier: "text.input", title: "回复", options: [], textInputButtonTitle: "发送", textInputPlaceholder: "请在这里输入文字进行回复")
// 推送下一条
let nextAction = UNNotificationAction(identifier: "next.action", title: "推送下一条", options: [])
// 停止推送
let stopAction = UNNotificationAction(identifier: "stop.action", title: "停止推送", options: [])
// 稍后再推送
let sentLaterAction = UNNotificationAction(identifier: "sent.later.action", title: "稍后推送", options: [])
/** 2、创建category */
// 创建第一个category
let sendCategory = UNNotificationCategory(identifier: "send.category", actions: [stopAction], intentIdentifiers: [], options: [])
// 创建第二个category
let otherCategory = UNNotificationCategory(identifier: "other.category", actions: [nextAction, textInputAction, sentLaterAction, stopAction], intentIdentifiers: [], options: [])
/** 3、在通知中心设置category */
// 设置category
UNUserNotificationCenter.current().setNotificationCategories([sendCategory, otherCategory])
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// 注册可交互通知
setCategories()
return true
}
回到ViewController文件中,分别在sendNotifications(_ : )和createNotificationContent() -> UNMutableNotificationContent函数中设置content的categoryIdentifier:
// 在sendNotifications(_ : )这个函数中设置categoryIdentifier
content.categoryIdentifier = "send.category"
// 在createNotificationContent() -> UNMutableNotificationContent中设置categoryIdentifier
content.categoryIdentifier = "other.category"
除了上述两个步骤之外,还要实现UNUserNotificationCenterDelegate中的userNotificationCenter(_ : , didReceive : , withCompletionHandler : )这个代理方法:
// 用于实现可交互的通知
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
// 取出actionIdentifier
let action = response.actionIdentifier
// 取出发送请求
let request = response.notification.request
// 如果用户点击了"推送下一条"按钮
if action == "next.action" {
// 调用更新即将显示通知内容的方法,更新下一条内容
updateNotification(request)
}
// 如果用户点击了"停止推送"按钮
if action == "stop.action" {
// 将带有该条标识符的通知从通知中心移除
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [request.identifier])
}
// 如果用户点击了"稍后再推送"按钮
if action == "sent.later.action" {
// 创建触发器
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5.0, repeats: false)
// 重新创发送通知的请求
let newRequest = UNNotificationRequest(identifier: request.identifier, content: request.content, trigger: trigger)
// 将通知发送请求添加到发送中心
UNUserNotificationCenter.current().add(newRequest, withCompletionHandler: { (error) in
if error != nil {
// 如果有错误
print("\(String(describing: error?.localizedDescription))")
}
})
}
// 如果用户点击了"回复"按钮
if action == "text.input" {
// 将接收到的response内容转换成UNTextInputNotificationResponse
let textResponse = response as! UNTextInputNotificationResponse
// 创建通知内容
let newContent = request.content.mutableCopy() as! UNMutableNotificationContent
// 将回复的内容设置为newContent的子标题
newContent.subtitle = textResponse.userText
// 将回复的内容作为通知内容添加通知中心
addNotification(request.identifier, newContent, request.trigger)
}
// 函数回调
completionHandler()
}
接下来,我们就可以运行程序进行相应的演示了。先点击“发送通知”按钮,演示比较简单的,因为它里面只有“停止推送”一个交互按钮:
上面那个通知比较简单,展开通知详情之后,它里面只有一个交互按钮,点击"停止推送"以后,系统就不会再推送通知了。接下来,我们要点击"又发通知"按钮,来演示更为复杂的交互通知:
从上面通知展开的详情来看,它里面总过有4个可供交互的按钮,我们先来演示点击"推送下一条"action按钮,看看会发生什么情况:
和上面那条通知的内容进行比较,当我们点击"推送下一条"按钮之后,系统会在5秒钟之后在推送一条通知,并且通知的内容会发生改变,这是因为我们在代理方法中调用了updateNotification()方法。接下来,我们点击"回复"action,看看会发生什么情况:
当我们点击"回复"action按钮之后,系统会弹出输入键盘,输入相关的内容之后点击发送按钮,过一会儿系统又会将我们发送的文本作为通知的内容进行推送。最后,我们再来演示一下点击"稍后推送"action按钮:
点击"稍后推送"action按钮之后,系统不会更改通知的任何内容,它会在5秒钟之后,将原通知原封不动的再推送一遍。当我们点击"停止推送"action按钮之后,系统不会再推送任何通知了,因为与该标识符有关的通知被从通知中心移除了。
六、多媒体通知
除了上面哪几种形式的通知意外,还可以推送音频通知、视频通知,以及图片通知(静态图片和动态图片都可以)。下面我们就来演示一下多媒体通知。
/// 加载音频或者视频资源
func notificationAttachment(_ identifier: String, _ resource: String, _ type: String) -> [UNNotificationAttachment] {
// 创建音频或视频通知的标识符
let extendedIdentifier = identifier + "." + type // send.video.mp4
// 从Bundle中获取资源所在的路径
guard let path = Bundle.main.path(forResource: resource, ofType: type) else {
print("找不到文件\(resource).\(type)!")
// 返回空的数组
return []
}
// 将资源路径转化为URL地址
let multimediaURL = URL(fileURLWithPath: path)
// 进行错误处理(先尝试操作,如果失败了,则进行错误处理)
do {
// 先尝试根据标识符和资源URL创建attachement
let attachement = try UNNotificationAttachment(identifier: extendedIdentifier, url: multimediaURL, options: nil)
// 返回创建成功的attachement
return [attachement]
}
catch {
print("attachement加载失败!")
// 如果创建失败,则返回空的数组
return []
}
}
// MARK: - 发送通知
@IBAction func sendNotifications(_ sender: UIButton) {
// 如果获取到发送通知的权限
if isGrantedNotificationAccess {
// 创建通知的内容
let content = UNMutableNotificationContent()
// 设置通知默认提示音
content.sound = UNNotificationSound.default()
// 设置通知的标题
content.title = "难念的经"
// 设置通知的内容
content.body = "古装群像·香港电影·红颜乱入版"
// 设置categoryIdentifier
content.categoryIdentifier = "send.category"
/** 加载多媒体通知 */
// 将标识符、文件名称和扩展名作为参数传递进去
let attachement = notificationAttachment("send.video", "难念的经", "mp4")
// 设置内容的attachments
content.attachments = attachement
/** 创建通知触发器 */
let dateComponents: Set<Calendar.Component> = [.second, .minute, .hour]
var date = Calendar.current.dateComponents(dateComponents, from: Date())
date.second = date.second! + 3
let trigger = UNCalendarNotificationTrigger(dateMatching: date, repeats: false)
// 创建发送通知请求的标识符
let identifier = "message.yourWifeRanAway"
// 创建发送通知其的请求,并且将其添加到通知中心
addNotification(identifier, content, trigger)
}
}
需要注意的是,在使用UNNotificationAttachment创建attachement的过程中,可以在其options参数中设置视频的某一帧作为通知的封面,这一功能待会在后面设置GIF动画通知时再做演示。我们先来看一下视频通知的效果:
视频通知在推送时,其最右边会有一个图片预览,而这张预览图片可以通过UNNotificationAttachment在创建attachement对象时的参数options来控制。比如说设置该值为[UNNotificationAttachmentOptionsThumbnailTimeKey: 10],其中10表示缩略图的时间键值,可以理解为视频中的第10帧。点击视频的播放按钮就可以播放了:
点击视频中的任意位置就可以停止。除了可以推送视频通知意外,还可以推送音频通知。推送音频通知的方法和推送视频通知是几乎是一毛一样的。所以在点击"发送通知"按钮的实现代码中,修改content的相关属性,并且在创建attachement的时候,将音频文件的标识符、文件名称和扩展名传递过去:
// 设置通知的标题
content.title = "The Sound of Silence"
// 设置通知的内容
content.body = "Paul Simon & Garfunkel"
// 设置categoryIdentifier
content.categoryIdentifier = "send.category"
/** 加载多媒体通知 */
// 将标识符、文件名称和扩展名作为参数传递进去
let attachement = notificationAttachment("send.music", "The Sound of Silence", "mp3")
点击"发送通知"按钮,等到通知推送以后,点击详情就可以播放音频文件了:
我们接下来要推送图片通知。先来看下一GIF图片通知如何实现:
// 动图通知
func setGif() -> [UNNotificationAttachment] {
// 创建通知标识符
let extendedIdentifier = "set.gif"
// 从Bundle中获取资源所在的路径
guard let path = Bundle.main.path(forResource: "动一动04", ofType: "gif") else {
print("找不到文件!")
// 返回空的数组
return []
}
// 如果成功的加载到资源
let gifURL = URL(fileURLWithPath: path)
do {
// 先尝试根据标识符和资源URL创建attachement(并且设置GIF的某一帧作为通知封面)
let attachement = try UNNotificationAttachment(identifier: extendedIdentifier, url: gifURL, options: [UNNotificationAttachmentOptionsThumbnailTimeKey: 11])
// 返回创建成功的attachement
return [attachement]
}
catch {
print("attachement加载失败!")
// 创建失败则返回空的数组
return []
}
}
// MARK: - 又发通知
@IBAction func otherNotifications(_ sender: UIButton) {
// 如果获取到发送通知授权
if isGrantedNotificationAccess {
// 调用createNotificationContent
let content = createNotificationContent()
// 创建通知触发器
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 2.0, repeats: false)
// 创建发送通知请求的标识符
let identifier = "message.yourWifeRanAgain"
// 创建发送通知其的请求,并且将其添加到通知中心
addNotification(identifier, content, trigger)
}
}
/// 创建通知的内容
func createNotificationContent() -> UNMutableNotificationContent {
// 创建通知内容
let content = UNMutableNotificationContent()
// 设置通知默认提示音
content.sound = UNNotificationSound.default()
// 设置通知标题
content.title = "来,屁股扭起来!"
// 设置通知内容
content.body = "脖子扭扭, 屁股扭扭, 早睡早起,咱们来做运动!😂😂😂"
// 设置categoryIdentifier
content.categoryIdentifier = "other.category"
// 设置attachments,用于推送GIF通知
content.attachments = setGif()
return content
}
点击“又发通知”按钮,然后再展开通知详情进行查看:
除了可以推送GIF图片通知以外,我们还可以推送JPG图片通知。下面,我们先来实现一个加载JPG图片资源并创建UNNotificationAttachment数组对象的函数,然后在updateNotification(_ : )函数中调用它,并且将其设置为content的attachments:
/// JPG图片通知
func setImages(_ step: Int) -> [UNNotificationAttachment] {
// 根据传递进来的步长创建字符串
let stepString = String(format: "%i", step)
// 设置每一条图片通知的标识符
let identifier = "set.image." + stepString
// 拼接图片的名称
let resource = "跑了0" + stepString
// 图片的扩展名
let type = "jpg"
// 调用notificationAttachment()函数并返回
return notificationAttachment(identifier, resource, type)
}
/// 更新即将显示通知的内容
func updateNotification(_ request: UNNotificationRequest) {
// 获取所有标识符前缀为"message.yourWifeRanAgain"的请求
if request.identifier.hasPrefix("message.yourWifeRanAgain") {
// 根据userInfo中的键取出对应的值,并且将其强转成真实的类型
var stepNumber = request.content.userInfo["index"] as! Int
// 取余运算,能保证stepNumber的值永远都在有效的范围之内,可以防止数组越界
stepNumber = (stepNumber + 1 ) % catchUp.count // catchUp总共只有4个
// 创建更新通知的内容
let updatedContent = createNotificationContent()
// 更新内容(根据stepNumber的值取数组catchUp中取出对应的值)
updatedContent.body = catchUp[stepNumber]
// 更新userInfo
updatedContent.userInfo["index"] = stepNumber
// 更新子标题
updatedContent.subtitle = request.content.subtitle
/** 设置JPG图片通知 */
updatedContent.attachments = setImages(stepNumber)
// 创建通知请求,并且将其添加到通知中心
addNotification(request.identifier, updatedContent, request.trigger)
}
}
运行程序,点击“又发通知”按钮进行相应的操作:
至此,我们本地通知的演示就搞完了,我也懒得检查了😂😂😂😂😂,代码参见UserNotificationsDemo.