使用说明
本字典整理 Wails v2 日常开发最常查的 API,版本锚点是 v2.9.2(2024 年 11 月时点的 v2 最新稳定版,v3 尚在 alpha,未收录)。Go 侧条目全部来自 github.com/wailsapp/wails/v2/pkg/runtime 包,前端条目来自 CLI 生成的 wailsjs/runtime 模块(同一套函数也挂在 window.runtime 上)。条目按”签名 → 什么时候用 → 最小示例 → 坑”组织,示例自包含可复制,这里只做查与抄,原理讲解看《Wails 框架要点》。
一、Go 侧运行时 API
组内共性:所有函数第一个参数都是 ctx context.Context——就是 OnStartup 回调里那个,丢了它所有运行时调用都不生效。易混点集中在事件家族:Emit 是发,On 是收,Off 是按名解绑,Once 是收一次就解绑。
EventsEmit
func EventsEmit(ctx context.Context, eventName string, optionalData ...interface{})
向所有事件监听方广播一条事件,载荷跟在事件名后,数量不限。给前端推进度、状态变更用它。
runtime.EventsEmit(a.ctx, "download:progress", file, done, total)
⚠️ OnDomReady 之前 emit,前端监听器还没注册,事件直接丢。初始状态用绑定方法拉取,事件只做增量通知。
EventsOn
func EventsOn(ctx context.Context, eventName string, callback func(optionalData ...interface{})) func()
Go 侧订阅事件(多为前端发来的),返回值是取消函数,调它即解绑。与 JS 侧同名函数行为一致。
off := runtime.EventsOn(a.ctx, "ui:filter", func(optionalData ...interface{}) {
// JSON 边界:JS 发来的数字一律是 float64,断言 int 会失败
keyword, _ := optionalData[0].(string)
_ = keyword
})
⚠️ 载荷是 []interface{},数字是 float64、字符串才是 string;高频数据别走事件,走绑定方法,事件通道没有回执。
EventsOnce 与 EventsOnMultiple
func EventsOnce(ctx context.Context, eventName string, callback func(...interface{})) func()
func EventsOnMultiple(ctx context.Context, eventName string, callback func(...interface{}), counter int) func()
Once 触发一次自动解绑;OnMultiple 限定最多触发 counter 次。适合”初始化完成即失效”的一次性握手。
⚠️ Once 的回调里如果再注册同名监听,注意解绑时机,避免前一次的残留监听还在收。
EventsOff 与 EventsOffAll
func EventsOff(ctx context.Context, eventName string, additionalEventNames ...string)
func EventsOffAll(ctx context.Context)
按名批量解绑;OffAll 清空全部监听,页面整体刷新前用。
⚠️ 优先用 EventsOn 返回的取消函数精确解绑;Off 是按事件名一刀切,会把同名的其他监听一起干掉。
ClipboardGetText 与 ClipboardSetText
func ClipboardGetText(ctx context.Context) (string, error)
func ClipboardSetText(ctx context.Context, text string) error
读、写系统剪贴板的纯文本。做剪贴板类工具、把导出结果一键塞进剪贴板都用它。
text, err := runtime.ClipboardGetText(a.ctx)
if err != nil {
// 剪贴板里可能是图片等非文本内容,按错误处理而不是当空串
runtime.LogDebug(a.ctx, "clipboard not text")
}
⚠️ 剪贴板内容可能是图片、文件等非文本对象,GetText 会返回错误而不是空串,别把错误当”剪贴板为空”吞掉。
OpenFileDialog 与 SaveFileDialog
func OpenFileDialog(ctx context.Context, dialogOptions OpenDialogOptions) (string, error)
func SaveFileDialog(ctx context.Context, dialogOptions SaveDialogOptions) (string, error)
单选文件打开框、保存框。OpenDialogOptions 常用字段:DefaultDirectory、DefaultFilename、Title、Filters([]FileFilter,按 DisplayName/Pattern 过滤)。多选与目录用 OpenMultipleFilesDialog / OpenDirectoryDialog。
path, err := runtime.SaveFileDialog(a.ctx, runtime.SaveDialogOptions{
DefaultFilename: "export.json",
Title: "保存导出文件",
})
⚠️ 用户取消选择时返回空串与 nil error,两个返回值都要判:只判 err 不判空串,后面拿空路径去写文件必炸。
MessageDialog
func MessageDialog(ctx context.Context, dialogOptions MessageDialogOptions) (string, error)
原生消息框,替代网页 alert——生产构建里没有浏览器弹窗能力,系统级确认框用它。Type 常量有 InfoDialog / WarningDialog / ErrorDialog / QuestionDialog;Buttons 自定义按钮文字,返回点中的按钮文字。
choice, _ := runtime.MessageDialog(a.ctx, runtime.MessageDialogOptions{
Type: runtime.QuestionDialog,
Title: "清空历史",
Message: "确定要清空全部记录吗?",
Buttons: []string{"确定", "取消"},
})
if choice != "确定" {
return nil
}
⚠️ 返回值是按钮文字字符串,改了 Buttons 数组记得同步改判断,最好用常量。
BrowserOpenURL
func BrowserOpenURL(ctx context.Context, url string)
用系统默认浏览器打开链接,而不是在 WebView 里导航走——”关于页”、”帮助文档”这类外部链接的规范出口。
⚠️ 让 WebView 内部导航到外部网站会把应用变成”浏览器”,且脱离了应用上下文;外部 URL 一律走这个函数。
日志家族:LogTrace / LogDebug / LogInfo / LogWarning / LogError / LogFatal
runtime.LogInfo(a.ctx, "config loaded")
分级日志,dev 模式打到控制台。LogFatal 记录后直接终止进程,只用于”活不下去”的启动失败。
⚠️ LogFatal 在绑定方法里等于”点一下按钮应用就退”,绑定方法里的失败应该走 error 返回值。
Environment
func Environment(ctx context.Context) EnvironmentInfo // BuildType / Platform / Arch
BuildType 取值 “dev” 或 “production”,用来在运行时开关调试行为;Platform/Arch 打日志定位用户环境。
⚠️ BuildType 是编译期决定的运行时事实,不要用它做需要编译期裁剪的事(那该用 build tag)。
Show、Hide 与 Quit
func Show(ctx context.Context)
func Hide(ctx context.Context)
func Quit(ctx context.Context)
显示/隐藏窗口(常驻应用的核心组合)、退出应用。配合 HideWindowOnClose 选项做”点关闭只是藏起来”。
⚠️ Hide 之后用户没有任何入口唤回(v2 没有系统托盘),要么留绑定按钮,要么用 SingleInstanceLock 让二次启动唤回主窗口。
OnFileDrop
func OnFileDrop(ctx context.Context, callback func(x, y int, paths []string))
func OnFileDropOff(ctx context.Context)
接收文件拖入,回调拿到落点坐标与绝对路径列表。需在 options.App 里配 DragAndDrop: &options.DragAndDrop{EnableFileDrop: true}(v2.9.0 起提供)。
⚠️ 不配 DragAndDrop 选项时回调永远不触发;WebView 自己的 drop 行为想关掉用 DisableWebViewDrop,否则拖图进窗口会当资源打开。
窗口函数速记
WindowSetSize / WindowGetSize / WindowSetPosition / WindowGetPosition / WindowSetMinSize / WindowSetMaxSize / WindowCenter / WindowShow / WindowHide / WindowMaximise / WindowUnminimise / WindowSetAlwaysOnTop / WindowSetTitle / WindowFullscreen——签名统一是 func WindowXxx(ctx context.Context, ...),Get 类返回值。窗口置顶常驻小面板的用法:runtime.WindowSetAlwaysOnTop(a.ctx, true)。
⚠️ v2 是单窗口模型,这些函数都作用于唯一主窗口;WindowSetAlwaysOnTop 是 v2.6.0 起的能力,更早版本没有。
二、options.App 关键字段
组内共性:全部在 wails.Run(&options.App{...}) 里一次性传入,运行时改不了。易混点:StartHidden 是”启动时藏”,HideWindowOnClose 是”点关闭改藏”,两个是不同行为。
| 字段 | 类型与语义 | 什么时候用 |
|---|---|---|
| Bind | []interface{},要暴露给前端的结构体实例 | 几乎所有应用必配 |
| AssetServer | *assetserver.Options,Assets 指内嵌 fs.FS | 单文件产物的基础,配合 go:embed |
| OnStartup / OnDomReady / OnBeforeClose / OnShutdown | 生命周期回调 | 存 ctx / 发首屏事件 / 拦截关闭 / 清理 |
| StartHidden | bool,启动时不显示窗口 | 常驻工具的静默启动 |
| HideWindowOnClose | bool,点关闭改为隐藏 | 常驻应用替代 OnBeforeClose 拦截 |
| WindowStartState | options.Normal / Maximised / Minimised / Fullscreen | 控制初始窗口状态 |
| AlwaysOnTop | bool,窗口置顶 | 小面板、悬浮工具 |
| SingleInstanceLock | *options.SingleInstanceLock,单实例锁(v2.7.0+) | 防止多开;二次启动唤回主窗口 |
| DragAndDrop | *options.DragAndDrop,文件拖入(v2.9.0+) | 接收文件路径的应用 |
| EnableDefaultContextMenu | bool,生产构建启用默认右键菜单 | 需要”复制粘贴”右键操作时 |
Bind 展开示例
app := NewApp()
Bind: []interface{}{app}, // 换行写在 options.App 里;绑定的实例方法均暴露
⚠️ 绑定的是实例:同一个结构体 New 两份、只绑了一份,另一份的状态前端永远看不到,症状是”方法能调但字段都是零值”。
SingleInstanceLock 展开示例
SingleInstanceLock: &options.SingleInstanceLock{
UniqueId: "e8f2b3c0-7d1a-4b9e-9c3f-demo-app-uuid", // 用 UUID,全局唯一
OnSecondInstanceLaunch: app.onSecondInstanceLaunch,
},
// 第二次双击 exe 时走到这里:唤起已存在的主窗口
func (a *App) onSecondInstanceLaunch(data options.SecondInstanceData) {
runtime.WindowUnminimise(a.ctx)
runtime.Show(a.ctx)
}
⚠️ 官方文档明确:该回调不会自动聚焦窗口,必须自己调 WindowUnminimise + Show;且从第二实例传来的参数按不可信输入对待。Linux 上窗口管理器可能拒绝抢焦点,这是平台行为不是 bug。
三、前端 JS 运行时
组内共性:import 自 wailsjs/runtime(CLI 生成),也全局挂在 window.runtime 上;与 Go 侧同名函数语义一致,只是没有 ctx 参数。
EventsOn(JS 侧)
import { EventsOn, EventsEmit, EventsOff } from '../wailsjs/runtime';
// 返回取消函数,组件卸载时调用,防止监听越积越多
const off = EventsOn('download:progress', (file, done, total) => {
bar.style.width = (done / total) * 100 + '%';
});
EventsEmit('ui:filter', 'invoice'); // 前端也能发,Go 侧 EventsOn 收
⚠️ 最常见的内存泄漏来源:组件每次挂载都 EventsOn、从不解绑,同一事件收到 N 次回调。取消函数要么存起来在卸载时调,要么用 EventsOff 按名清理。
ClipboardGetText 与 ClipboardSetText(JS 侧)
import { ClipboardSetText } from '../wailsjs/runtime';
const ok = await ClipboardSetText('已复制的文本');
⚠️ 这套函数走的是 Wails 的运行时通道,与浏览器 navigator.clipboard 的权限模型无关;但在 WebView 里 navigator.clipboard 常受限制,要稳定读写优先用 runtime 版。
其他 JS 侧函数
WindowSetTitle / WindowCenter / WindowFullscreen / WindowSetSize 等窗口组、LogInfo 等日志组、BrowserOpenURL、ScreenGetAll、Quit / Show / Hide、Environment——全部与 Go 侧同名同语义。要在”非绑定场景”(如模板事件)里快速用就用 window.runtime.xxx。
⚠️ JS 侧没有对话框函数:文件选择、消息确认在 v2 里只有 Go 侧 runtime.Dialog 系列能做,封装成绑定方法给前端调。
四、CLI 与项目配置
组内共性:命令都不钉版本号(@latest 或项目内固定版本);wails.json 是 CLI 与项目构建的单一事实来源,手写 npm 命令绕过它迟早出构建顺序问题。
| 命令 | 一句话用途 | 常用参数 |
|---|---|---|
| wails init | 从模板生成项目 | -n 项目名,-t 模板(vue-ts/react-ts/svelte-ts/vanilla 等) |
| wails dev | 开发模式:热更新 + 生成绑定 | -browser 用浏览器开调试页 |
| wails build | 生产构建,产出单文件可执行程序 | -platform 目标平台,-tags 追加构建标签 |
| wails doctor | 体检平台依赖是否齐全 | 装完环境先跑一次 |
| wails generate module | 重新生成 wailsjs 绑定模块 | 绑定类型报错时刷新 |
| wails update | 升级 CLI | 不钉版本号,升级前看 changelog |
| wails.json 字段 | 一句话用途 | 有什么坑 |
|---|---|---|
| frontend:install | 构建前安装前端依赖的命令 | 改了包管理器(pnpm/yarn)要同步改这里 |
| frontend:build | wails build 时构建前端产物的命令 | 产物没进 dist 目录时 embed 会编译失败 |
| wailsjsdir | 自动生成绑定模块的输出目录 | 默认在项目根 wailsjs,前端 import 路径以此为锚 |
| outputfilename | 二进制产物文件名 | Windows 产物自动加 .exe |
| devServer | dev 服务器地址,默认 localhost:34115 | 端口被占时浏览器调试页起不来 |
| assetdir | dev 模式静态资产目录 | 与 AssetServer.Assets 是两套事:前者 dev 用,后者打进二进制 |
速查表
| 条目 | 一句话用途 | 有什么坑 |
|---|---|---|
| EventsEmit | 广播事件给前端 | DomReady 前发等于白发 |
| EventsOn | 订阅事件,返回取消函数 | JS 数字到 Go 是 float64 |
| EventsOnce | 订阅一次即解绑 | 适合握手,别做常驻监听 |
| EventsOff | 按名批量解绑 | 会误杀同名的其他监听 |
| ClipboardGetText / SetText | 读写剪贴板文本 | 非文本内容返回 error 不是空串 |
| OpenFileDialog / SaveFileDialog | 文件选择框 | 取消时是空串 + nil error |
| MessageDialog | 原生消息/确认框 | 返回值是按钮文字字符串 |
| BrowserOpenURL | 系统浏览器打开链接 | 别让 WebView 导航去外站 |
| Log 家族 | 分级日志 | LogFatal 会直接退出进程 |
| Environment | dev/production 与平台信息 | 运行时事实,别当编译期开关 |
| Show / Hide / Quit | 窗口显隐与退出 | Hide 后要有唤回入口 |
| OnFileDrop | 接收文件拖入 | 必须先配 DragAndDrop 选项 |
| WindowSetAlwaysOnTop | 窗口置顶(v2.6.0+) | v2 单窗口,只作用于主窗口 |
| Bind | 暴露 Go 结构体方法给前端 | 绑实例不是绑类型 |
| AssetServer.Assets | 内嵌前端资产 | dist 为空编译失败 |
| HideWindowOnClose | 点关闭改为隐藏 | 与 OnBeforeClose 拦截二选一 |
| SingleInstanceLock | 单实例锁 + 二次启动回调(v2.7.0+) | 回调不自动聚焦,要手动 Show |
| DragAndDrop 选项 | 启用文件拖入(v2.9.0+) | 不开 EnableFileDrop 拖入无回调 |
| JS EventsOn | 前端订阅事件 | 不解绑是泄漏源头 |
| wails dev / build | 开发热更新 / 生产单文件产物 | 改前端必须重新 build 才进产物 |
| wails generate module | 重新生成 wailsjs 绑定 | 类型对不上时先跑它 |
相关阅读:安装与第一个窗口见《Wails 入门》;绑定与事件的原理展开见《Wails 框架要点》;这些 API 组合起来能做什么,看实战篇《用 Wails 做一个剪贴板历史工具》。Go 侧函数的签名风格(ctx 第一参、多返回值、error 收尾)是标准 Go 惯例,不熟悉的先补《Go内置函数详解》。
版本核实(以官方文档为准):本字典基于 Wails v2.9.2(2024 年 11 月时点的 v2 最新稳定版)核对,含 v2.7.0 起的 SingleInstanceLock、v2.9.0 起的 DragAndDrop、v2.6.0 起的 WindowSetAlwaysOnTop 等版本敏感条目;各签名以 GitHub 仓库 v2.9.2 标签源码与 wails.io 文档为准。