2

I have seen several threads on this here and elsewhere but none seem to be using the new UserNotifications framework for iOS 10

There is an instance method getDeliveredNotifications(completionHandler:) that is called on UNUserNotificationCenter singleton function current()

The completionHandler: takes an array of delivered notifications that could then be removed inside the block using removeDeliveredNotifications(withIdentifiers:)

UNUserNotificationCenter.current().getDeliveredNotifications { notifications in 
    // UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [String])
}

My challenge is how to identify a specific notification from all delivered notifications and then remove it?

This is what I am doing right now to see if there is a remote notification delivered with the id I had sent from the server with the payload key ID. This doesn't remove the notification in question, obviously because the first function returns nil although the notification is visible in the notification center.

func isThereANotificationForID(_ ID: Int) -> UNNotification? {    
    var foundNotification: UNNotification?

    UNUserNotificationCenter.current().getDeliveredNotifications {
        DispatchQueue.main.async {
            for notification in notifications {
                if notification.request.content.userInfo["id"] as! Int == ID {
                    foundNotification = notification
                }
            }
        }
    }

    return foundNotification
}

func removeNotification(_ notification: UNNotification) {
    UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [notification.request.identifier])
}

// Find the notification and remove it
if let deliveredNotification = isThereANotificationForID(ID) {
    removeNotification(deliveredNotification)
}
Ahmed Khedr
  • 1,053
  • 1
  • 11
  • 24

2 Answers2

3

Note that this answer is using Swift 5 and tested on iOS 13.

We can extend UNUserNotificationCenter to remove the notification(s) of our choice. Personally, I group them by thread and remove them that way, but this extension also includes a way to remove by dictionary pair.

extension UNUserNotificationCenter {
    func decreaseBadgeCount(by notificationsRemoved: Int? = nil) {
        let notificationsRemoved = notificationsRemoved ?? 1
        DispatchQueue.main.async {
            UIApplication.shared.applicationIconBadgeNumber -= notificationsRemoved
        }
    }

    func removeNotifications(_ notifications: [UNNotification], decreaseBadgeCount: Bool = false) {
        let identifiers = notifications.map { $0.request.identifier }
        UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: identifiers)
        if decreaseBadgeCount {
            self.decreaseBadgeCount(by: notifications.count)
        }
    }

    func removeNotifications<T: Comparable>(whereKey key: AnyHashable, hasValue value: T, decreaseBadgeCount: Bool = false) {
        UNUserNotificationCenter.current().getDeliveredNotifications { notifications in
            let notificationsToRemove = notifications.filter {
                guard let userInfoValue = $0.request.content.userInfo[key] as? T else { return false }
                return userInfoValue == value
            }
            self.removeNotifications(notificationsToRemove, decreaseBadgeCount: decreaseBadgeCount)
        }
    }

    func removeNotifications(withThreadIdentifier threadIdentifier: String, decreaseBadgeCount: Bool = false) {
        UNUserNotificationCenter.current().getDeliveredNotifications { notifications in
            let notificationsToRemove = notifications.filter { $0.request.content.threadIdentifier == threadIdentifier }
            self.removeNotifications(notificationsToRemove, decreaseBadgeCount: decreaseBadgeCount)
        }
    }

    func removeNotification(_ notification: UNNotification, decreaseBadgeCount: Bool = false) {
        removeNotifications([notification], decreaseBadgeCount: decreaseBadgeCount)
    }
}

With this extension in place, you can call, for example,

UNUserNotificationCenter.current().removeNotifications(whereKey: "id", hasValue: 123)

If you also want to decrease the badge number on the app icon, you can set decreaseBadgeCount: true, or alternately call UNUserNotificationCenter.current().decreaseBadgeCount.

CartoonChess
  • 663
  • 7
  • 17
0

Previosly removeDeliveredNotifications is not work properly. It seems like Apple was fixed issue because it will work for me by using the single line of code.

UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: aryIdentifier)

I have tried 5-6 hours in the simulator to clear local notification but no luck. When I will run code in the actual device it will like the charm.

NOTE: Please test into real device, Above method are not working in simulator.

Hitesh Surani
  • 12,733
  • 6
  • 54
  • 65