Here is the scenario I am trying to solve: In my app the user has the ability to schedule daily, weekly or monthly repeating notifications. The notification content body and badge number include a dynamic Int property who's value might change daily (numOverdueStents in the example below). I am struggling with finding a way to fetch and display this dynamic value in the notification each time the notification presents, without launching the app into the foreground.
I tried implementing a UNNotificationAction followed by the didReceive response method of the UNUserNotificationCenterDelegate but I have been unsuccessful in achieving my goal.
func scheduleNotification (on timeAndDate: Date, scheduleInterval: Int){
let center = UNUserNotificationCenter.current()
center.delegate = self
let cdStentLogTVC = CDStentLogTableViewController()
let numOverdueStents = cdStentLogTVC.overdueStentCount ?? 0
//Notification
let content = UNMutableNotificationContent()
content.title = "StentLog Notification"
content.body = "You have: \(numOverdueStents) overdue stents "
content.badge = NSNumber(integerLiteral: numOverdueStents)
content.categoryIdentifier = "alert"
// Action
let action = UNNotificationAction(identifier: "show", title: "Overdue Stents?", options: .foreground)
let category = UNNotificationCategory(identifier: "alert", actions: [action], intentIdentifiers: [])
UNUserNotificationCenter.current().setNotificationCategories([category])
// Schedule notification interval
var dateComponents = DateComponents()
switch scheduleInterval {
case 0: dateComponents = Calendar.current.dateComponents([.hour, .minute], from: timeAndDate)
case 1: dateComponents = Calendar.current.dateComponents([.hour, .minute, .weekday], from: timeAndDate)
case 2: dateComponents = Calendar.current.dateComponents([.hour, .minute, .weekday, .day], from: timeAndDate)
default: dateComponents = Calendar.current.dateComponents([.hour, .minute, .weekday, .day], from: timeAndDate)
}
// Request
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
let request = UNNotificationRequest(identifier: "StentNotification", content: content, trigger: trigger)
center.add(request)
}
Here are the delegate methods:
extension NotificationPublisher: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
print("The notification is about to present")
completionHandler([.badge, .sound, .alert])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
let identifier = response.actionIdentifier
switch identifier {
case UNNotificationDismissActionIdentifier:
print("The notification was dismissed")
completionHandler()
case UNNotificationDefaultActionIdentifier:
print("The user opened the app from the notification")
completionHandler()
// This is where I was trying to act on the selected action response
case "show":
print("Custom action selected")
default:
print("The default case was called")
completionHandler()
}
}