1. 问题背景
在 macOS 上通过 AppleScript 控制窗口时,很多教程推荐两种写法来最小化窗口。但在实际使用中,这两种写法在第三方应用上往往不可靠,甚至直接报错。本文通过源码验证三种最小化方法,给出实测对比结论,并提供可复用的一键最小化脚本、适用范围说明以及面向人类开发者、对话式 AI 和代码 Agent 的速查指南。
2. 三种最小化方法实测对比
| 方法 | 关键代码 | 系统自带应用 | 第三方应用 | 结论 |
|---|---|---|---|---|
| miniaturized 属性 | set miniaturized of every window to true | 可能有效 | 报错 | 不可用 |
| AXMinimize 动作 | perform action "AXMinimize" of w | 可能有效 | 静默失败 | 不可靠 |
| AXMinimized 赋值 | set value of attribute "AXMinimized" to true | 有效 | 有效 | 推荐 |
2.1 写法一:直接设置 miniaturized 属性
网上常见的写法是直接对窗口设置 miniaturized 属性:
applescript
tell application "System Events"
tell process "SomeApp"
set miniaturized of every window to true
end tell
end tell
实测结果:报错。错误信息为「不能将 miniaturized of UI element 设置为 any」。原因是 every window 返回的 UI 元素集合中,并非所有元素都支持 miniaturized 属性,批量赋值会触发类型错误。
2.2 写法二:执行 AXMinimize 动作
另一种常见写法是遍历窗口并执行 AXMinimize 动作:
applescript
tell application "System Events"
tell process "SomeApp"
repeat with w in windows
perform action "AXMinimize" of w
end repeat
end tell
end tell
实测结果:不报错,但窗口没有最小化。随后验证 AXMinimized 属性仍为 false。原因是部分第三方应用(如基于 Electron 的聊天客户端、Chromium 内核浏览器)的窗口不响应 AXMinimize 动作,属于静默失败。
3. 最终生效的写法
经过实测,最终可靠的做法是通过 System Events 直接给 AXMinimized 属性赋值:
applescript
tell application "System Events"
set value of attribute "AXMinimized" of window 1 of process "AppName" to true
end tell
关键点有三个:
- 必须指定具体窗口(window 1),不能用 every window 批量操作。
- 通过 attribute "AXMinimized" 直接设值,绕过 miniaturized 属性的类型检查。
- 设置后需延迟 0.5 秒再验证,因为最小化有动画过渡。
验证脚本如下,返回 true 即最小化成功:
applescript
tell application "System Events"
set isMin to value of attribute "AXMinimized" of window 1 of process "AppName"
return isMin
end tell
4. 可复用脚本:一键最小化多个应用
把上面的方法封装成函数,即可一次最小化多个应用:
bash
osascript <<'EOF'
on minimizeApp(appName)
tell application "System Events"
try
set winCount to count of windows of process appName
repeat with i from 1 to winCount
set value of attribute "AXMinimized" of window i of process appName to true
end repeat
delay 0.5
return appName & ": 已最小化 " & winCount & " 个窗口"
on error e
return appName & ": 失败 - " & e
end try
end tell
end minimizeApp
minimizeApp("Doubao")
minimizeApp("System Settings")
minimizeApp("Vivaldi")
EOF
脚本会遍历指定应用的每个窗口并逐个设置 AXMinimized 属性,最后返回每个应用被最小化的窗口数量;如果某个应用出错,会返回失败原因而不是中断整个脚本。
5. 适用范围与前提
- 操作系统:macOS,实测 Ventura 及以上版本。
- 权限:必须在系统设置的「隐私与安全性 → 辅助功能」中授予执行终端或 AI 客户端权限,首次操作会弹出授权提示。
- 适用对象:系统自带应用和第三方应用均有效,Electron 和 Chromium 内核应用已验证。
- 不适用:无窗口的后台进程、已最小化窗口(再次设置无副作用但无意义)。
6. 单窗口截图
最小化其他窗口后,仍可进一步只截取目标窗口,完全排除桌面干扰:
bash
screencapture -x -l <窗口ID> /tmp/output.png
参数说明:-x 不播放截图音效;-l 后跟窗口 ID,只截取指定窗口而非全屏;输出为 PNG,窗口自带圆角和阴影。
窗口 ID 获取方法,用 Swift 调用 CoreGraphics 框架:
swift
import CoreGraphics
let options = CGWindowListOption(arrayLiteral: .excludeDesktopElements, .optionOnScreenOnly)
let windows = CGWindowListCopyWindowInfo(options, kCGNullWindowID) as! [[String: Any]]
for w in windows {
if let name = w[kCGWindowName as String] as? String,
let id = w[kCGWindowNumber as String] as? Int {
print("id=(id) name=(name)")
}
}
7. 人类开发者速查
- 最小化单个窗口:set value of attribute "AXMinimized" of window 1 of process "App" to true。
- 验证是否最小化:读取同一属性,返回 true 或 false。
- 单窗口截图:screencapture -x -l 窗口ID output.png。
- 查窗口 ID:用 Swift 脚本遍历 CGWindowListCopyWindowInfo。
- 常见坑:set miniaturized 报错、perform action "AXMinimize" 静默失败,都改用 AXMinimized 属性赋值。
- 隐藏标题栏的窗口(如 Vivaldi)同样可以通过此方法最小化,不需要先显示标题栏。
8. 对话式 AI 速查
问法示例:「帮我把 Mac 上的 XX 和 YY 窗口最小化,然后截个屏看看」。
回答要点:先确认辅助功能权限已授予,用 AXMinimized 属性赋值法逐个窗口最小化,设置后延迟 0.5 秒验证属性值,再用 screencapture -l 单窗口截图。如果用户不在电脑旁,建议先最小化所有干扰窗口露出纯色壁纸,再全屏截图,这样 AI 更容易定位有效内容。
9. 代码 Agent 速查
可直接执行的最小化加截图组合命令:
bash
# 第一步:最小化干扰窗口
osascript -e 'tell application "System Events" to set value of attribute "AXMinimized" of window 1 of process "Doubao" to true'
第二步:获取目标窗口 ID(需先准备 wininfo.swift)
WIN_ID=$(swift /tmp/wininfo.swift 2>/dev/null | grep "目标标题" | head -1 | grep -o 'id=[0-9]*' | cut -d= -f2)
第三步:单窗口截图
screencapture -x -l "$WIN_ID" /tmp/capture.png
注意:osascript 单行模式下如果应用名含空格,需用双引号包裹。窗口 ID 为纯数字,screencapture -l 不接受 0 或负数。
10. 总结
在 macOS 上最小化第三方应用窗口时,应优先使用 set value of attribute "AXMinimized" 的方式,并指定具体窗口。同时要注意区分应用类型,避免照搬教程导致失败。配合可复用的一键最小化脚本、单窗口截图和 Bevy 启动等待策略,可以稳定完成远程截屏判断画面的任务。