Remove / cancel pending local notifications from NotificationCenter - ios

I have a view controller that initializes a local scheduled notification on viewDidLoad. I would like to stop this notification from happening if a user presses a button.
I have found some answers saying to use center.removeAllPendingNotificationRequests() but this does not work for NotificationCenter
let notificationPublisher = NotificationPublisher()
override func viewDidLoad() {
notificationPublisher.sendNotification(title: "Test", subtitle: "", body: "Test", badge: nil, delayInterval: Int(breakTime))
}
#objc func buttonPressed() {
// Want to dismiss the pending notification here
}
NotificationPublisher.swift:
import UIKit
import UserNotifications
class NotificationPublisher: NSObject {
let notificationCenter = NotificationCenter.default
func sendNotification(title: String, subtitle: String, body: String, badge: Int?, delayInterval: Int?) {
let notificationContent = UNMutableNotificationContent()
notificationContent.title = title
notificationContent.subtitle = subtitle
notificationContent.body = body
var delayTimeTrigger: UNTimeIntervalNotificationTrigger?
if let delayInterval = delayInterval {
delayTimeTrigger = UNTimeIntervalNotificationTrigger(timeInterval: TimeInterval(delayInterval), repeats: false)
}
if let badge = badge {
var currentBadgeCount = UIApplication.shared.applicationIconBadgeNumber
currentBadgeCount += badge
notificationContent.badge = NSNumber(integerLiteral: currentBadgeCount)
}
notificationContent.sound = UNNotificationSound.default
UNUserNotificationCenter.current().delegate = self
let request = UNNotificationRequest(identifier: "TestLocalNotification", content: notificationContent, trigger: delayTimeTrigger)
UNUserNotificationCenter.current().add(request) { (error) in
if let error = error {
print(error.localizedDescription)
}
}
}
}
extension NotificationPublisher: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
let identifer = response.actionIdentifier
switch identifer {
case UNNotificationDismissActionIdentifier:
print("The notification was dismissed")
completionHandler()
case UNNotificationDefaultActionIdentifier:
print("The user opened the app from the notification")
completionHandler()
default:
print("The default case was called")
}
}
}

Related

Open a specific view when opening the App through a Notification

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.

Displaying local notifications when app starts up in iOS

In my app I want to give a notification for an event when the user first enters the app. I have the notifications set up in another viewController handling the calendar that holds the events:
//setup calendar notifications
func createNotification(){
let content = UNMutableNotificationContent()
content.title = "Event"
content.subtitle = eventNameArray[0]
content.body = descriptionsArray[0]
content.sound = UNNotificationSound.default()
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 3.0, repeats: false)
let request = UNNotificationRequest(identifier: "notification", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request){
(error) in
print(error as Any)
}
}
This notification only triggers in when the user goes to the calendar page.
How do I display this notification when the user boots up the app? Do I need to make changes to the AppDelegate?
EDIT: Following a this tutorial (https://www.youtube.com/watch?v=cx2B8P84tS4) I implemented a new class to push the notifications:
import UIKit
import UserNotifications
class NotificationPublisher: NSObject {
func sendNotification(title: String,
subtitle: String,
body: String,
badge: Int?,
delayInterval: Int?){
let notificationContent = UNMutableNotificationContent()
notificationContent.title = title
notificationContent.subtitle = subtitle
notificationContent.body = body
var delayTimeTrigger: UNTimeIntervalNotificationTrigger?
if let delayInterval = delayInterval {
delayTimeTrigger = UNTimeIntervalNotificationTrigger(timeInterval: TimeInterval(delayInterval), repeats: false)
}
if let badge = badge {
var currentBadgeCount = UIApplication.shared.applicationIconBadgeNumber
currentBadgeCount += badge
notificationContent.badge = NSNumber(integerLiteral: currentBadgeCount)
}
notificationContent.sound = UNNotificationSound.default()
UNUserNotificationCenter.current().delegate = self
let request = UNNotificationRequest(identifier: "TestLocalNotification", content: notificationContent, trigger: delayTimeTrigger)
UNUserNotificationCenter.current().add(request) {
error in
if let error = error {
print(error.localizedDescription)
}
}
}
}
extension NotificationPublisher: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .sound, .badge])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
let identifier = response.actionIdentifier
switch identifier {
case UNNotificationDismissActionIdentifier:
print("Notification dismissed")
completionHandler()
case UNNotificationDefaultActionIdentifier:
print("User opened app from notification ")
default:
print("Default case was called")
completionHandler()
}
}
}
Then inside the viewController of the startup page I did this:
class ViewController: UIViewController{
private let notificationPublisher = NotificationPublisher()
private let calendarEvents = CalendarController()
override func viewDidLoad() {
super.viewDidLoad()
print("Events to show in notification: ", calendarEvents.descriptionsArray)
notificationPublisher.sendNotification(title: "Hey", subtitle: "Testing", body: "Is this working?", badge: 1, delayInterval: nil )
}
}
The app shows the notification on startup but I cannot display anything inside the calendarEvents.descriptionsArray as it is empty. How do I make it so the array is filled with data from a server so that the notification can display the event?
You can do simply the same in AppDelegate class on method applicationDidFinishLaunchingWithOptions
you may want to save a flag to NSUSerDefaults to indicate whether it is the very first launch of the app or not and act accordingly (display local notification)

How to schedule Notifications in Swift

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

Local Notifications swift 3

I am trying to send a notification on a button click. This is the code in my viewController:
#IBAction func getNotificationButtonPressed(_ sender: Any) {
let content = UNMutableNotificationContent()
content.title = "Title"
content.body = "Body"
content.categoryIdentifier = "ident"
content.sound = UNNotificationSound.default()
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.1, repeats: false)
let request = UNNotificationRequest(identifier: "ident", content: content, trigger: trigger)
let center = UNUserNotificationCenter.current()
center.add(request) { (error : Error?) in
if let theError = error {
print(theError.localizedDescription)
} else {
print ("success")
}
}
}
also in AppDelegate I have requested permission to use Notifications:
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in
// Enable or disable features based on authorization.
}
application.registerForRemoteNotifications()
P.S. I have imported
import UserNotifications
in both AppDelegate and the custom ViewController.
When you create notification at that check
if #available(iOS 10.0, *) {
let content = UNMutableNotificationContent()
content.title = "Intro to Notifications"
content.subtitle = "Lets code,Talk is cheap"
content.body = "Sample code from WWDC"
content.sound = UNNotificationSound.default()
// Deliver the notification in five seconds.
let trigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 5.0, repeats: false)
let request = UNNotificationRequest(identifier:requestIdentifier, content: content, trigger: trigger)
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().add(request){(error) in
if (error != nil){
print(error?.localizedDescription)
}
}
}
Implement this delegates method UNUserNotification for Notification being triggered.
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print("Tapped in notification")
}
//This is key callback to present notification while the app is in foreground
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
print("Notification being triggered")
//You can either present alert ,sound or increase badge while the app is in foreground too with ios 10
//to distinguish between notifications
if notification.request.identifier == requestIdentifier{
completionHandler( [.alert,.sound,.badge])
}
}
Happy coding.

How to replace depreciated UILocalNotification and add UNNotificationAction in iOS 10

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.

Resources