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

macOS下有无非轮询方案让Shell脚本监听屏幕锁定/解锁状态?

替代轮询的macOS屏幕锁定状态监听方案

你现有的RunWhenUnlocked.sh通过轮询ioreg和PlistBuddy检测屏幕锁定状态,虽然能实现功能,但轮询会持续占用系统资源。下面提供几种无需轮询、通过系统原生钩子监听状态变化的方案:

1. 利用launchd的会话管理(最简便)

macOS的launchd可以直接根据用户图形会话的激活/停用状态自动启动或终止脚本,完全不需要轮询。

创建一个launchd配置文件~/Library/LaunchAgents/com.example.WakeTracker.plist:

<?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.example.WakeTracker</string>
    <!-- 替换为你的WakeTracker.sh的绝对路径 -->
    <key>ProgramArguments</key>
    <array>
        <string>/full/path/to/WakeTracker.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <dict>
        <key>SuccessfulExit</key>
        <false/>
        <!-- 仅在Aqua图形会话激活(屏幕解锁)时保持脚本运行 -->
        <key>SessionType</key>
        <string>Aqua</string>
    </dict>
</plist>

加载配置并启动服务:

launchctl load ~/Library/LaunchAgents/com.example.WakeTracker.plist

当屏幕锁定时,系统会自动终止WakeTracker.sh;解锁时则重新启动它,完全由系统原生机制驱动,没有轮询开销。

2. AppleScript监听系统事件

用AppleScript可以直接监听登录窗口的可见性变化,对应屏幕锁定/解锁状态,比轮询系统属性更轻量:

on handleScreenLock()
    do shell script "killall WakeTracker.sh 2>/dev/null"
end handleScreenLock

on handleScreenUnlock()
    do shell script "/full/path/to/WakeTracker.sh &"
end handleScreenUnlock

tell application "System Events"
    repeat
        set loginWindowVisible to visible of login window
        if loginWindowVisible then
            handleScreenLock()
            -- 等待解锁完成
            repeat while visible of login window
                delay 0.5
            end repeat
            handleScreenUnlock()
        end if
        delay 1
    end repeat
end tell

将脚本保存为.scpt文件后运行,它会在后台监听状态变化,仅在状态切换时执行操作。

3. Swift调用Cocoa通知API(最精准)

通过Swift调用macOS的DistributedNotificationCenter,可以直接监听系统发出的屏幕锁定/解锁通知,完全消除轮询:

创建LockListener.swift文件:

import Cocoa

class LockObserver: NSObject {
    override init() {
        super.init()
        let notificationCenter = DistributedNotificationCenter.default()
        // 监听锁定通知
        notificationCenter.addObserver(
            self,
            selector: #selector(onScreenLocked),
            name: NSNotification.Name("com.apple.screenIsLocked"),
            object: nil
        )
        // 监听解锁通知
        notificationCenter.addObserver(
            self,
            selector: #selector(onScreenUnlocked),
            name: NSNotification.Name("com.apple.screenIsUnlocked"),
            object: nil
        )
    }

    @objc private func onScreenLocked() {
        let killTask = Process()
        killTask.executableURL = URL(fileURLWithPath: "/usr/bin/killall")
        killTask.arguments = ["WakeTracker.sh", "-q"]
        try? killTask.run()
    }

    @objc private func onScreenUnlocked() {
        let startTask = Process()
        startTask.executableURL = URL(fileURLWithPath: "/full/path/to/WakeTracker.sh")
        try? startTask.run()
    }
}

// 启动监听
let observer = LockObserver()
NSApplication.shared.run()

编译为可执行文件:

swiftc LockListener.swift -o LockListener

运行这个可执行文件后,它会在后台静默监听系统通知,只有当屏幕锁定/解锁事件发生时才执行对应操作,完全没有轮询开销。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 21:18:16