Add app icon to NSUserNotification - swift

I am currently making an application that displays a notification to the user, however it does not show the application icon.
Here is my code:
func showNotification(message:String, title:String = "App Name") -> Void {
let notification = NSUserNotification()
notification.title = title
notification.informativeText = message
NSUserNotificationCenter.defaultUserNotificationCenter().deliverNotification(notification)
}
showNotification("\(song)\n\(artist)",title: "Now Playing")
How would I add my application icon to the notification?
Edit:
Here is my Application Icon Asset:
And here is my notification.

Related

macOS app StatusBar icon only appears when Xcode is focussed

I'm building a macOS app with a StatusBar icon in Xcode (13.2, Swift 5) for personal use.
When I build in the dev environment it works as expected and the StatusBar icon appears.
To create the production app I go to Product > Archive > Distribute App > Copy App, and it creates a .app file with no errors (this method works for other apps without signing).
When I run the .app file, I see the app running in my processes, but no StatusBar icon appears.
Then if I switch to Xcode while the app is running, the StatusBar icon for the production app shows up. I know it's the distribution app because if I run the development build again I see two icons.
And if I kill the process one goes away.
Relevant code -
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
let statusItem = NSStatusBar.system.statusItem(withLength:NSStatusItem.squareLength)
let popover = NSPopover()
var eventMonitor: EventMonitor?
func applicationDidFinishLaunching(_ aNotification: Notification) {
if let button = self.statusItem.button {
button.image = NSImage(named: NSImage.Name("MenuBarIcons"))
button.action = #selector(AppDelegate.togglePopover(_:))
}
self.popover.contentViewController = ViewController.newInstance()
self.popover.animates = false
self.eventMonitor = EventMonitor(mask: [.leftMouseDown, .rightMouseDown]) { [weak self] event in
if let strongSelf = self, strongSelf.popover.isShown {
strongSelf.closePopover(sender: event)
}
}
}
Questions are:
Why does the distribution app StatusBar icon only appear when I'm focused on Xcode?
What can I do to get the icon to always show up?

Pressing on app notification always activates app window

My application schedules notification and displays it well
NSUserNotificationCenter.default.delegate = self
let notification = NSUserNotification()
notification.deliveryDate = Date(timeIntervalSinceNow: TimeInterval(10))
notification.title = title
notification.actionButtonTitle = "Do something"
notification.soundName = notificationSound != "none" ? notificationSound : nil
notification.otherButtonTitle = "Close"
NSUserNotificationCenter.default.scheduleNotification(notification)
When I press on the button activation method is called well
func userNotificationCenter(_ center: NSUserNotificationCenter, didActivate notification: NSUserNotification) {
DDLogDebug("Did activate notification")
switch notification.activationType {
...
}
The problem is that opened window is activated after pressing on it that I don't need.
Application is agent (UIElement) with multiple windows opened. Tried non-agent application, the problem still persists - it activates main window
Any ideas?
UPDATE
Unfortunately, I didn't find the answer. I implemented my own mechanism of notifications that displays custom Panel

Showing notification banner on Mac with Swift

I tried to show up some notification banners on Mac OS with Swift. But i get them only in the notification center, not as banner.
Do you have an idea? Here my simple code:
func showNotification() -> Void {
let notification = NSUserNotification()
notification.title = "Title of notification"
notification.subtitle = "Subtitle of notification"
notification.soundName = NSUserNotificationDefaultSoundName
NSUserNotificationCenter.default.deliver(notification)
}
#IBAction func btnPressed(_ sender: NSButton) {
showNotification()
testLbl.stringValue = "Button was pressed"
}
You won't get a banner if your app is in the foreground.
Try using…
notification.deliveryDate = Date(timeIntervalSinceNow: 5)
NSUserNotificationCenter.default.scheduleNotification(notification)
and then switch to another app
If, at the time of sending the notification, the app sending the notification is focused, then the notification won't show as a banner. An app can only deliver a banner notification if it is not active in the foreground.
Your code works well when your app is not the main focus, I've just tested it.
So, because you send the notification on a button click, the app is focused when the notification is sent: the notification only goes to the Notification Center, it is not shown as a banner.
This is a rule made on purpose by Apple.

UNUserNotificationCenter don't work when app is killed

I just did change for my notification for iOs 10 and others:
if #available(iOS 10.0, *) {
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound]) { (granted, error) in
let content = UNMutableNotificationContent()
content.body = notifMessage!
content.sound = UNNotificationSound.default()
// Deliver the notification in five seconds.
let trigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 5, repeats: false)
let request = UNNotificationRequest.init(identifier: "Upload", content: content, trigger: trigger)
// Schedule the notification.
let center = UNUserNotificationCenter.current()
center.add(request)
}
} else {
let notification = UILocalNotification()
notification.alertBody = notifMessage
notification.fireDate = NSDate() as Date
notification.soundName = UILocalNotificationDefaultSoundName
UIApplication.shared.scheduleLocalNotification(notification)
}
When I run my apps on my device by connect it with the USB it works, but only when the app is in background, it doesn't work when:
i kill the app
when the app is displayed
If you kill the app (by double tapping on home button and then swiping up), that not only terminates the app, but prohibits further background operation of the app (until the user fires it up again). You have to just press the home button and let the app be jettisoned via the normal memory recovery processes. Or you can, for testing purposes, programmatically crash app. But you cannot use springboard (the double tap of home button trick), because affects the permissible background modes of an app.
Regarding the notification when the app is displayed vs if the user taps on the notification vs user manually starts app having disregarding a notification, those are all conveyed to the app in different ways. See the Responding to Notifications and Events section of the UIApplicationDelegate documentation. Or see the App Programming Guide for iOS: Background Execution for general information about background operation.
There are a couple of errors in your code :
1. Title for the notification is missing. You have added the body and sound to the content but the title is missing. Title is a must and if you don't add the title the notification won't show.
content.title = "Some Title"
Do not use init to initialise. These functions can be re-written as :
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
let request = UNNotificationRequest.init(identifier: "Upload", content: content, trigger: trigger)
The identifier value is same. The identifier value needs to be different for every notification that you schedule. Notifications with same identifier do not appear.
let request = UNNotificationRequest(identifier: some_value, content: content, trigger: trigger)
Trigger time. The time that you specifying in the trigger is for 5 seconds. Which may be less for you to close the app and test for the notification. Just to be on the safe side, make sure this value is at least 1 minute so that you can properly test out if it is working or not.
Hope this helps.

How to observe other application icon in OS X?

I need to know current shown icon of another running application, I have tried this code:
var icon = NSRunningApplication.runningApplicationsWithBundleIdentifier("some.app.dentifier").first?.icon
but this returns a fixed app icon and if the other app changed its icon this code still returns same icon before change.
Is there a way to return current shown icon of another app or icon identifier ?
First add this to applicationDidFinishLaunching
let appChanged = Notification.Name("NSWorkspaceDidActivateApplicationNotification")
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(self.appChanged), name: appChanged, object: nil)
Then this function will get you the image
#objc func appChanged(notification:NSNotification){
if let userInfo = notification.userInfo![NSWorkspace.applicationUserInfoKey] as? NSRunningApplication {
let icon = userInfo.icon
}
}