Swift UserNotifications用户通知
Swift UserNotifications 用户通知基础概念
在 iOS、iPadOS、macOS、watchOS 和 tvOS 应用开发中,用户通知(User Notifications)是一种强大的功能,它允许应用在适当的时候向用户推送信息,即便应用当前不在前台运行。Swift 的 UserNotifications
框架为开发者提供了一套丰富且灵活的 API 来管理和呈现这些通知。
通知的类型
- 本地通知(Local Notifications):这类通知由设备上的应用直接生成并发送。例如,日历应用可以在事件即将开始时发送本地通知提醒用户。本地通知不需要网络连接,完全由设备端触发。
- 远程通知(Remote Notifications):通过服务器发送到用户设备的通知。像社交媒体应用,当有新消息、点赞或评论时,服务器会向用户设备推送远程通知。远程通知依赖于网络连接和应用的推送服务配置。
通知的组成部分
- 标题(Title):简短地概括通知的主题,吸引用户注意力。
- 正文(Body):详细描述通知的具体内容,为用户提供更多信息。
- 附件(Attachment):可以是图片、视频或音频等媒体文件,丰富通知的展示形式。例如,图片分享应用可以在通知中附带新上传图片的预览。
- 操作(Actions):允许用户直接在通知上执行某些操作,如回复消息、删除事项等,无需打开应用。
配置 UserNotifications 框架
在使用 UserNotifications
框架之前,需要在项目中进行相应的配置。
导入框架
在 Swift 文件的开头,使用 import
关键字导入 UserNotifications
框架:
import UserNotifications
请求授权
为了向用户发送通知,应用首先需要获得用户的授权。在 iOS 中,可以在应用启动时请求授权,示例代码如下:
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in
if granted {
print("Notification authorization granted.")
} else if let error = error {
print("Notification authorization failed: \(error)")
}
}
在上述代码中,requestAuthorization(options:completionHandler:)
方法用于请求授权,options
参数指定了应用希望获得的通知权限,这里包括显示提醒、播放声音和设置应用图标徽章数。completionHandler
是授权请求完成后的回调,granted
参数表示用户是否授权,error
参数如果存在则表示授权过程中出现的错误。
获取当前授权状态
有时候,需要检查当前应用的通知授权状态,可以使用以下代码:
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
switch settings.authorizationStatus {
case .authorized:
print("Notification authorization is authorized.")
case .denied:
print("Notification authorization is denied.")
case .notDetermined:
print("Notification authorization is not determined yet.")
case .provisional:
print("Notification authorization is provisional.")
@unknown default:
print("Unknown authorization status.")
}
}
getNotificationSettings(completionHandler:)
方法会在完成后调用 completionHandler
,通过 settings.authorizationStatus
可以获取当前的授权状态。.authorized
表示用户已授权;.denied
表示用户拒绝授权;.notDetermined
表示用户尚未做出决定;.provisional
是 iOS 12 引入的临时授权状态,应用可以在这种状态下显示有限形式的通知。
创建和发送本地通知
创建 UNMutableNotificationContent
UNMutableNotificationContent
类用于配置通知的内容,包括标题、正文、声音、徽章等。以下是一个简单的示例:
let content = UNMutableNotificationContent()
content.title = "新消息"
content.body = "你收到了一条新消息,请查看。"
content.sound = UNNotificationSound.default
content.badge = 1
在上述代码中,首先创建了一个 UNMutableNotificationContent
实例 content
。然后设置了通知的标题为“新消息”,正文为“你收到了一条新消息,请查看。”,声音使用默认声音,徽章数设置为 1。
创建 UNNotificationRequest
UNNotificationRequest
类用于创建通知请求,它关联了 UNMutableNotificationContent
和触发通知的条件。以下是一个基于时间触发的通知请求示例:
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
let request = UNNotificationRequest(identifier: "newMessageNotification", content: content, trigger: trigger)
在上述代码中,UNTimeIntervalNotificationTrigger
用于创建一个基于时间间隔触发的通知触发器,这里设置为 5 秒后触发,并且不重复。UNNotificationRequest
的构造函数接收三个参数:identifier
是通知的唯一标识符,用于管理和取消特定通知;content
是之前创建的 UNMutableNotificationContent
实例;trigger
是通知的触发条件。
添加通知请求到 UNUserNotificationCenter
创建好通知请求后,需要将其添加到 UNUserNotificationCenter
中,以便系统在合适的时机发送通知:
UNUserNotificationCenter.current().add(request) { (error) in
if let error = error {
print("Failed to add notification request: \(error)")
}
}
add(_:completionHandler:)
方法将通知请求添加到通知中心,并在完成后调用 completionHandler
。如果添加过程中出现错误,error
参数将包含错误信息。
通知的触发条件
基于时间的触发
除了前面示例中的 UNTimeIntervalNotificationTrigger
,还可以使用 UNCalendarNotificationTrigger
基于日历时间触发通知。例如,每天早上 8 点发送通知:
var dateComponents = DateComponents()
dateComponents.hour = 8
dateComponents.minute = 0
dateComponents.second = 0
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
let content = UNMutableNotificationContent()
content.title = "早安"
content.body = "美好的一天开始啦!"
content.sound = UNNotificationSound.default
let request = UNNotificationRequest(identifier: "morningNotification", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { (error) in
if let error = error {
print("Failed to add notification request: \(error)")
}
}
在上述代码中,首先创建了 DateComponents
实例,设置小时为 8,分钟和秒为 0。然后使用 UNCalendarNotificationTrigger
根据这些日历组件创建触发器,并设置为重复触发。接着创建通知内容和请求,并添加到通知中心。
基于位置的触发
UNLocationNotificationTrigger
可用于基于用户位置触发通知。例如,当用户进入某个特定地理区域时发送通知:
import CoreLocation
let region = CLCircularRegion(center: CLLocationCoordinate2D(latitude: 37.7749, longitude: -122.4194), radius: 100, identifier: "myLocationRegion")
let trigger = UNLocationNotificationTrigger(region: region, repeats: false)
let content = UNMutableNotificationContent()
content.title = "欢迎来到这里"
content.body = "你已到达指定地点。"
content.sound = UNNotificationSound.default
let request = UNNotificationRequest(identifier: "locationNotification", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { (error) in
if let error = error {
print("Failed to add notification request: \(error)")
}
}
在上述代码中,首先导入了 CoreLocation
框架,然后创建了一个圆形地理区域 region
,中心坐标为 (37.7749, -122.4194),半径为 100 米,并指定了标识符。接着使用 UNLocationNotificationTrigger
根据该区域创建触发器,设置为不重复触发。之后创建通知内容和请求,并添加到通知中心。需要注意的是,使用基于位置的触发需要用户授予应用位置权限。
处理通知交互
处理通知点击
当用户点击通知时,可以在应用中进行相应的处理。在 iOS 应用的 AppDelegate
中,可以实现以下方法:
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
let identifier = response.notification.request.identifier
if identifier == "newMessageNotification" {
// 处理新消息通知点击逻辑
print("用户点击了新消息通知")
}
completionHandler()
}
在上述代码中,userNotificationCenter(_:didReceive:withCompletionHandler:)
方法在用户点击通知时被调用。通过 response.notification.request.identifier
可以获取通知的标识符,根据标识符进行相应的处理逻辑。处理完成后,需要调用 completionHandler
。
自定义通知操作
除了默认的通知点击操作,还可以为通知添加自定义操作。例如,为消息通知添加“回复”和“删除”操作:
let replyAction = UNTextInputNotificationAction(identifier: "replyAction", title: "回复", options: [], textInputButtonTitle: "发送", textInputPlaceholder: "输入回复内容")
let deleteAction = UNNotificationAction(identifier: "deleteAction", title: "删除", options: .destructive)
let category = UNNotificationCategory(identifier: "messageCategory", actions: [replyAction, deleteAction], intentIdentifiers: [], options: [])
UNUserNotificationCenter.current().setNotificationCategories([category])
在上述代码中,首先创建了一个 UNTextInputNotificationAction
类型的“回复”操作 replyAction
,它允许用户输入文本。identifier
是操作的唯一标识符,title
是显示在通知上的标题,textInputButtonTitle
是输入框的发送按钮标题,textInputPlaceholder
是输入框的占位文本。然后创建了一个普通的 UNNotificationAction
类型的“删除”操作 deleteAction
,设置 options
为 .destructive
以显示为红色的删除样式。接着创建了一个 UNNotificationCategory
实例 category
,将“回复”和“删除”操作添加到该类别中。最后,通过 UNUserNotificationCenter.current().setNotificationCategories(_:)
方法将该类别设置到通知中心。
在 AppDelegate
中处理自定义操作:
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
let identifier = response.actionIdentifier
if identifier == "replyAction" {
if let text = response.textInput {
// 处理回复内容
print("用户回复内容:\(text)")
}
} else if identifier == "deleteAction" {
// 处理删除逻辑
print("用户点击了删除操作")
}
completionHandler()
}
在上述代码中,根据 response.actionIdentifier
判断用户点击的是哪个操作。如果是“回复”操作,通过 response.textInput
获取用户输入的文本;如果是“删除”操作,则执行相应的删除逻辑。
远程通知
远程通知的工作原理
远程通知通过苹果的推送通知服务(APNs)来实现。应用服务器将通知发送到 APNs,APNs 再将通知推送到用户设备上的应用。应用在启动时需要向系统注册远程通知,获取设备令牌(Device Token),并将设备令牌发送到应用服务器。服务器使用设备令牌来标识特定的设备,并向其发送远程通知。
注册远程通知
在 iOS 应用的 AppDelegate
中,可以注册远程通知:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in
if granted {
DispatchQueue.main.async {
application.registerForRemoteNotifications()
}
} else if let error = error {
print("Notification authorization failed: \(error)")
}
}
} else {
let settings = UIUserNotificationSettings(types: [.alert, .sound, .badge], categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
}
return true
}
在上述代码中,首先检查当前系统版本是否支持 iOS 10.0 及以上。如果支持,使用 UNUserNotificationCenter
请求通知授权,授权成功后在主线程中调用 application.registerForRemoteNotifications()
注册远程通知。如果系统版本低于 iOS 10.0,则使用旧的 UIUserNotificationSettings
方式请求授权并注册远程通知。
接收设备令牌
当应用成功注册远程通知后,系统会回调 AppDelegate
中的 application(_:didRegisterForRemoteNotificationsWithDeviceToken:)
方法,在该方法中可以获取设备令牌:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
let token = tokenParts.joined()
print("Device Token: \(token)")
// 将设备令牌发送到应用服务器
}
在上述代码中,将 deviceToken
转换为十六进制字符串形式,并打印出来。通常,需要将这个设备令牌发送到应用服务器,以便服务器向该设备发送远程通知。
处理远程通知接收
当应用接收到远程通知时,会调用 AppDelegate
中的相应方法。在 iOS 10.0 及以上,可以使用 UNUserNotificationCenterDelegate
的方法来处理:
@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .sound, .badge])
}
@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
// 处理远程通知中的用户信息
print("Remote notification userInfo: \(userInfo)")
completionHandler()
}
在 userNotificationCenter(_:willPresent:withCompletionHandler:)
方法中,如果应用在前台运行,通过 completionHandler
设置通知的展示选项,这里设置为显示提醒、播放声音和设置徽章。在 userNotificationCenter(_:didReceive:withCompletionHandler:)
方法中,通过 response.notification.request.content.userInfo
获取远程通知中的用户信息,并进行相应的处理。
通知附件
添加通知附件
通知附件可以是图片、视频或音频等文件。以下是添加图片附件的示例:
let fileURL = Bundle.main.url(forResource: "example", withExtension: "jpg")
do {
let attachment = try UNNotificationAttachment(identifier: "imageAttachment", url: fileURL!, options: nil)
let content = UNMutableNotificationContent()
content.title = "图片通知"
content.body = "这里有一张新图片。"
content.attachments = [attachment]
content.sound = UNNotificationSound.default
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
let request = UNNotificationRequest(identifier: "imageNotification", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { (error) in
if let error = error {
print("Failed to add notification request: \(error)")
}
}
} catch {
print("Failed to create attachment: \(error)")
}
在上述代码中,首先获取应用主 bundle 中的图片文件 URL。然后使用 UNNotificationAttachment
的构造函数创建附件,identifier
是附件的唯一标识符,url
是附件文件的 URL。接着创建通知内容,将附件添加到 attachments
数组中。之后创建触发器、通知请求,并添加到通知中心。如果创建附件过程中出现错误,会捕获并打印错误信息。
显示通知附件
当通知包含附件时,系统会根据附件类型自动以合适的方式显示。对于图片附件,会在通知中显示图片预览;对于视频和音频附件,会显示相应的播放按钮。用户可以点击附件进行查看或播放。
通知的管理和调试
取消通知
可以根据通知的标识符取消特定的通知。例如,取消之前创建的“newMessageNotification”通知:
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: ["newMessageNotification"])
removePendingNotificationRequests(withIdentifiers:)
方法会取消所有标识符在指定数组中的未发送通知请求。
清除所有通知
如果需要清除设备上应用的所有通知,可以使用以下方法:
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
UNUserNotificationCenter.current().removeAllDeliveredNotifications()
removeAllPendingNotificationRequests()
方法会取消所有未发送的通知请求,removeAllDeliveredNotifications()
方法会清除设备上已经显示过的所有通知。
调试通知
在开发过程中,可以通过 Xcode 的调试功能来查看通知相关的日志。在设备控制台中,可以查看通知授权、发送、接收等操作的详细信息。此外,还可以使用 print
语句在代码中输出关键步骤的信息,以便定位问题。例如,在通知请求添加失败时打印错误信息,有助于快速发现和解决问题。同时,对于远程通知,可以在服务器端记录发送日志,与客户端的接收情况进行对比调试。
通过以上对 Swift UserNotifications
框架的详细介绍,开发者可以全面掌握如何在应用中有效地管理和利用用户通知功能,为用户提供更好的交互体验。无论是本地通知还是远程通知,都能根据应用的需求进行灵活配置和处理,满足不同场景下的通知需求。