go wails 如何开发桌面程序
· 阅读需 9 分钟
Wails 是一款基于 Go 语言的跨平台桌面应用开发框架,核心优势是用 Go 编写后端逻辑 + 前端技术(HTML/CSS/JS/Vue/React)编写 UI,无需打包完整浏览器内核(如 Electron),生成的程序体积更小(MB 级)、启动更快、资源占用更低。
本文将从环境搭建、项目创建、核心特性、实战开发、打包发布五个维度,手把手教你用 Wails 开发桌面程序。
一、Wails 核心优势(对比 Electron)
| 特性 | Wails | Electron |
|---|---|---|
| 程序体积 | 小(5-20MB) | 大(100+MB) |
| 启动速度 | 快(毫秒级) | 慢(秒级) |
| 内存占用 | 低(几十MB) | 高(几百MB) |
| 开发语言 | Go + 前端(任意框架) | JS/TS + 前端 |
| 跨平台 | Windows/macOS/Linux | 同左 |
| 系统集成 | 深度集成 Go 生态 | 需通过 Node 插件集成 |
| 打包方式 | 静态编译 | 打包 ASAR 资源 |
二、环境搭建
1. 基础依赖
Wails 依赖 Go 环境和前端构建工具,需先安装:
(1)安装 Go
- 下载地址:https://go.dev/dl/(要求 Go 1.21+)
- 验证:
go version
(2)安装前端依赖(Node.js + npm/yarn/pnpm)
- 下载 Node.js:https://nodejs.org/(要求 Node 16+)
- 验证:
node -v && npm -v
(3)安装 Wails 命令行工具
# 安装 Wails v2(最新稳定版)
go install github.com/wailsapp/wails/v2/cmd/wails@latest
# 验证安装
wails version
# 输出示例:Wails CLI v2.8.0
(4)安装系统依赖(根据系统)
- Windows:无需额外依赖(自动安装 Build Tools);
- macOS:安装 Xcode 命令行工具:
xcode-select --install; - Linux(Ubuntu/Debian):
sudo apt install libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev gcc
2. 初始化 Wails 环境
# 检查环境是否满足要求(自动检测依赖)
wails doctor
输出 SUCCESS 表示环境正常,若有缺失依赖,按提示安装即可。
三、第一个 Wails 项目:Hello World
1. 创建项目
# 创建新项目(交互式,按提示选择)
wails init
# 或直接指 定模板(Vue 模板,推荐)
wails init -n mywailsapp -t vue
# -n:项目名;-t:模板(vue/react/svelte/vanilla)
2. 项目结构解析
创建完成后,项目目录如下(以 Vue 模板为例):
mywailsapp/
├── app.go # Go 后端核心逻辑(与前端通信)
├── frontend/ # 前端代码(Vue 项目)
│ ├── src/ # Vue 源码(组件、样式、逻辑)
│ ├── package.json # 前端依赖
│ └── vite.config.js # 前端构建配置
├── go.mod/go.sum # Go 模块依赖
├── main.go # 程序入口
└── wails.json # Wails 配置(窗口大小、图标、打包等)
3. 核心文件说明
(1)main.go(程序入口)
package main
import (
"embed"
"github.com/wailsapp/wails/v2"
"github.com/wailsapp/wails/v2/pkg/options"
"github.com/wailsapp/wails/v2/pkg/options/assetserver"
)
//go:embed all:frontend/dist
var assets embed.FS
func main() {
// 创建应用实例
app := NewApp()
// 运行应用
err := wails.Run(&options.App{
Title: "My Wails App", // 窗口标题
Width: 800, // 窗口宽度
Height: 600, // 窗口高度
// 绑定前端资源
AssetServer: &assetserver.Options{
Assets: assets,
},
// 绑定 Go 后端实例(供前端调用)
Binding: app,
// 窗口样式(无边框/透明等)
Windows: &options.Windows{
WindowIsTranslucent: false,
DisableWindowIcon: false,
},
})
if err != nil {
println("Error:", err.Error())
}
}
(2)app.go(Go 后端逻辑)
package main
import (
"context"
"fmt"
)
// App 结构体(供前端绑定调用)
type App struct {
ctx context.Context
}
// NewApp 创建 App 实例
func NewApp() *App {
return &App{}
}
// Startup 应用启动时执行(初始化逻辑)
func (a *App) Startup(ctx context.Context) {
a.ctx = ctx
}
// Greet 供前端调用的方法(参数/返回值支持 JSON 序列化类型)
func (a *App) Greet(name string) string {
return fmt.Sprintf("Hello %s! Welcome to Wails!", name)
}
(3)前端代码(frontend/src/App.vue)
<script setup>
import { ref } from 'vue'
// 引入 Wails 内置的 Go 绑定对象
import { invoke } from '@wailsapp/runtime'
const name = ref("")
const result = ref("")
// 调用 Go 后端的 Greet 方法
const greet = async () => {
result.value = await invoke("Greet", name.value)
}
</script>
<template>
<div class="container">
<h1>Wails + Vue Hello World</h1>
<input v-model="name" placeholder="请输入名字" />
<button @click="greet">点击问候</button>
<p>{{ result }}</p>
</div>
</template>
<style scoped>
.container {
padding: 20px;
text-align: center;
}
input {
padding: 8px;
margin-right: 10px;
}
button {
padding: 8px 16px;
background: #42b983;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
</style>
4. 运行开发环境
# 进入项目目录
cd mywailsapp
# 启动开发模式(热更新,前端/Go 代码修改后自动刷新)
wails dev
运行成功后,会弹出桌面窗口,输入名字点击按钮,即可看到 Go 后端返回的结果。
四、Wails 核心特性实战
1. Go 与前端通信(核心能力)
Wails 提供两种通信方式:前端调用 Go 方法、Go 主动通知前端。
(1)前端调用 Go 方法(基础)
- Go 端:定义公开方法(首字母大写),参数/返回值需为 JSON 序列化类型(string/int/map/struct 等);
- 前端:通过
invoke("方法名", 参数1, 参数2)调用,返回 Promise。
(2)Go 主动发送消息给前端(事件)
适用于后端异步通知前端(如进度更新、状态变化):
// Go 端:发送事件(app.go)
func (a *App) StartTask() {
// 模拟异步任务,每秒发送进度给前端
go func() {
for i := 0; i <= 100; i += 10 {
time.Sleep(1 * time.Second)
// 发送事件:事件名 + 数据
a.ctx.EventEmitter.Emit("task-progress", i)
}
a.ctx.EventEmitter.Emit("task-progress", "完成")
}()
}
<!-- 前端:监听事件 -->
<script setup>
import { onMounted } from 'vue'
import { invoke, on } from '@wailsapp/runtime'
// 监听 Go 发送的 task-progress 事件
onMounted(() => {
on("task-progress", (progress) => {
console.log("任务进度:", progress)
// 更新 UI 显示进度
})
})
// 启动任务(调用 Go 方法)
const startTask = () => {
invoke("StartTask")
}
</script>
2. 系统对话框(文件选择/消息提示)
Wails 内置系统对话框 API,无需前端模拟:
// Go 端:打开文件选择对话框(app.go)
import (
"github.com/wailsapp/wails/v2/pkg/runtime"
)
func (a *App) OpenFileDialog() (string, error) {
// 调用系统文件选择对话框
filePath, err := runtime.OpenFileDialog(a.ctx, runtime.OpenDialogOptions{
Title: "选择文件",
Filters: []runtime.FileFilter{
{
DisplayName: "文本文件 (*.txt)",
Pattern: "*.txt",
},
{
DisplayName: "所有文件 (*.*)",
Pattern: "*.*",
},
},
})
return filePath, err
}
<!-- 前端调用 -->
const openFile = async () => {
const filePath = await invoke("OpenFileDialog")
console.log("选择的文件:", filePath)
}
3. 窗口控制(大小/位置/全屏)
通过 runtime 包控制窗口行为:
// Go 端:窗口控制(app.go)
import (
"github.com/wailsapp/wails/v2/pkg/runtime"
)
// 最大化窗口
func (a *App) MaximizeWindow() {
runtime.WindowMaximise(a.ctx)
}
// 最小化窗口
func (a *App) MinimizeWindow() {
runtime.WindowMinimise(a.ctx)
}
// 关闭窗口
func (a *App) CloseWindow() {
runtime.Quit(a.ctx)
}
4. 访问系统资源(文件/网络)
直接使用 Go 生态的库访问系统资源,例如读写文件:
// Go 端:读写文件(app.go)
import (
"os"
"fmt"
)
// 写入文件
func (a *App) WriteFile(path string, content string) error {
err := os.WriteFile(path, []byte(content), 0644)
if err != nil {
return fmt.Errorf("写入文件失败:%v", err)
}
return nil
}
// 读取文件
func (a *App) ReadFile(path string) (string, error) {
data, err := os.ReadFile(path)
if err != nil {
return "", fmt.Errorf("读取文件失败:%v", err)
}
return string(data), nil
}
5. 打包静态资源(前端)
开发完成后,前端代码需打包为静态资源,嵌入到 Go 程序中:
# 前端打包(自动执行,也可手动)
cd frontend && npm run build
# Go 端通过 //go:embed 嵌入静态资源(main.go 中已配置)
五、打包发布
1. 基础打包
# 进入项目目录
cd mywailsapp
# 打包为可执行文件(自动适配当前系统)
wails build
打包完成后,可执行文件位于 build/bin/ 目录下(Windows 为 .exe,macOS 为 .app,Linux 为可执行文件)。
