如何解决UNCalendarNotificationTrigger 未启动
好的 - 我现在对这段代码感到非常沮丧,准备放弃!基本上,当模拟到模拟器或实际设备时,我让 requestAuthorisation 正常工作,但触发器永远不会启动。我在网上关注了几个人,他们的代码很容易运行!当我使用按钮启动 UNTimeIntervalNotificationTrigger 时,它可以工作,但这不是我想要的。目前在 iOS 14.3 中作为构建目标进行测试。其余的应用程序构建没有问题。我究竟做错了什么?!不禁想到,在尝试让它工作的过程中,我可能已经损坏了 info.plist 或类似的东西?!我已经测试过重复触发和不重复但都不起作用。
override func viewDidLoad() {
super.viewDidLoad()
//NOTIFICATIONS
// Step 1 - Ask the use for permission to notify
let randVerseCenter = UNUserNotificationCenter.current()
randVerseCenter.requestAuthorization(options: [.alert,.sound]){ (granted,error) in
if granted {
print("Yay - request authorisation worked!")
} else {
print ("D'oH - request Authorisation did not work!")
}
}
// Step 2 - Create the Notification Content
let randVerseContent = UNMutableNotificationContent()
randVerseContent.title = "Random Reference"
randVerseContent.body = "Random Verse"
randVerseContent.sound = UNNotificationSound.default
// Step 3 - Create the trigger for the notification by delay
let randVerseDate = Date().addingTimeInterval(30)
let randVerseDateComponents = Calendar.current.dateComponents([.year,.month,.day,.hour,.minute,.second],from: randVerseDate)
let randVerseTrigger = UNCalendarNotificationTrigger(dateMatching: randVerseDateComponents,repeats: true)
// Step 4 - Creating the request
let randVerseUUIDString = UUID().uuidString
let randVerseRequest = UNNotificationRequest(identifier: randVerseUUIDString,content: randVerseContent,trigger: randVerseTrigger)
// Step 5 - Register the request
randVerseCenter.add(randVerseRequest) { (error) in
if let error = error{
print (error.localizedDescription)
}
//Check the error parameter and handle any errors
}
}
解决方法
问题在于触发器是如何创建的。我们可以查看 UNCalendarNotificationTrigger
的文档以获得更多理解:
在需要时创建一个 UNCalendarNotificationTrigger 对象 安排在指定日期发送本地通知 和时间。您可以使用 NSDateComponents 对象,它允许您仅指定时间值 这对你来说很重要。系统使用提供的信息来 确定下一个与指定匹配的日期和时间 信息。
https://developer.apple.com/documentation/usernotifications/uncalendarnotificationtrigger
因此,当您想要创建触发器以匹配日期组件时,您可以使用 UNCalendarNotificationTrigger
。下面的代码将创建一个触发器,它会在每天早上 8:30 发送通知,因为指定了 .hour
和 .minute
组件:
var date = DateComponents()
date.hour = 8
date.minute = 30
// This trigger will match these two components - hour and minute
let trigger = UNCalendarNotificationTrigger(dateMatching: date,repeats: true)
就您而言,您使用日期的所有组件(年、月、日、小时、分钟、秒)创建了一个触发器:
let randVerseDateComponents = Calendar.current.dateComponents([.year,.month,.day,.hour,.minute,.second],from: randVerseDate)
这使得重复触发成为不可能的条件——因为不会再有 2021 年了——所以它不会被触发。
您需要考虑如何触发此通知。如果您打算在特定时间的同一秒内发送通知,则您必须仅使用 .second
日期组件:
let randVerseDateComponents = Calendar.current.dateComponents([.second],from: randVerseDate)
假设 randVerseDate
类似于 2021-01-06-20:01:35,我们使用上面的代码行。然后这将在时钟到达 35 秒时每分钟触发一次通知:20:02:35,然后是 20:03:35,然后20:04:35 等等......
在获得更多详细信息后,我想我知道为什么您仍然看不到正在发送的通知。我正在另一个答案中回答,不要太长,但我会保留 my previous answer 以供参考。
也许您正在等待应用程序在前台的通知?我将参考文档的另一部分:
Scheduling and Handling Local Notifications
关于当您的应用程序在前台时处理通知的部分:
如果您的应用在前台时收到通知,您可以 使该通知静音或告诉系统继续显示 通知界面。 系统将通知静音 默认的前台应用,提供通知数据 直接到您的应用...
因此,如果是这种情况,您必须为 UNUserNotificationCenter
实现一个委托。
我建议你这样做,在 AppDelegate 上你为 UNUserNotificationCenter
分配委托,因为文档说它必须在应用程序完成启动之前完成:
// AppDelegate.swift
@main
class AppDelegate: UIResponder,UIApplicationDelegate {
func application(_ application: UIApplication,willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
UNUserNotificationCenter.current().delegate = self
return true
}
// Rest of your code on AppDelegate...
}
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter,willPresent notification: UNNotification,withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
// Here we actually handle the notification
print("Notification received with identifier \(notification.request.identifier)")
// So we call the completionHandler telling that the notification should display a banner and play the notification sound - this will happen while the app is in foreground
completionHandler([.banner,.sound])
}
}
在您处理通知授权和请求注册的视图控制器上,您可以这样做:
class NotificationsViewController: UIViewController {
static let notificationAuthorizedNotification = NSNotification.Name(rawValue: "NotificationAuthorizedNotification")
let randVerseCenter = UNUserNotificationCenter.current()
override func viewDidLoad() {
super.viewDidLoad()
// We call this method when we know that the user granted permission,so we know we can then make notification requests
NotificationCenter.default.addObserver(self,selector: #selector(handleNotificationAuthorization),name: NotificationsViewController.notificationAuthorizedNotification,object: nil)
randVerseCenter.getNotificationSettings { [weak self] settings in
// We check current settings and asks for permission if not granted before
if settings.authorizationStatus == .notDetermined {
// Step 1 - Ask the use for permission to notify
self?.randVerseCenter.requestAuthorization(options: [.alert,.sound]){ (granted,error) in
if granted {
NotificationCenter.default.post(name: NotificationsViewController.notificationAuthorizedNotification,object: nil)
print("Yay - request authorisation worked!")
} else {
print ("D'oH - request Authorisation did not work!")
}
}
}
}
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
// We stop listening to those notifications here
NotificationCenter.default.removeObserver(self)
}
@objc
func handleNotificationAuthorization() {
// Step 2 - Create the Notification Content
let randVerseContent = UNMutableNotificationContent()
randVerseContent.title = "Random Reference"
randVerseContent.body = "Random Verse"
randVerseContent.sound = UNNotificationSound.default
// Step 3 - Create the trigger for the notification by delay
let randVerseDate = Date().addingTimeInterval(30)
let randVerseDateComponents = Calendar.current.dateComponents([.second],from: randVerseDate)
let randVerseTrigger = UNCalendarNotificationTrigger(dateMatching: randVerseDateComponents,repeats: true)
// Step 4 - Creating the request
let randVerseUUIDString = UUID().uuidString
let randVerseRequest = UNNotificationRequest(identifier: randVerseUUIDString,content: randVerseContent,trigger: randVerseTrigger)
// Step 5 - Register the request
randVerseCenter.add(randVerseRequest) { (error) in
if let error = error{
print (error.localizedDescription)
} else {
print("Successfully registered notification with id \(randVerseUUIDString) at every second \(randVerseDateComponents.second!) of a minute")
}
}
}
}
由于您的代码在 viewDidLoad
请求通知,因此您可能仍然安排了较旧的通知,而且您可能没有删除它们或删除应用程序。
您可以在 viewDidLoad
上使用它来检查待处理的通知,例如:
randVerseCenter.getPendingNotificationRequests() { requests in
for request in requests {
guard let trigger = request.trigger as? UNCalendarNotificationTrigger else { return }
print("Notification registered with id \(request.identifier) is schedulled for \(trigger.nextTriggerDate()?.description ?? "(not schedulled)")")
}
}
并使用 randVerseCenter
通过标识符删除它们或将它们全部删除。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。