跳到主要内容

go wails 如何开发桌面程序

· 阅读需 9 分钟
ahKevinXy
作者

Wails 是一款基于 Go 语言的跨平台桌面应用开发框架,核心优势是用 Go 编写后端逻辑 + 前端技术(HTML/CSS/JS/Vue/React)编写 UI,无需打包完整浏览器内核(如 Electron),生成的程序体积更小(MB 级)、启动更快、资源占用更低。

本文将从环境搭建、项目创建、核心特性、实战开发、打包发布五个维度,手把手教你用 Wails 开发桌面程序。

一、Wails 核心优势(对比 Electron)

特性WailsElectron
程序体积小(5-20MB)大(100+MB)
启动速度快(毫秒级)慢(秒级)
内存占用低(几十MB)高(几百MB)
开发语言Go + 前端(任意框架)JS/TS + 前端
跨平台Windows/macOS/Linux同左
系统集成深度集成 Go 生态需通过 Node 插件集成
打包方式静态编译打包 ASAR 资源

二、环境搭建

1. 基础依赖

Wails 依赖 Go 环境和前端构建工具,需先安装:

(1)安装 Go

(2)安装前端依赖(Node.js + npm/yarn/pnpm)

(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 为可执行文件)。

2. 自定义打包配置(wails.json)

修改 wails.json 可配置窗口图标、程序名称、打包方式等:

{
"name": "mywailsapp",
"outputfilename": "MyWailsApp",
"frontend:install": "npm install",
"frontend:build": "npm run build",
"app:icon": "assets/icon.png", // 窗口图标(支持 PNG/ICO/ICNS)
"app:title": "我的 Wails 应用",
"app:width": 800,
"app:height": 600,
"windows": {
"Webview2": "embed", // 嵌入 WebView2 运行时(Windows 无需额外安装)
"disableconsole": true, // 关闭控制台窗口(仅 GUI)
"productversion": "1.0.0",
"fileversion": "1.0.0"
},
"macos": {
"category": "Utility",
"sign": false,
"package": "dmg" // 打包为 DMG 镜像
},
"linux": {
"package": "deb" // 打包为 DEB 包(Ubuntu/Debian)
}
}

3. 跨平台打包

Wails 支持交叉编译(需安装对应系统的编译依赖):

# Windows 打包 macOS 程序(需安装 macOS 交叉编译工具)
GOOS=darwin GOARCH=amd64 wails build

# Linux 打包 Windows 程序
GOOS=windows GOARCH=amd64 wails build

六、最佳实践与优化

1. 性能优化

  • 禁用调试模式:打包时添加 -prod 参数,关闭调试日志;
  • 压缩前端资源:前端打包时开启 Gzip/Brotli 压缩;
  • 减少内存占用:避免 Go 端创建大量临时对象,及时释放资源。

2. 开发效率提升

  • 热更新:开发时使用 wails dev,前端/Go 代码修改后自动刷新;
  • 前端调试:打开 http://localhost:34115 可在浏览器中调试前端代码;
  • Go 调试:使用 GoLand/VS Code 调试 Wails 程序(配置断点即可)。

3. 常见问题解决

(1)Windows 打包后运行提示缺少 WebView2

(2)macOS 程序无法打开(提示“无法验证开发者”)

  • 解决方案:右键程序 → 打开 → 确认打开(仅首次);
  • 或签名程序(需 Apple 开发者账号)。

(3)前端调用 Go 方法返回 undefined

  • 检查 Go 方法名首字母是否大写;
  • 检查参数类型是否匹配(如前端传 number,Go 端用 int 接收);
  • 查看终端日志,Go 端是否有报错。

七、总结

  1. 核心流程
    • 环境搭建:安装 Go + Node.js + Wails CLI;
    • 项目创建:wails init 选择模板(Vue/React);
    • 开发:Go 写后端逻辑,前端写 UI,通过 invoke/事件实现通信;
    • 打包:wails build 生成跨平台可执行文件。
  2. 核心优势:体积小、启动快、深度集成 Go 生态,适合需要高性能、轻量的桌面程序;
  3. 适用场景:工具类软件、数据可视化程序、本地服务客户端(如数据库管理工具);
  4. 最佳实践:利用 Go 生态处理核心逻辑,前端专注 UI,合理使用事件通信实现异步更新。

Wails 完美结合了 Go 的高性能和前端的易用性,是替代 Electron 开发轻量级桌面程序的最佳选择之一。