记录MacOS上遇到的一个小问题
起因需要监控家里的MacOS电量,对低电量进行Hook,进入低电量后,执行shell命令,通知我。
让AI帮我写了以下脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| import Foundation
func log(_ message: String) { print(message) fflush(stdout) }
class PowerObserver { init() { NotificationCenter.default.addObserver( self, selector: #selector(powerStateChanged), name: .NSProcessInfoPowerStateDidChange, object: nil ) }
@objc func powerStateChanged() { let isLowPower = ProcessInfo.processInfo.isLowPowerModeEnabled
if isLowPower { log("[\(Date())] 检测到:低电量模式已开启") executeCommand(command: "COMMAND") } else { log("[\(Date())] 检测到:低电量模式已关闭") } }
func executeCommand(command: String) { let task = Process() task.launchPath = "/bin/sh" task.arguments = ["-c", command]
do { try task.run() } catch { print("命令执行失败: \(error)") } } }
let observer = PowerObserver() log("正在监听 macOS 低电量模式变化...")
RunLoop.main.run()
|
编译命令:
1
| $ swiftc LowPowerHook.swift -o LowPowerHook
|
然后编写plist,让其自启,plist内容如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <?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.mycustom.lowpowerhook</string>
<key>ProgramArguments</key> <array> <string>/xxx/powerMonitor/LowPowerHook</string> </array>
<key>RunAtLoad</key> <true/>
<key>KeepAlive</key> <true/>
<key>StandardOutPath</key> <string>/xxx/powerMonitor/Logs/LowPowerHook.log</string> <key>StandardErrorPath</key> <string>/xxx/powerMonitor/Logs/LowPowerHook-error.log</string> </dict> </plist>
|
放在以下目录:~/Library/LaunchAgents/com.mycustom.lowpowerhook.plist
启动命令:launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.mycustom.lowpowerhook.plist
卸载命令:launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.mycustom.lowpowerhook.plist
但是遇到了一个网络问题,因为我执行的命令需要出网,错误如下所示:
1 2
| $ tail -f Logs/LowPowerHook-error.log ssh: connect to host 192.168.1.1 port 22: No route to host
|
但是如果我直接在终端启动LowPowerHook程序,却不会出现该错误。经过研究发现,launchctl控制的自启动程序需要获取LocalNetwork权限才能出网,iTerm已经有权限了,所以直接运行没问题。但是在设置界面中LocalNetwork权限界面无法进行添加或删除。
在这阶段卡了好久,相关的资料也特别少,在资料少的情况下AI自然也不太行了,给的方案唯一有效的是以root启动:
1 2 3
| $ sudo mv ~/Library/LaunchAgents/com.mycustom.lowpowerhook.plist /Library/LaunchDaemons/ $ sudo chown root:wheel /Library/LaunchDaemons/com.mycustom.lowpowerhook.plist $ sudo launchctl bootstrap system /Library/LaunchDaemons/com.mycustom.lowpowerhook.plist
|
的确,也是解决了。但是我不太想使用root权限执行该工具。随着不断搜索资料,逼迫AI,终于提供了解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| $ cat Info.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>CFBundleIdentifier</key> <string>com.mycustom.lowpowerhook</string> <key>CFBundleName</key> <string>LowPowerHook</string> <key>NSLocalNetworkUsageDescription</key> <string>需要连接本地网络以执行 SSH 自动化命令。</string> </dict> </plist> $ swiftc LowPowerHook.swift \ -Xlinker -sectcreate \ -Xlinker __TEXT \ -Xlinker __info_plist \ -Xlinker Info.plist \ -o LowPowerHook codesign --force --sign - LowPowerHook
|
最重要的就是需要添加Info.plist信息,并且进行签名。然后在该程序进行网络请求时,就会弹窗询问是否运行。点击运行后,该程序在后台运行就能出网了。
之后搭建OpenClaw时也遇到该问题,没有给OpenClaw root权限,gateway自启动脚本也是在~/Library/LaunchAgents/目录下,在请求LLM时也一样会遇到网络问题,只需要对node程序进行签名,就能解决问题了。