1

I'm writing standalone Objective-C code to display notifications on MacOS. Here's what I have so far.

The main logic is in notify.m:

#import <stdio.h>
#import <Cocoa/Cocoa.h>
#import <UserNotifications/UserNotifications.h>
#import <objc/runtime.h>


@interface AppDelegate : NSObject<NSUserNotificationCenterDelegate>

@end

@implementation AppDelegate

- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center 
                               shouldPresentNotification:(NSUserNotification *)notification {
  return YES;
}

@end


int native_show_notification(char *title, char *msg) {
    NSApplication *app = [NSApplication sharedApplication];
    AppDelegate *appdel = [[AppDelegate alloc] init];
    app.delegate = appdel;
    NSUserNotificationCenter *nc = [NSUserNotificationCenter defaultUserNotificationCenter];
    nc.delegate = appdel;

    NSUserNotification *n = [[NSUserNotification alloc] init];

    n.title = [NSString stringWithUTF8String:title];
    n.informativeText = [NSString stringWithUTF8String:msg];

    [NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:n];

    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];

    return 0;
}


int main() {
    const int a = 50, b = 150;
    char title[a] = "Test\0", msg[b] = "Hello!\0";
    native_show_notification(title, msg);
}

Along with the code, we have an Info.plist in the same directory.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>CFBundleIdentifier</key>
  <string>com.microsoft.VSCode</string>
</dict>
</plist>

The compilation command is simple: cc -framework Cocoa -o app notif.m. The Info.plist is discovered and incorporated automatically.

This code works fine, with one caveat. If the application defined by the package name (in this case com.microsoft.VSCode) is focused, the notification is not "pushed" to the user under default settings [1]. Instead it is hidden in the notification center. When the application in question is not focused, though, the notification is pushed properly. If you want to test this yourself, try compiling and running the code in VSCode, where it seems like nothing happened until you check your notification center. Then set the <string> to something like com.apple.calendar. It'll work.

How can I avoid this and get the notification to display no matter what?

[1] The default notification scheme is "Banner". The problem goes away when the user selects "Alert", but I cannot expect this. I'd like to get it working with Banner too.

kaylum
  • 13,833
  • 2
  • 22
  • 31
cmt0220
  • 117
  • 6
  • What version of macOS are you testing this code with? – esqew Jan 21 '22 at 20:00
  • Big Sur: 11.3.1 – cmt0220 Jan 21 '22 at 20:07
  • [`NSUserNotificationDelegate`](https://stackoverflow.com/questions/64272748/whats-the-difference-between-nsusernotification-and-unusernotification-in-macos) and its related classes are deprecated after macOS 11.0. On later platforms you should be targeting to implement [`userNotificationCenter:willPresentNotification:withCompletionHandler:`](https://developer.apple.com/documentation/usernotifications/unusernotificationcenterdelegate/1649518-usernotificationcenter?language=objc) to dictate how notifications are handled when your app is in the foreground. – esqew Jan 21 '22 at 20:38
  • @esqew gotcha, I was actually trying to get the new API to work but didn't know how. Do you happen to have an example of a standalone program that can use UNUserNotification to throw notifications? I can provide a first-try implementation if that would be helpful. – cmt0220 Jan 21 '22 at 21:26
  • I don't off-hand, no. – esqew Jan 21 '22 at 21:27
  • Does this answer your question? [Getting local notifications to show while app is in foreground Swift 3](https://stackoverflow.com/questions/39713605/getting-local-notifications-to-show-while-app-is-in-foreground-swift-3) – Willeke Jan 22 '22 at 05:49

0 Answers0