Posting a local notifications (or alert) from a launch agent

My Mac app has a launch agent (within the app bundle) that works great without the app running. There are some occasions where I need to display an alert and ask the user to launch the app to handle the issue. I thought about using UNUserNotificationCenter but I'm not able to make it work from the agent.

I'm asking for authorization as follows:

    [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge)
                          completionHandler:^(BOOL granted, NSError * _Nullable error) {
        NSLog(@"authorization request completion. Granted: %@, error: %@ (%@)",granted?@"YES":@"NO",error, [error localizedDescription]);
    }];

And I'm trying to post the notification as follows:

content.title = @"Your App Name";
content.body = @"Click the button to open the app";
content.sound = [UNNotificationSound defaultSound];

UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:[[NSUUID UUID] UUIDString]
                                                                      content:content
                                                                      trigger:nil];
 
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
    if (error) {
        NSLog(@"Error showing notification: %@ %@", error, [error localizedDescription]);
    }
}];

When running I'm getting asked to authorize, I authorize and all seems OK in system settings but I'm not able send any notifications. addNotificationRequest results in UNErrorCodeNotificationsNotAllowed error. I tried this with the authorization request inside the main app, or inside the agent, with the same results. When trying to post the notification from within the app, it does work, but that's not what I need. Is posting notifications from within the launch agent not possible at all, or is there anything here that I'm missing. TIA

Answered by DTS Engineer in 863299022

While User Notifications framework won’t work for you, you do have other options, albeit more old school ones. A launchd agent can present a notification using the CFUserNotification type.

Note CFUserNotification actually works from a launchd daemon as well, but I generally recommend that folks not use it from that context because of a fundamental impedance: A daemon can be running when no user is logged in, or when multiple users are logged in, and thus it’s not obvious who’ll get the notification. OTOH, CFUserNotification is reasonable from a launchd agent because the user context is clear.

CFUserNotification is a quite unpleasant type to use, especially from Swift. In addition to the docs referenced above, I recommend that you read the doc comments in <CoreFoundation/CFUserNotification.h>.

If you get stuck, reply here and I’ll see if I can find any helpful snippets lurking in the dusty corners of my local disk (-:

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Posting notifications requires a user level TCC (Transparency, Consent, and Control) prompt, which requires the requesting app to be running in a user context.

Therefore is not possible to use notifications (or anything else that requires user authorization) from a system level daemon or launch agent.

Your best bet would be to separate the notification functionality into a user level component, perhaps a user agent, and communicate between your launch agent and the user level process.

If there are specific actions the launch agent needs to take, it can delegate them to the user level process.

While User Notifications framework won’t work for you, you do have other options, albeit more old school ones. A launchd agent can present a notification using the CFUserNotification type.

Note CFUserNotification actually works from a launchd daemon as well, but I generally recommend that folks not use it from that context because of a fundamental impedance: A daemon can be running when no user is logged in, or when multiple users are logged in, and thus it’s not obvious who’ll get the notification. OTOH, CFUserNotification is reasonable from a launchd agent because the user context is clear.

CFUserNotification is a quite unpleasant type to use, especially from Swift. In addition to the docs referenced above, I recommend that you read the doc comments in <CoreFoundation/CFUserNotification.h>.

If you get stuck, reply here and I’ll see if I can find any helpful snippets lurking in the dusty corners of my local disk (-:

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Posting a local notifications (or alert) from a launch agent
 
 
Q