Swift NSUserNotification doesn't show while app is active
To ensure the notifications are always shown you'll need to set a delegate for NSUserNotificationCenter
and implement userNotificationCenter(center:shouldPresentNotification:) -> Bool
. The documentation says this message is
Sent to the delegate when the user notification center has decided not
to present your notification.
You can implement the delegate in any class of your choosing. Here is an example:
class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDelegate {
func applicationDidFinishLaunching(aNotification: NSNotification) {
NSUserNotificationCenter.defaultUserNotificationCenter().delegate = self
}
func userNotificationCenter(center: NSUserNotificationCenter, shouldPresentNotification notification: NSUserNotification) -> Bool {
return true
}
MacOS App Local Notification Not Showing when testing with XCode
I believe that my problem here was asking permission to use UNUserNotification and then using NSUserNotification to create the notification itself, which of course I had not requested permission to use. Requesting permission is now mandatory in Catalina (and perhaps it was in earlier versions of macOS as well.)
So I replaced the generateNotification function with the following and it all works correctly.
let notificationCenter = UNUserNotificationCenter.current();
notificationCenter.getNotificationSettings
{ (settings) in
if settings.authorizationStatus == .authorized
{
//print ("Notifications Still Allowed");
// build the banner
let content = UNMutableNotificationContent();
content.title = summary ;
content.body = title ;
if sound == "YES" {content.sound = UNNotificationSound.default};
// could add .badge
// could add .userInfo
// define when banner will appear - this is set to 1 second - note you cannot set this to zero
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false);
// Create the request
let uuidString = UUID().uuidString ;
let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger);
// Schedule the request with the system.
notificationCenter.add(request, withCompletionHandler:
{ (error) in
if error != nil
{
// Something went wrong
}
})
//print ("Notification Generated");
}
removeDeliveredNotification: doesn't
The notification you are attempting to be removed must be in the deliveredNotifications
array. Quote the docs for -removeDeliveredNotification:
If the user notification is not in deliveredNotifications, nothing happens.
Your notification may be copied when you call -deliverNotification:
, so keeping a reference to that instance and attempting to remove later it may fail. Instead, stash something in the notification's userInfo
property so you can identify it, and scan through the deliveredNotifications
array to find the notification you want to remove.
Added by Brent
Here's the corrected version of the method in my question. I'm using the original notification's pointer value, casted to an integer, to identify the copy; this isn't foolproof, but it's probably good enough.
- (NSUserNotification*)deliverNotificationWithSound:(NSString*)sound title:(NSString*)title messageFormat:(NSString*)message {
NSUserNotification * note = [NSUserNotification new];
note.soundName = sound;
note.title = title;
note.informativeText = [NSString stringWithFormat:message, NSRunningApplication.currentApplication.localizedName, self.document.displayName];
note.userInfo = @{ @"documentFileURL": self.document.fileURL.absoluteString, @"originalPointer": @((NSUInteger)note) };
[NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:note];
// NSUserNotificationCenter actually delivers a copy of the notification, not the original.
// If we want to remove the notification later, we'll need that copy.
for(NSUserNotification * deliveredNote in NSUserNotificationCenter.defaultUserNotificationCenter.deliveredNotifications) {
if([deliveredNote.userInfo[@"originalPointer"] isEqualToNumber:note.userInfo[@"originalPointer"]]) {
return deliveredNote;
}
}
return nil;
}
ObjectiveC - how to use NSUserNotification identifier property
You can delete an existing notification
using the NSNotificationCenter
s removeDeliveredNotification:
method.
Just remove and re-add your notification.
Objective-C
[[NSUserNotificationCenter defaultUserNotificationCenter] removeDeliveredNotification:userNotification];
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:userNotification];
Swift
NSUserNotificationCenter.default.removeDeliveredNotification(userNotification)
NSUserNotificationCenter.default.deliver(userNotification)
I successfully used this technique to show notifications without polluting the notification center.
didReceiveRemoteNotification:fetchCompletionHandler not being called when app is in background and not connected to Xcode
Issue have been fixed in iOS 7.1 Beta 3.
I double checked and I confirm it's working just fine.
Related Topics
Define Struct That Is Treated Like a Class in Swift
Saving Swifty JSON Array to User Defaults
How to Combine Two Nsdictionary in Swift
Writing Data to an Outputstream with Swift 5+
Simple Observable Struct with Rxswift
Swift: Get 30 Days Before 'Specific Date'
Check If Color Is Blue(Ish), Red(Ish), Green(Ish),
Uiimagepickercontroller Navigation Bar Tint Color Not Working with iOS 13
Swift Protocol with Variadic Property
Swift Package Manager Unable to Compile Ncurses Installed Through Homebrew
How to Delete Object in Array of Dictionaries Using Key Value
Count the Number of Lines in a Swift String
Scenekit Shape Between 4 Points
Why Strings Are Not Equal in My Case
Use Quick Look Inside a Swift Cocoa Application to Preview Audio Files