Does Untimeintervalnotificationtrigger Nexttriggerdate() Give the Wrong Date

nextTriggerDate() doesn't return the 'expected' value, is there another way to obtain the next fire date of a repeating Local Notification?

Confirmed. I ran this code:

let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 120, repeats: true)
print("scheduling at", Date())
DispatchQueue.main.asyncAfter(deadline: .now()+15) {
print("checking at", Date())
UNUserNotificationCenter.current().getPendingNotificationRequests {
arr in let arr = arr
if let req = arr[0].trigger as? UNTimeIntervalNotificationTrigger {
let fd = req.nextTriggerDate()
print("trigger date", fd as Any)
}
}
}
// ... proceed to configure and schedule the notification

I also configured my user notification center delegate to receive the notification in the foreground and print the time.

Here's what I saw in the console:

scheduling at 2018-08-01 03:40:36 +0000
checking at 2018-08-01 03:40:51 +0000
trigger date Optional(2018-08-01 03:42:51 +0000)
received notification while active 2018-08-01 03:42:36 +0000

So the trigger date was reported as 2 minutes from when I checked, but the notification actually fired 2 minutes from when I scheduled it.

I'd describe that as a bug!

The one disagreement I'd have with your original question is that I get exactly the same result for a non-repeating UNTimeIntervalNotificationTrigger:

scheduling at 2018-08-01 03:45:50 +0000
checking at 2018-08-01 03:46:06 +0000
trigger date Optional(2018-08-01 03:48:06 +0000)
received notification while active 2018-08-01 03:47:50 +0000

A UNTimeIntervalNotificationTrigger also has a timeInterval property, but even that does us no good unless we know when the notification was originally scheduled — and a UNNotificationRequest provides no way to find that out.

(Just to be certain, I postponed my checking until the repeating notification had fired a couple of times, but the result was the same: nextTriggerDate is clearly adding the timeInterval to now rather than reporting the time at which the notification will next fire.)

How to get date of upcoming notification in swift?

You want to use dateComponents of the UNCalendarNotificationTrigger. try using notification.fireDate to retrieve that.

More info on Apple Developer Documentation: https://developer.apple.com/documentation/usernotifications/uncalendarnotificationtrigger

Accessing the scheduled date of a UNNotificationRequest object

can't find a way to access the scheduled fire date of the notification.

You have already shown that you understand how to get the UNNotificationTrigger. Well, UNNotificationTrigger is an abstract superclass. You need to find out what class it really is and cast it down to that class. Then you can explore its properties.

For example:

  • If it is a UNCalendarNotificationTrigger, then cast it down to a UNCalendarNotificationTrigger. Now it has a nextTriggerDate.

  • If it is a UNTimeIntervalNotificationTrigger, then cast it down to a UNTimeIntervalNotificationTrigger. Now it has a nextTriggerDate.

Edit But note that there is a massive bug: if this is a UNTimeIntervalNotificationTrigger, the nextTriggerDate will be wrong.

Why does PHP 8 return the wrong second Friday of the next Year

It is not a bug. “Second Friday in January next year” is interpreted as “second Friday in January” of this year and “next year” as +1 year. With long expressions it is not always clear in which order they are processed. It is usually better to do this in several steps.

$jan2 = date_create('next year')->modify('second friday of january');  //2022-01-14

UNCalendarNotificationTrigger not initiating

After getting more details, I guess I know why you still don't see the notifications being delivered. I'm making it in another answer to not have it too long, but I'll keep my previous answer for reference.

Maybe you were waiting for the notification with the application in foreground? I'll refer to another part of the documentation:

Scheduling and Handling Local Notifications

On the section about Handling Notifications When Your App Is in the Foreground:

If a notification arrives while your app is in the foreground, you can
silence that notification or tell the system to continue to display
the notification interface. The system silences notifications for
foreground apps by default
, delivering the notification’s data
directly to your app...

So, if that's the case, you must implement a delegate for UNUserNotificationCenter.

I suggest you something like this, where on AppDelegate you assign the delegate for UNUserNotificationCenter since documentation says it must be done before application finishes launching:

// 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])
}
}

On the view controller you have handling the notification authorization and request registration, you could do it like this:

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")
}
}
}
}

You might still have older notifications scheduled since your code was requesting them at the viewDidLoad and maybe you didn't remove them or delete the app.

You can check the pending notifications using this on your viewDidLoad for example:

        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)")")
}
}

And use randVerseCenter to remove them by their identifiers or remove all of them.



Related Topics



Leave a reply



Submit