Hi there! Please advice how I can subscribe to listening system events (Lock Screen/User log off/Device mounted/etc)? I try to use NSDistributedNotificationCenter to do it, but I can receive only own notifications =(
This is the my test Console application:
//
// main.m
// EventsListener
//
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#include <iostream>
@interface MyClass : NSObject
-(void)subscribe;
-(void)handleNotification:(NSNotification*)notification;
@end
@implementation MyClass : NSObject
-(void)subscribe
{
[[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:nil object:nil];
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(handleNotification2:) name:nil object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification3:) name:nil object:nil];
[[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification4:) name:@"com.apple.screenIsLocked" object:nil];
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(handleNotification4:) name:@"com.apple.screenIsLocked" object:nil];
}
-(void)handleNotification:(NSNotification*)notification
{
NSLog(@"handleNotification: %@", notification);
}
-(void)handleNotification2:(NSNotification*)notification
{
NSLog(@"handleNotification2: %@", notification);
}
-(void)handleNotification3:(NSNotification*)notification
{
NSLog(@"handleNotification3: %@", notification);
}
-(void)handleNotification4:(NSNotification*)notification
{
NSLog(@"handleNotification3: %@", notification);
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");
MyClass* mc = [MyClass new];
[mc subscribe];
[[NSNotificationCenter defaultCenter] postNotificationName:@"test notification" object:nil];
NSLog(@"Press enter to abort");
getchar();
}
return 0;
}
What wrong I does? Thanks!
But when I supply nil as value of name I should receive all notifications
Right, but that does not give you free reign to use those notification keys as if they were API.
[In retrospect this particular feature of the notification API was a poor choice, in that it actively encourages such behaviour. In its defence, that API was designed a long time ago.]
We should be able to run some 'job' on this event. User will can choose which event should be a trigger.
Most people who ask this question are building a security product, in which case the path forward is clear:
-
Our long-term direction for such things is the Endpoint Security (ES) API.
-
That does not currently support log in or log out events and, if you’re working on an ES client and need those events, I encourage you to file an enhancement request for them.
-
Pending that, you can use the now-deprecated audit (OpenBSM) subsystem to learn about log it and log out events in real time using
auditpipe
(see its man page).
However, if you’re not building a security product then I can’t recommend this approach. The problem is that first point: The ES client API is intended to be used as security products and not appropriate for non-security products.
A better approach in your case would be to implement a launchd
agent. The system will start this agent in the GUI context created by the user when they log in, and stop it when they log out. It can then connect to your daemon (using some sort of IPC mechanism, preferably XPC) to inform it of these state changes.
This approach has a bunch of other advantages:
-
The code runs with no special privileges.
-
Because it’s running in a GUI login context, it can call APIs that are only available in such contexts. For example,
NSWorkspace
has some really useful notifications, butNSWorkspace
is part of AppKit and thus only available in GUI contexts. -
If the daemon needs something done in a GUI login context — for example, if one of these jobs is ‘launch an app’ — it can command the agent to do that on its behalf.
IMPORTANT If you’re building a product like this it’s critical to understand how execution contexts work on the Mac. Technote 2083 Daemons and Agents has the best info on that subject.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"