Mac跑长任务,不想再半开盖端着走了

Mac 跑长任务,不想再半开盖端着走了

!Mac 合盖不睡菜单栏工具总览

其实大家都知道,Mac 可以直接在系统设置里实现「合盖不休眠」。

但我太懒了——偶尔跑长任务才用,来回改配置,切来切去真的很麻烦。

而且还有个更实际的问题:单纯合盖不休眠、屏幕一直亮着,不仅发热严重,还会有**烧屏**的风险。

今天索性顺手写了这个状态栏小工具,核心就是解决这两件事。

## 它做什么

落在一个菜单栏图标上,四个开关,够用就行:

!菜单栏下拉菜单:合盖不睡 / 合盖睡眠 / 合盖熄屏保护 / 开机自启

  • **一键切换**:合盖不睡 / 默认合盖睡眠。想用再开,用完切回去,不用进系统设置翻。
  • **合盖之后自动息屏**:屏幕黑掉,后台任务继续跑;开盖屏幕自动恢复亮度。规避烧屏,也顺带少一点发热。
  • **顶部菜单栏常驻**:随时能看到当前是什么状态,不用猜。
  • **支持开机自启**:常驻工具该有的素养。

## 切换的时候会提醒你

工具不打算假装无事发生。切到「合盖不睡」时会弹一次确认,把代价说明白:

已切换 · 合盖不睡
合盖后电脑继续运行,耗电和发热不会停止。

!切换为合盖不睡后的系统提示

## ⚠️ 重要提醒

  • **仅临时跑任务的时候开启。** 这不是一个「常开」的开关。
  • **就算息屏运行,依旧会发热。** 息屏只解决烧屏和一部分功耗,不解决物理散热。
  • **尽量放在通风位置**,别塞进包里、别压在被子或沙发垫上。
  • **任务结束记得切回睡眠模式。**

合盖不睡本质上是让机器在一个它本来被设计成休息的状态下持续工作,散热路径是断的。把它当成「临时手段」而不是「日常配置」,会安全很多。

## 最后

这类小工具的价值不在于技术难度,而在于它把一件「知道怎么做但懒得做」的事,压缩成了一次点击。

把这套东西交给 Agent 自动配置、直接生成软件的提示词:

# 「合盖开关.app」生成提示词

发给能执行终端命令的 AI agent。把下面整段复制过去即可。

==========

在我这台 MacBook 上做一个菜单栏 App [b 合盖开关.app],装到 `~/Desktop`,并完成编码、编译、签名、安装、启动、自测和汇报。

[b 技术]:Swift + AppKit,`xcrun swiftc` 命令行编译(不要 Xcode 工程;缺 swiftc 先 `xcode-select --install` 并等我)。按 `-target arm64-apple-macosx13.0` 与 `x86_64-apple-macosx13.0` 各编一份,`lipo -create` 合并,每次重建先 `rm -f` 两份切片产物再合并,避免拿到旧 fat 二进制。`LSUIElement=true` + `setActivationPolicy(.accessory)` 不占 Dock;启动时用 `NSRunningApplication` 按 bundle id 判单实例,已有则激活它并退出自己。

[b 核心开关]:读 `pmset -g` 的 `SleepDisabled`(1=合盖不睡,0/读不到=合盖睡眠),读取无需 root。写入 `sudo -n pmset -a disablesleep 0|1`;错误含 `password` 时回退 `osascript -e 'do shell script "pmset -a disablesleep N" with administrator privileges'`;返回含 `-128` 视为取消,提示"已取消,保持原状态"。[b 只准改 `disablesleep`],不得碰 `sleep`/`displaysleep`/`hibernatemode`;`disablesleep` 是全局键,插电和电池是同一份状态,如实告诉我这点。

[b 合盖熄屏保护](默认开,状态存 UserDefaults):每 0.5 秒用 IOKit 读 `IOPMrootDomain` 的 `AppleClamshellState`(`IOServiceMatching` + `IORegistryEntryCreateCFProperty`,返回值 NSNumber 和字符串 "Yes"/"No" 两种都要解析),合盖时先记录内屏亮度再设为 0(熄背光),开盖后精确恢复原值;合盖期间亮度被抬起则再次压回 0;关闭该开关或 App 退出时立即恢复。[b macOS 27 上 `CoreDisplay.framework` 已不存在],亮度符号在 `/System/Library/PrivateFrameworks/DisplayServices.framework/DisplayServices` 的 `DisplayServicesGetBrightness`/`DisplayServicesSetBrightness`,用 `dlopen`+`dlsym`+`unsafeBitCast`,签名为 `(UInt32, UnsafeMutablePointer<Float>)->Int32` 和 `(UInt32, Float)->Int32`,内屏 id 用 `CGGetActiveDisplayList`+`CGDisplayIsBuiltin` 取。只动内建屏,别碰外接屏;符号取不到时菜单项标题标注"(本机接口不可用)"。注意 macOS 只有合盖布尔值、[b 没有连续转轴角度],"开盖超过 15 度才恢复"做不到,按布尔值恢复即可。

