NSWorkspaceWillPowerOffNotification 从未调用过
NSWorkspaceWillPowerOffNotification never called
我正在尝试 运行 后台进程中的一个程序,它将注册系统中的每个关闭事件。
通过注册到 NSWorkspaceWillPowerOffNotification 来执行此操作,如下所示:
#import <AppKit/AppKit.h>
@interface ShutDownHandler : NSObject <NSApplicationDelegate>
- (void)computerWillShutDownNotification:(NSNotification *)notification;
@end
int main(int argc, char* argv[]) {
NSNotificationCenter *notCenter;
notCenter = [[NSWorkspace sharedWorkspace] notificationCenter];
ShutDownHandler* sdh = [ShutDownHandler new];
[NSApplication sharedApplication].delegate = sdh;
[notCenter addObserver:sdh
selector:@selector(computerWillShutDownNotification:)
name:NSWorkspaceWillPowerOffNotification
object:nil];
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[[NSFileManager defaultManager] createFileAtPath:@"./output.txt" contents:nil attributes:nil];
});
[[NSRunLoop currentRunLoop] run];
return 0;
}
@implementation ShutDownHandler
- (void)computerWillShutDownNotification:(NSNotification *)notification {
NSFileHandle* file = [NSFileHandle fileHandleForUpdatingAtPath: @"./output.txt"];
[file seekToEndOfFile];
NSDateFormatter* fmt = [NSDateFormatter new];
[fmt setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSDate* current = [NSDate date];
NSString* dateStr = [fmt stringFromDate:current];
[dateStr writeToFile:@"./output.txt" atomically:YES encoding:NSUTF8StringEncoding error:nil];
}
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
return NSTerminateCancel;
}
@end
出于某种我无法理解的原因,从未调用 NSWorkspaceWillPowerOffNotification 处理程序!
还在我的 .plist 中添加了以下内容:
<key>NSSupportsSuddenTermination</key>
<false/>
但关闭我的系统时仍然没有注册通知。
知道为什么吗?
当您说 运行 您的代码作为后台进程时,您的意思是它基于根据 /Library/LaunchDeamon
中的 plist 文件处理的 launchd 守护进程?在这种情况下,将不会发送通知。在 Cocoa application
下尝试 运行
似乎此通知不适用于与 AppKit 链接的 LaunchDaemon。
我仍在寻找在后台守护进程上获取这些通知的方法。
供日后参考:
我无法注册到上述事件并看到它发生了。
最后,我采用了不同的方法:
apple open-source power management
在这里,您可以看到我们有通知名称,例如:
"com.apple.system.loginwindow.logoutNoReturn"
您可以注册到这些网站,这样就可以了。
希望有一天这会对某人有所帮助:)
我可以通过添加 NSApplicationActivationPolicyAccessory
并用 [NSApp run]
替换 运行 循环来使 NSWorkspaceWillPowerOffNotification
和 applicationShouldTerminate:
工作。如果您想继续监视所有注销(and/or 次关机尝试),它仍然不会很有用,因为它仅在用户已经登录时启动进程时才有效,并且它只能检测当前 UI 登录会话的 power-off/logout 通知和“应用应终止”委托。
属于当前 UI 登录会话的“应用程序”在用户注销时被 OS 终止。非应用程序(无 [NSApp run]
)进程将继续 运行,即使在用户注销后也是如此。
因此,如果您想继续监视用户注销(或尝试关闭电源),您将需要一个非应用程序(无 [NSApp run]
)进程。
NSWorkspaceSessionDidBecomeActiveNotification
和 NSWorkspaceSessionDidResignActiveNotification
可以在没有 [NSApp run]
的情况下工作,如果您想监视用户是退出还是返回。
或者您可以尝试系统配置 API(如果它适用于您的用例)。
“技术问答 QA1133:确定控制台用户登录状态”https://developer.apple.com/library/archive/qa/qa1133/_index.html
听起来 com.apple.system.loginwindow.logoutNoReturn
是无论您想做什么的最佳选择。很高兴知道!
这里是更新后的代码(虽然不是很有用):
// cc powreoff-notification.m -o poweroff-notification -framework AppKit
#import <AppKit/AppKit.h>
@interface ShutDownHandler : NSObject <NSApplicationDelegate>
- (void)computerWillShutDownNotification:(NSNotification *)notification;
@end
int main(int argc, char* argv[]) {
@autoreleasepool {
NSLog(@"%s", __func__);
NSNotificationCenter* notCenter = [[NSWorkspace sharedWorkspace] notificationCenter];
ShutDownHandler* sdh = [ShutDownHandler new];
[NSApplication sharedApplication].delegate = sdh;
[notCenter addObserver:sdh
selector:@selector(computerWillShutDownNotification:)
name:NSWorkspaceWillPowerOffNotification
object:nil];
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[[NSFileManager defaultManager] createFileAtPath:@"./output.txt" contents:nil attributes:nil];
});
// without NSApplicationActivationPolicyAccessory, the [NSApp run] process gets killed on
// poweroff/logout instead of getting the power off notification or applicationShouldTerminate:.
[NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];
// without [NSApp run], you won't get the power off notification or applicationShouldTerminate:.
//[[NSRunLoop currentRunLoop] run];
[NSApp run];
// this process needs to be launched while the user has already logged in. otherwise,
// you won't get the power off notification or applicationShouldTerminate:.
}
return 0;
}
@implementation ShutDownHandler
- (void)computerWillShutDownNotification:(NSNotification *)notification {
NSLog(@"%s", __func__);
NSFileHandle* file = [NSFileHandle fileHandleForUpdatingAtPath: @"./output.txt"];
[file seekToEndOfFile];
NSDateFormatter* fmt = [NSDateFormatter new];
[fmt setDateFormat:@"yyyy-MM-dd HH:mm:ss\n"];
NSDate* current = [NSDate date];
NSString* dateStr = [fmt stringFromDate:current];
[dateStr writeToFile:@"./output.txt" atomically:YES encoding:NSUTF8StringEncoding error:nil];
}
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
NSLog(@"%s", __func__);
return NSTerminateCancel;
}
@end
我正在尝试 运行 后台进程中的一个程序,它将注册系统中的每个关闭事件。
通过注册到 NSWorkspaceWillPowerOffNotification 来执行此操作,如下所示:
#import <AppKit/AppKit.h>
@interface ShutDownHandler : NSObject <NSApplicationDelegate>
- (void)computerWillShutDownNotification:(NSNotification *)notification;
@end
int main(int argc, char* argv[]) {
NSNotificationCenter *notCenter;
notCenter = [[NSWorkspace sharedWorkspace] notificationCenter];
ShutDownHandler* sdh = [ShutDownHandler new];
[NSApplication sharedApplication].delegate = sdh;
[notCenter addObserver:sdh
selector:@selector(computerWillShutDownNotification:)
name:NSWorkspaceWillPowerOffNotification
object:nil];
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[[NSFileManager defaultManager] createFileAtPath:@"./output.txt" contents:nil attributes:nil];
});
[[NSRunLoop currentRunLoop] run];
return 0;
}
@implementation ShutDownHandler
- (void)computerWillShutDownNotification:(NSNotification *)notification {
NSFileHandle* file = [NSFileHandle fileHandleForUpdatingAtPath: @"./output.txt"];
[file seekToEndOfFile];
NSDateFormatter* fmt = [NSDateFormatter new];
[fmt setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSDate* current = [NSDate date];
NSString* dateStr = [fmt stringFromDate:current];
[dateStr writeToFile:@"./output.txt" atomically:YES encoding:NSUTF8StringEncoding error:nil];
}
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
return NSTerminateCancel;
}
@end
出于某种我无法理解的原因,从未调用 NSWorkspaceWillPowerOffNotification 处理程序!
还在我的 .plist 中添加了以下内容:
<key>NSSupportsSuddenTermination</key>
<false/>
但关闭我的系统时仍然没有注册通知。
知道为什么吗?
当您说 运行 您的代码作为后台进程时,您的意思是它基于根据 /Library/LaunchDeamon
中的 plist 文件处理的 launchd 守护进程?在这种情况下,将不会发送通知。在 Cocoa application
似乎此通知不适用于与 AppKit 链接的 LaunchDaemon。
我仍在寻找在后台守护进程上获取这些通知的方法。
供日后参考:
我无法注册到上述事件并看到它发生了。
最后,我采用了不同的方法: apple open-source power management
在这里,您可以看到我们有通知名称,例如: "com.apple.system.loginwindow.logoutNoReturn"
您可以注册到这些网站,这样就可以了。
希望有一天这会对某人有所帮助:)
我可以通过添加 NSApplicationActivationPolicyAccessory
并用 [NSApp run]
替换 运行 循环来使 NSWorkspaceWillPowerOffNotification
和 applicationShouldTerminate:
工作。如果您想继续监视所有注销(and/or 次关机尝试),它仍然不会很有用,因为它仅在用户已经登录时启动进程时才有效,并且它只能检测当前 UI 登录会话的 power-off/logout 通知和“应用应终止”委托。
属于当前 UI 登录会话的“应用程序”在用户注销时被 OS 终止。非应用程序(无 [NSApp run]
)进程将继续 运行,即使在用户注销后也是如此。
因此,如果您想继续监视用户注销(或尝试关闭电源),您将需要一个非应用程序(无 [NSApp run]
)进程。
NSWorkspaceSessionDidBecomeActiveNotification
和 NSWorkspaceSessionDidResignActiveNotification
可以在没有 [NSApp run]
的情况下工作,如果您想监视用户是退出还是返回。
或者您可以尝试系统配置 API(如果它适用于您的用例)。
“技术问答 QA1133:确定控制台用户登录状态”https://developer.apple.com/library/archive/qa/qa1133/_index.html
听起来 com.apple.system.loginwindow.logoutNoReturn
是无论您想做什么的最佳选择。很高兴知道!
这里是更新后的代码(虽然不是很有用):
// cc powreoff-notification.m -o poweroff-notification -framework AppKit
#import <AppKit/AppKit.h>
@interface ShutDownHandler : NSObject <NSApplicationDelegate>
- (void)computerWillShutDownNotification:(NSNotification *)notification;
@end
int main(int argc, char* argv[]) {
@autoreleasepool {
NSLog(@"%s", __func__);
NSNotificationCenter* notCenter = [[NSWorkspace sharedWorkspace] notificationCenter];
ShutDownHandler* sdh = [ShutDownHandler new];
[NSApplication sharedApplication].delegate = sdh;
[notCenter addObserver:sdh
selector:@selector(computerWillShutDownNotification:)
name:NSWorkspaceWillPowerOffNotification
object:nil];
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[[NSFileManager defaultManager] createFileAtPath:@"./output.txt" contents:nil attributes:nil];
});
// without NSApplicationActivationPolicyAccessory, the [NSApp run] process gets killed on
// poweroff/logout instead of getting the power off notification or applicationShouldTerminate:.
[NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];
// without [NSApp run], you won't get the power off notification or applicationShouldTerminate:.
//[[NSRunLoop currentRunLoop] run];
[NSApp run];
// this process needs to be launched while the user has already logged in. otherwise,
// you won't get the power off notification or applicationShouldTerminate:.
}
return 0;
}
@implementation ShutDownHandler
- (void)computerWillShutDownNotification:(NSNotification *)notification {
NSLog(@"%s", __func__);
NSFileHandle* file = [NSFileHandle fileHandleForUpdatingAtPath: @"./output.txt"];
[file seekToEndOfFile];
NSDateFormatter* fmt = [NSDateFormatter new];
[fmt setDateFormat:@"yyyy-MM-dd HH:mm:ss\n"];
NSDate* current = [NSDate date];
NSString* dateStr = [fmt stringFromDate:current];
[dateStr writeToFile:@"./output.txt" atomically:YES encoding:NSUTF8StringEncoding error:nil];
}
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
NSLog(@"%s", __func__);
return NSTerminateCancel;
}
@end