I'm learning the new notification system but I'm having trouble with actions. The notification works, but I do't get an action with it. I'm following a tutorial on https://www.appcoda.com/ios10-user-notifications-guide/ but I don't seem to get actions to appear with notification.
As you can see the commented out part in func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil)is where I cannot seem to get where it goes, can anyone see where I'm mistaking?
import UIKit
import UserNotifications
#UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func scheduleNotification(at date: Date) {
UNUserNotificationCenter.current().delegate = self
//compone a new Date components because components directly from Date don't work
let calendar = Calendar(identifier: .gregorian)
let components = calendar.dateComponents(in: .current, from: date)
let newComponents = DateComponents(calendar: calendar, timeZone: .current, month: components.month, day: components.day, hour: components.hour, minute: components.minute)
//create the trigger with above new date components, with no repetitions
let trigger = UNCalendarNotificationTrigger(dateMatching: newComponents, repeats: false)
//create the content for the notification
let content = UNMutableNotificationContent()
content.title = "Tutorial Reminder"
content.body = "Just a reminder to read your tutorial over at appcoda.com!"
content.sound = UNNotificationSound.default()
// notification action category
//add an image to notification
//convert logo to url
if let path = Bundle.main.path(forResource: "logo", ofType: "png") {
let url = URL(fileURLWithPath: path)
do { // because UNNotificationAttachment is mark as throwing we need an attach block for handling errors
let attachment = try UNNotificationAttachment(identifier: "logo", url: url, options: nil)
content.attachments = [attachment]
content.categoryIdentifier = "myCategory"
} catch {
print("The attachment was not loaded.")
}
}
//create the request for notification with desired parameters
let request = UNNotificationRequest(identifier: "textNotification", content: content, trigger: trigger)
//add the request to notification center after removing all notifications
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
UNUserNotificationCenter.current().add(request) {(error) in
if let error = error {
print("Uh oh! We had an error: \(error)")
}
}
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
// let action = UNNotificationAction(identifier: "remindLater", title: "Remind me later", options: [])
// let category = UNNotificationCategory(identifier: "myCategory", actions: [action], intentIdentifiers: [], options: [])
// UNUserNotificationCenter.current().setNotificationCategories([category])
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) {(accepted, error) in
if !accepted {
// print("Notification access denied.")
// let action = UNNotificationAction(identifier: "remindLater", title: "Remind me later", options: [])
// let category = UNNotificationCategory(identifier: "myCategory", actions: [action], intentIdentifiers: [], options: [])
// UNUserNotificationCenter.current().setNotificationCategories([category])
}
}
let action = UNNotificationAction(identifier: "remindLater", title: "Remind me later", options: [])
let category = UNNotificationCategory(identifier: "myCategory", actions: [action], intentIdentifiers: [], options: [])
UNUserNotificationCenter.current().setNotificationCategories([category])
return true
}
}
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
if response.actionIdentifier == "remindLater" {
let newDate = Date(timeInterval: 5, since: Date())
scheduleNotification(at: newDate)
}
// UNUserNotificationCenter.current().delegate = self
}
}
EDIT:
after #VIP-DEV answer I changed the code, to add the reminder in it's own action, into:
import UIKit
import UserNotifications
#UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
configureCategory()
triggerNotification(at: Date())
requestAuth()
return true
}
private let category = "Notification.Category.Read"
private let readActionIdentifier = "Read"
private let waitActionIdentifier = "Wait"
private func requestAuth() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (success, error) in
if let error = error {
print("Request Authorization Failed (\(error), \(error.localizedDescription))")
}
}
}
func triggerNotification(at date: Date) {
// Create Notification Content
let notificationContent = UNMutableNotificationContent()
//compone a new Date components because components directly from Date don't work
let calendar = Calendar(identifier: .gregorian)
let components = calendar.dateComponents(in: .current, from: date)
let newComponents = DateComponents(calendar: calendar, timeZone: .current, month: components.month, day: components.day, hour: components.hour, minute: components.minute)
//create the trigger with above new date components, with no repetitions
// Configure Notification Content
notificationContent.title = "Hello"
notificationContent.body = "Kindly read this message."
// Set Category Identifier
notificationContent.categoryIdentifier = category
// Add Trigger
// let notificationTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 10.0, repeats: false)
let trigger = UNCalendarNotificationTrigger(dateMatching: newComponents, repeats: false)
// // Create Notification Request
let notificationRequest = UNNotificationRequest(identifier: "test_local_notification", content: notificationContent, trigger: trigger)
//
// Add Request to User Notification Center
UNUserNotificationCenter.current().add(notificationRequest) { (error) in
if let error = error {
print("Unable to Add Notification Request (\(error), \(error.localizedDescription))")
}
}
}
private func configureCategory() {
// Define Actions
let read = UNNotificationAction(identifier: readActionIdentifier, title: "Read", options: [])
let wait = UNNotificationAction(identifier: waitActionIdentifier, title : "Wait", options: [])
// Define Category
let readCategory = UNNotificationCategory(identifier: category, actions: [read, wait], intentIdentifiers: [], options: [])
// Register Category
UNUserNotificationCenter.current().setNotificationCategories([readCategory])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
switch response.actionIdentifier {
case readActionIdentifier:
print("Read tapped")
case waitActionIdentifier:
let NewDate = Date(timeInterval: 20, since: Date())
triggerNotification(at: NewDate)
print("Wait tapped")
default:
print("Other Action")
}
completionHandler()
}
}
and
class ViewController: UIViewController {
#IBAction func datePickerDidSelectNewDate(_ sender: UIDatePicker) {
let selectedDate = sender.date
let delegate = UIApplication.shared.delegate as? AppDelegate
// delegate?.scheduleNotification(at: selectedDate)
delegate?.triggerNotification(at: selectedDate)
}
}
Now I don't get to set new notification when tap on wait button. where do I have to set let NewDate = Date(timeInterval: 20, since: Date())
triggerNotification(at: NewDate)? I thought it went in case waitActionIdentifier but I don't even get the print to console.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
UNUserNotificationCenter.current().delegate = self
configureCategory()
triggerNotification()
requestAuth()
return true
}
private let category = "Notification.Category.Read"
private let actionIdentifier = "Read"
private func requestAuth() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (success, error) in
if let error = error {
print("Request Authorization Failed (\(error), \(error.localizedDescription))")
}
}
}
private func triggerNotification() {
// Create Notification Content
let notificationContent = UNMutableNotificationContent()
// Configure Notification Content
notificationContent.title = "Hello"
notificationContent.body = "Kindly read this message."
// Set Category Identifier
notificationContent.categoryIdentifier = category
// Add Trigger
let notificationTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 3.0, repeats: false)
// Create Notification Request
let notificationRequest = UNNotificationRequest(identifier: "test_local_notification", content: notificationContent, trigger: notificationTrigger)
// Add Request to User Notification Center
UNUserNotificationCenter.current().add(notificationRequest) { (error) in
if let error = error {
print("Unable to Add Notification Request (\(error), \(error.localizedDescription))")
}
}
}
private func configureCategory() {
// Define Actions
let read = UNNotificationAction(identifier: actionIdentifier, title: "Read", options: [])
// Define Category
let readCategory = UNNotificationCategory(identifier: category, actions: [read], intentIdentifiers: [], options: [])
// Register Category
UNUserNotificationCenter.current().setNotificationCategories([readCategory])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
switch response.actionIdentifier {
case actionIdentifier:
print("Read tapped")
default:
print("Other Action")
}
completionHandler()
}
The declaration of the category identifier was declared as private.
Now the Notification actions work as expected.
Thanks to VIP-DEV's answer I could find how to correct my code.
Related
I am able to open a specific view (ToDoView) when I use categories with actions for my notification.
But what I would like to achieve is that a specific view gets also opened when I click on the notification itself.
Maybe this is super simple to solve, but I couldn't find out yet using SwiftUI.
By the way: This code only works if the app still runs in the background, otherwise i land at ContentView, which is also not optimal.
AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
UNUserNotificationCenter.current().delegate = self
return true
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
if response.actionIdentifier == "open" {
NotificationCenter.default.post(name: NSNotification.Name("ToDoView"), object: nil)
}
}
NotificationManager.swift
func scheduleNotifications() -> Void {
for notification in notifications {
let content = UNMutableNotificationContent()
content.title = notification.title
var dateComponents = DateComponents()
dateComponents.hour = 18
dateComponents.minute = 10
dateComponents.weekday = notification.weekday
let open = UNNotificationAction(identifier: "open", title: "Notizen öffnen", options: .foreground)
let cancel = UNNotificationAction(identifier: "cancel", title: "Schließen", options: .destructive)
let categories = UNNotificationCategory(identifier: "action", actions: [open,cancel], intentIdentifiers: [])
UNUserNotificationCenter.current().setNotificationCategories([categories])
content.categoryIdentifier = "action"
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
let request = UNNotificationRequest(identifier: notification.id, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { error in
guard error == nil else { return }
print("Benachrichtigung mit folgender ID eingerichtet: \(notification.id)")
}
ContentView.swift
.....
.onAppear {
NotificationCenter.default.addObserver(forName: NSNotification.Name("ToDoView"), object: nil, queue: .main) { (_) in
self.showToDo = true
} }
By the way: This code only works if the app still runs in the
background,
Instead of .onAppear in ContentView use subscription to publisher, like below
1) Declare publisher
struct ContentView: View {
let todoPublisher = NotificationCenter.default.publisher(for: NSNotification.Name("ToDoView"))
...
2) Add subscriber (in the place you added .onAppear and instead of it)
.onReceive(todoPublisher) { notification in
self.showToDo = true
}
this will work as long as ContentView exists.
I am trying to create a notification based on date and time specified by a user for an application I am working on. I am able to save user's date and retrieve. I now want a notification to pop up when the user's specified date has arrived just like an reminder thing. I can create a notification with with hard coded values but now retriving from the Real database to pass into the trigger value is what I am unable to do. my codes are specified below
func notifcation() -> Void {
let calendar = Calendar.current
let components = DateComponents(year: 2018, month: 09, day: 08, hour: 18, minute: 55) // Set the date here when you want Notification
let date = calendar.date(from: components)
let comp2 = calendar.dateComponents([.year,.month,.day,.hour,.minute], from: date!)
let trigger = UNCalendarNotificationTrigger(dateMatching: comp2, repeats: true)
let content = UNMutableNotificationContent()
content.title = "Don't forget"
content.body = "Buy some milk"
content.sound = UNNotificationSound.default()
let identifier = "UYLLocalNotification"
let request = UNNotificationRequest(identifier: identifier,
content: content, trigger: trigger)
center.add(request, withCompletionHandler: { (error) in
if let error = error {
// Something went wrong
print(error as Any)
}
})
}
then I call notification() in my viewDidLoad
Model
class ListModel: Object {
#objc dynamic var createdDate: Date?
#objc dynamic var remiderDate: Date?
}
based on Sh answer
My function
func getDataFromDB() -> Results<ListModel>? {
let todoListArray: Results<ListModel> = database.objects(ListModel.self)
return todoListArray
}
my viewdidLoad was now
TodoListFunctions.instance.getDataFromDB()?.forEach({ (list) in
notifcation(list.remiderDate)
})
in my AppDelegate for Permission
let center = UNUserNotificationCenter.current()
let options: UNAuthorizationOptions = [.alert, .sound]
center.requestAuthorization(options: options) {
(granted, error) in
if !granted {
print("Something went wrong")
}
}
further codes would be supplied on request
You can try
let allList = self.database.objects(ListModel.self)
allList.forEach{ notifcation($0.remiderDate) }
//
func notifcation(_ reminder:Date?) -> Void {
guard let date = reminder else { return }
let comp2 = calendar.dateComponents([.year,.month,.day,.hour,.minute], from: date)
let trigger = UNCalendarNotificationTrigger(dateMatching: comp2, repeats: true)
let content = UNMutableNotificationContent()
content.title = "Don't forget"
content.body = "Buy some milk"
content.sound = UNNotificationSound.default()
let identifier = "\(date)" // identider should be different for each one
let request = UNNotificationRequest(identifier: identifier,
content: content, trigger: trigger)
center.add(request, withCompletionHandler: { (error) in
if let error = error {
// Something went wrong
print(error as Any)
}
})
}
//
Set the delegate inside AppDelegte
UNUserNotificationCenter.current().delegate = self
and notice the print from
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .sound])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print("notification received")
}
I'm trying to reschedule a notification when user tap on wait notification action. When triggerNotification() gets called the first time Dateis provided by a Date Picker, but when it's called by a response gets the date from a time interval. Inside the didReceiveResponsemethod case:waitActionIdentifier: I set newDate and pass that to the triggerNotificationparameter. The delayed notification never arrives.
I don't understand if it's a function calling problem or else because newDatei see is correct by the print of it.
Here's the code:
class ViewController: UIViewController {
#IBAction func datePickerDidSelectNewDate(_ sender: UIDatePicker) {
let selectedDate = sender.date
let delegate = UIApplication.shared.delegate as? AppDelegate
// delegate?.scheduleNotification(at: selectedDate)
delegate?.triggerNotification(at: selectedDate)
}
}
and the AppDelegate
import UIKit
import UserNotifications
#UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
UNUserNotificationCenter.current().delegate = self
configureCategory()
triggerNotification(at: Date())
requestAuth()
return true
}
let category = "Notification.Category.Read"
private let readActionIdentifier = "Read"
private let waitActionIdentifier = "Wait"
private func requestAuth() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (success, error) in
if let error = error {
print("Request Authorization Failed (\(error), \(error.localizedDescription))")
}
}
}
func triggerNotification(at date: Date) {
// Create Notification Content
let notificationContent = UNMutableNotificationContent()
//compone a new Date components because components directly from Date don't work
let calendar = Calendar(identifier: .gregorian)
let components = calendar.dateComponents(in: .current, from: date)
let newComponents = DateComponents(calendar: calendar, timeZone: .current, month: components.month, day: components.day, hour: components.hour, minute: components.minute)
//create the trigger with above new date components, with no repetitions
let trigger = UNCalendarNotificationTrigger(dateMatching: newComponents, repeats: false)
// Configure Notification Content
notificationContent.title = "Hello"
notificationContent.body = "Kindly read this message."
// Set Category Identifier
notificationContent.categoryIdentifier = category
// Add Trigger
// let notificationTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 10.0, repeats: false)
// // Create Notification Request
let notificationRequest = UNNotificationRequest(identifier: "test_local_notification", content: notificationContent, trigger: trigger)
//
// Add Request to User Notification Center
UNUserNotificationCenter.current().add(notificationRequest) { (error) in
if let error = error {
print("Unable to Add Notification Request (\(error), \(error.localizedDescription))")
}
}
}
private func configureCategory() {
// Define Actions
let read = UNNotificationAction(identifier: readActionIdentifier, title: "Read", options: [])
let wait = UNNotificationAction(identifier: waitActionIdentifier, title : "Wait", options: [])
// Define Category
let readCategory = UNNotificationCategory(identifier: category, actions: [read, wait], intentIdentifiers: [], options: [])
// Register Category
UNUserNotificationCenter.current().setNotificationCategories([readCategory])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
switch response.actionIdentifier
{
case readActionIdentifier:
print("Read tapped")
case waitActionIdentifier:
let actualDate = Date()
let newDate: Date = Date(timeInterval: 10, since: actualDate)
self.triggerNotification(at: newDate)
print("Wait tapped")
print(actualDate)
print(newDate)
default:
print("Other Action")
}
completionHandler()
}
}
After trying different thing with #VIP-DEV and #Honey I finally understood where the problem with rescheduling notification when tapping on the wait action button from the notification.
Inside the func triggerNotification(at date: Date)scope I was getting the date components without seconds let newComponents = DateComponents(calendar: calendar, timeZone: .current, month: components.month, day: components.day, hour: components.hour, minute: components.minute)so when the new call of the function was made with a let newDate: Date = Date(timeInterval: 5.0 , since: actualDate)date, of course those seconds weren't taken into account and the date used was already passed, hence..no rescheduling .
let newComponents = DateComponents(calendar: calendar, timeZone: .current, month: components.month, day: components.day, hour: components.hour, minute: components.minute, second: components.second) is the final date with components including seconds.
I am trying to schedule notifications in my project. I don't get any errors or runtime crashes, however for some reason I don't get any notifications on the simulator when scheduling. I am not sure where exactly I am going wrong, as I have been successful in doing so in a previous project.
Does anyone have any suggestions ?
import UserNotifications
func addNotification(title: String, category: String, UI: String, date: Date) {
// Remove Notification
removeNotifcation(UI: UI)
// Create Notification
// iOS 10 Notification
if #available(iOS 10.0, *) {
let notif = UNMutableNotificationContent()
notif.title = title
notif.subtitle = "Reminder for \(title)"
notif.body = "Your Reminder for \(title) set for \(date)"
notif.sound = UNNotificationSound.default()
notif.categoryIdentifier = UI
let today = Date()
let interval = date.timeIntervalSince(today as Date)
let notifTrigger = UNTimeIntervalNotificationTrigger(timeInterval: interval, repeats: false)
let request = UNNotificationRequest(identifier: title, content: notif, trigger: notifTrigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: { error in
if error != nil {
print(error as Any)
// completion(Success: false)
} else {
//completion(Sucess: true)
}
})
} else {
let newNotification:UILocalNotification = UILocalNotification()
newNotification.category = category
newNotification.userInfo = [ "UUID" : UI]
newNotification.alertBody = "Your reminder for \(title)"
newNotification.fireDate = date
//notification.repeatInterval = nil
newNotification.soundName = UILocalNotificationDefaultSoundName
UIApplication.shared.scheduleLocalNotification(newNotification)
}
}
func removeNotifcation(UI: String) {
//Remove Notif
//iOS 10 Notification
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [UI])
} else {
//Remove Notif
let app:UIApplication = UIApplication.shared
for oneEvent in app.scheduledLocalNotifications! {
let notification = oneEvent as UILocalNotification
let userInfoCurrent = notification.userInfo!
let uuid = userInfoCurrent["UUID"] as! String
if uuid == UI {
//Cancelling local notification
app.cancelLocalNotification(notification)
break;
}
}
}
}
This is how I am calling the methods
dataManager.addNotification(title: "String", category: "001", UI: uuid, date: datePicker.date)
Notifications don't appear when app is in foreground only if you implement willPresent delegate method and because of
let today = Date()
this date makes it triggers when you run it , so add a time interval and send app to background and you'll see it , plus make sure you request a permission for it in AppDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
print("granted: (\(granted)")
}
return true
}
Also you can have a look to this tutorial
//
Edit : to verify it triggers anyway implement this
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print("handling notifications with the TestIdentifier Identifier")
completionHandler()
}
and set the delegate to the VC
UNUserNotificationCenter.current().delegate = self
I have created a scheduled notification in ViewController.swift and need two actions to be added to this notification. One that says "Call", and the other that says "Cancel". How can I add these actions in ViewController.swift? Here is the part of the code that has the function for firing my notification in my ViewController.swift:
func notificationFires(){
let notification = UILocalNotification()
// 2
notification.soundName = UILocalNotificationDefaultSoundName
notification.fireDate = datePicker.date
// 3
if textField.text == "" {
notification.alertBody = "You have a call right now!"
}
else{
notification.alertBody = self.textField.text
}
// 4
notification.timeZone = NSTimeZone.default
// 5
// 6
notification.applicationIconBadgeNumber = 1
// 7
UIApplication.shared.scheduleLocalNotification(notification)
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
print("Recived: notification")
if cancelled == true{
print("cancelled happened")
}
func cancelNotify(){
cancelled = true
UIApplication.shared.cancelAllLocalNotifications()
}
completionHandler(.newData)
}
}
I haven't used notifications in iOS 10 yet, so I went ahead and figured it out as a learning experience for myself, now I can pass it on to you.
UILocalNotification is depreciated in iOS 10 and replaced by the UserNotifications framework.
In your AppDelegate get authorization from the user to show notifications and set up the centers delegate with UNUserNotificationCenterDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let center = UNUserNotificationCenter.current()
center.delegate = self
let options: UNAuthorizationOptions = [.alert, .sound];
center.requestAuthorization(options: options) {
(granted, error) in
if !granted {
print("Something went wrong")
}
}
return true
}
Present the notification to the user:
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
// Play sound and show alert to the user
completionHandler([.alert,.sound])
}
Handling the actions:
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
// Determine the user action
switch response.actionIdentifier {
case UNNotificationDismissActionIdentifier:
print("Dismiss Action")
case UNNotificationDefaultActionIdentifier:
print("Default")
case "foo":
print("foo")
case "bar":
print("bar")
default:
print("Unknown action")
}
completionHandler()
}
Do this wherever you want to setup all actions and categories for all notifications in your app. Because they're assigned to the center, not the notification itself:
func setupActions() {
//create first action
let foo = UNNotificationAction(
identifier: "foo",
title: "foo"
)
//create second action
let bar = UNNotificationAction(
identifier: "bar",
title: "bar",
options: [.destructive]
)
//put the two actions into a category and give it an identifier
let cat = UNNotificationCategory(
identifier: "cat",
actions: [foo, bar],
intentIdentifiers: []
)
//add the category to the notification center
UNUserNotificationCenter.current().setNotificationCategories([cat])
}
And finally creating the actual notification:
func setupNotification() {
let content = UNMutableNotificationContent()
content.title = "Hello!"
content.body = "A message"
content.sound = UNNotificationSound.default()
//make sure to assign the correct category identifier
content.categoryIdentifier = "cat"
// Deliver the notification in five seconds.
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
let request = UNNotificationRequest(identifier: "hello", content: content, trigger: trigger)
let center = UNUserNotificationCenter.current()
center.add(request) { (error : Error?) in
if let theError = error {
print("theError \(theError)")
}
}
}
Be sure to import UserNotifications in each class utilizing these functions.
More info: User Notifications documentation.