系统集成
剪贴板、文件对话框、通知、密钥等操作系统能力,以及失败时如何报告。
app 包提供一小组同步的系统集成接口。每个操作要么按声明的语义完成,要么返回错误;适配层从不报告它没有做到的成功。
| 能力 | 函数 |
|---|---|
| 剪贴板文本 | app.ClipboardText、app.SetClipboardText |
| 文件对话框 | app.OpenFiles、app.OpenDirectory、app.SaveFile |
| 打开 URL | app.OpenURL |
| 用默认应用打开本地文档(绝不运行程序) | app.OpenPath |
| 通知与声音 | app.SendNotification、app.PlaySystemSound |
| 光标 | app.SetCursor |
| 系统首选语言 | app.PreferredLanguages |
| 系统外观(浅色/深色) | app.SystemAppearance、app.WatchSystemAppearance |
| 系统绘制部分的外观 | app.SetNativeAppearance |
| 减弱动效 | app.ReduceMotion |
| 密钥 | app.StoreSecret、app.LoadSecret、app.DeleteSecret |
| 状态栏图标与面板 | Application.AddStatusItem、app.WindowPanel |
| 等宽字体 | app.MonospaceFamilies |
各平台用什么实现
每个函数都映射到平台自己的接口:macOS 上是 NSPasteboard、NSOpenPanel 和 NSWorkspace;Windows 上是 Win32 剪贴板、IFileOpenDialog 和 ShellExecuteW;Linux 上是 X11 选区,文件对话框使用 zenity 或 kdialog,打开 URL 使用 xdg-open 或 gio,通知使用 notify-send。密钥存入钥匙串、凭据管理器或 Secret Service。
完整的表格,包括某个平台做不到某件事的情形,见仓库中的 docs/system-integrations.md。
错误
调用方用 errors.Is 比较,永远不要比较字符串:
| 错误 | 含义 |
|---|---|
ErrUnsupported |
当前平台或桌面环境无法提供该能力。 |
ErrCanceled |
用户关闭了文件对话框。 |
ErrPermissionDenied |
用户或系统拒绝了。 |
ErrAsyncRequired |
浏览器只提供 Promise,同步接口不会等待它。 |
ErrUserGestureRequired |
浏览器拒绝了不在直接用户手势中的调用。 |
值得了解的边界
- Linux 上的文件对话框、URL 分发和通知,会在用户请求时启动已安装的桌面工具。Viva 不捆绑 GTK、Qt 或 D-Bus 栈。
- 在浏览器里,剪贴板和文件选择器按设计返回
ErrAsyncRequired。提前返回会谎报成功,而等待会让 WebAssembly 事件循环死锁。 - 要跟随系统的浅色或深色外观,就在绘制时读取
app.SystemAppearance,并只调用一次app.WatchSystemAppearance,传入一个请求重绘的函数。它在事件循环线程上调用,且只在外观真的变了时调用。Linux 不监听桌面门户,而是在窗口获得焦点时重新读取一次,桌面没有给出偏好时返回AppearanceUnknown;无窗口的Driver在调用SetSystemAppearance之前也返回AppearanceUnknown。 - 如果用户可以不管系统而固定选择浅色或深色,就用这个选择调用
app.SetNativeAppearance,这样 macOS 自己绘制的窗口按钮、菜单、文件对话框和原生文本编辑会和窗口一致;传入AppearanceUnknown就还给系统,期间SystemAppearance仍然报告系统自己的外观。 - Linux 剪贴板读取有三秒期限,不增加空闲线程或轮询循环。