[b 开机自启]:优先 `SMAppService.mainApp.register()/unregister()`,抛错回退 osascript `System Events` 的 `make login item ... {path:<bundle路径>, hidden:false}` / `delete login item "<app名>"`。只在当前状态 ≠ 目标时调用对应机制,避免注册出重复登录项,并以复查结果判定成败;首次会弹自动化授权框,提示我点允许。

[b 状态栏图标]:代码绘制 28×18 pt 笔记本(圆角屏幕 + 底座),屏中表情 😄=不睡、💤=睡眠;线条用 `NSColor.labelColor` 适配深浅色,`isTemplate=false`,tooltip 显示状态,菜单栏不放文字。每 5 秒刷新图标。

[b 菜单]:`statusItem.menu` 点击直接弹菜单:`合盖不睡(继续运行)` / `合盖睡眠(默认)` / ─ / `合盖熄屏保护` / `开机自启` / ─ / `退出`。前两项二选一打勾,后两项勾选式开关;点当前项不动作;`menuNeedsUpdate` 时重读 `pmset` 并刷新全部勾选(含自启真实状态)。切换成功播 `NSSound(named:"Glass")` 并用 `NSAlert` 说明含义(含"继续运行会带来耗电和发热"),失败 `NSAlert` 显示错误原文;[b 必须回读 `pmset` 确认状态真的变了才算成功]。

[b 留痕]:所有看不见的动作(启动、切换、熄屏、恢复、开关变更)追加写入 `~/Library/Logs/合盖开关.log`,熄屏和恢复两行都带上亮度数值,否则我无法确认它到底有没有生效。

[b 打包]:`Info.plist` 含 `CFBundleExecutable`/`Identifier`/`Name`/`PackageType=APPL`/`ShortVersionString`/`LSMinimumSystemVersion=13.0`/`LSUIElement`/`NSHighResolutionCapable`/`CFBundleIconFile=AppIcon`。App 图标同样代码绘制:1024 主图(浅蓝灰渐变圆角底 + 深灰笔记本 + 屏上 😄)→ iconset 10 个尺寸(16/32/64/128/256/512 及 @2x)→ `iconutil -c icns` → `Contents/Resources/AppIcon.icns`。装好 bundle 后[b 必须先 `xattr -cr <app>` 再 `codesign --force --sign - <app>`](否则报 detritus not allowed),再 `codesign --verify --strict`、`open`、`pgrep` 确认进程、`lsregister -f` 刷新图标缓存。

[b 可选免密(先问我)]:先写临时文件、`visudo -cf` 校验通过才安装,绝不把未校验内容写进 `/etc/sudoers*`(写坏会让 sudo 全局不可用):

bash
U=$(whoami); printf '%s ALL=(root) NOPASSWD: /usr/bin/pmset -a disablesleep 0, /usr/bin/pmset -a disablesleep 1n' "$U" > /tmp/lid.sudoers
visudo -cf /tmp/lid.sudoers && sudo install -o root -g wheel -m 0440 /tmp/lid.sudoers /etc/sudoers.d/lid-keeper

验证两件事:`sudo -n pmset -a disablesleep 1` 免密通过;`sudo -n true` 仍要密码(证明权限没被放大)。

[b 自测并逐项报告]:`lipo -info` 双架构;签名 strict 通过;进程在跑;菜单勾选与 `pmset -g` 一致;终端手动 `sudo pmset -a disablesleep 0` 后 5 秒内图标 😄/💤 跟着变;取消授权框不改状态;除 `disablesleep` 外无任何其它 `pmset` 写入;单独写一个探针脚本验证亮度读/设/恢复可用;合盖再开盖一次后日志里出现"熄屏(原亮度 X)"和"恢复 X"且数值对称。

[b 如实告知]:你看不到我的屏幕——图标外观、弹窗、Finder 图标必须列为"未验证项"由我确认,别声称已验证;磁盘接近写满时 `swiftc` 会报 `No space left on device`,先提醒我清理;本 App 是 ad-hoc 签名、未公证,别人经微信/网盘/浏览器下载会带隔离属性被 Gatekeeper 拦(`spctl --assess` 返回 rejected),需「系统设置 → 隐私与安全性 → 仍要打开」或 `xattr -cr` 放行,AirDrop 通常不受影响。

**原文地址**:Mac跑长任务,不想再半开盖端着走了🥲 — 小红书https://xhslink.cn/o/7RmGBl3oOFm

短链:

*本文原发布于小红书,2026-10-27。*

关于本文:正文同步自 MorePlay(moreplay.cn),排版与原文一致;文中的图片已经保存到本站,原文另有独立页面。 —— 同步于 2026-10-27 06:05 · 在博客站查看原文