You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

macOS下Swift编写launchd daemon捕获关机事件失败求助

问题描述

我知道这个问题之前有人提过,但一直没找到有效的解决办法。我用Swift写了一个launchd守护进程,目的是捕获系统关机通知并执行脚本或其他操作。

目前这个守护进程能正常启动,日志显示已经完成观察者注册(但没法确认是不是真的注册成功),但就是捕获不到关机通知。

注:我已经更新过代码,现在没有选择器错误,能正常捕获应用激活/隐藏通知,但关机通知还是抓不到。

Swift代码
import AppKit
import os

public class ShutdownHandlerDelegate : NSObject, NSApplicationDelegate {
    static let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "LoggingTest")
    var shutdownObserver: NSObjectProtocol?
    @objc func handleShutdown() {
        ShutdownHandlerDelegate.logger.notice("System is about to shut down. This is us logging that for debug...")
        NSWorkspace.shared.notificationCenter.removeObserver(shutdownObserver!)
        shutdownObserver = nil
        // Perform your pre-shutdown tasks here
    }
    @objc func handleActivate(_ notification: Notification) {
        if let app = (notification.userInfo?[NSWorkspace.applicationUserInfoKey] as? NSRunningApplication)?.bundleIdentifier {
            ShutdownHandlerDelegate.logger.notice("\(app, privacy: .public) will now be activated!")
            // Perform your pre-shutdown tasks here
        }
    }
    @objc func handleHide(_ notification: Notification) {
        if let app = (notification.userInfo?[NSWorkspace.applicationUserInfoKey] as? NSRunningApplication)?.bundleIdentifier {
            ShutdownHandlerDelegate.logger.notice("\(app, privacy: .public) will now be hidden!")
            // Perform your pre-shutdown tasks here
        }
    }
    func setUpObservers() {
        self.shutdownObserver = NSWorkspace.shared.notificationCenter.addObserver(forName: NSWorkspace.willPowerOffNotification, object: nil, queue: OperationQueue.main, using: {
            (_ note) in
            self.handleShutdown()
        })
//      NSWorkspace.shared.notificationCenter.addObserver(
//          self,
//          selector: #selector(handleShutdown(_:)),
//          name: NSWorkspace.willPowerOffNotification,
//          object: nil
//      )
        NSWorkspace.shared.notificationCenter.addObserver(
            self,
            selector: #selector(handleActivate(_:)),
            name: NSWorkspace.didActivateApplicationNotification,
            object: nil
        )
        NSWorkspace.shared.notificationCenter.addObserver(
            self,
            selector: #selector(handleHide(_:)),
            name: NSWorkspace.didHideApplicationNotification,
            object: nil
        )
    }
    override init() {
        super.init()
    }
    deinit {
        if let observer = shutdownObserver {
            NSWorkspace.shared.notificationCenter.removeObserver(observer)
        }
    }
}

@main
public class ShutdownHandler : NSObject {
    let _app : NSApplication?
    static let _delegate : ShutdownHandlerDelegate = ShutdownHandlerDelegate()
    static public func main() {
//      _app.delegate = ShutdownHandlerDelegate
        _delegate.setUpObservers()
        ShutdownHandlerDelegate.logger.notice("We're registering the shutdown observer. bundle-id is: \(Bundle.main.bundleIdentifier!, privacy: .public)")
        NSApplication.shared.run() // This keeps the app running & makes sure events are received
    }
    override init () {
        _app = NSApplication.shared
        _app!.delegate = ShutdownHandler._delegate
        super.init()
    }
}
launchd配置文件
<?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>Label</key>
    <string>com.lord-kamina.shutdownHandler</string>
    <key>ProgramArguments</key>
    <array>
    <string>/usr/local/bin/shutdown-daemon</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
</dict>
</plist>

内容的提问来源于stack exchange,提问作者Gregorio Litenstein

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 18:46:08