首页 / Wails 入门教程 / Linux 打包与发行

Wails 入门教程

Linux 打包与发行

本教程共 42 篇 · 第 36 篇 · 更新于 2026-08-03

Wails桌面开发LinuxWebKit2GTKnfpmAppImage

36. Linux 打包与发行

本节目标

  • 知道 Linux 产物依赖哪些系统库,为什么不能「拷过去就跑」
  • 分清 WebKit2GTK 的 4.0 和 4.1 两个 ABI,会用构建标签选对
  • 查得到主流发行版的运行时依赖包名
  • 会用 nfpm 打出 deb 和 rpm,会写 .desktop 桌面入口
  • 认识几个 Linux 独有的运行期坑并知道怎么绕

36-1 产物很朴素,依赖不简单

Linux 上 wails build 出来的就是一个可执行文件,没有扩展名,chmod +x 之后直接跑。

但它不是静态链接的自足程序。运行时需要系统上有这两组库:

  • GTK3 —— 窗口、菜单等原生控件
  • WebKit2GTK —— 渲染前端页面的 WebView

缺任何一个,程序启动就报找不到 so 文件。这就是 Linux 分发跟 Windows、macOS 最大的区别:那两个平台的 WebView 要么系统自带、要么能打包进去,Linux 这边只能声明依赖,让包管理器去解决。

开发机上装的是 -dev 结尾的开发包(编译时需要头文件),用户机器上只需要运行时包。两者包名不同,别搞混。

36-2 WebKit2GTK 的两个 ABI 版本

这是 Linux 打包最容易翻车的地方。WebKit2GTK 有两条并行的 ABI 线:

  • 4.1 —— 现代版本,多数当前发行版在用
  • 4.0 —— 旧版本,Debian 11、Ubuntu 20.04、RHEL 系 8/9 上只有这个

两者二进制不兼容。用 4.1 编出来的程序,在只有 4.0 的机器上跑不起来。

Wails 通过构建标签让你选:

# 面向 ABI 4.1 的发行版
wails build -tags webkit2_41

# 面向 ABI 4.0 的发行版(RHEL 系、老 Debian/Ubuntu)
wails build -tags webkit2_40
Warning

一份产物无法同时覆盖两条 ABI 线。要都支持,就得编两个版本分开发布,包名上带清楚区分,比如 myapp_1.2.0_amd64_webkit41.deb

也可以把标签固化进 wails.json,省得每次敲:

{
  "build:tags": "webkit2_41"
}

36-3 各发行版的运行时依赖速查

用户机器上要装什么,按发行版查这张表:

发行版GTK3 包名WebKit2GTK 包名ABI安装命令
Debian 12 / Ubuntu 22.04+libgtk-3-0libwebkit2gtk-4.1-04.1apt install libgtk-3-0 libwebkit2gtk-4.1-0
Debian 11 / Ubuntu 20.04libgtk-3-0libwebkit2gtk-4.0-374.0apt install libgtk-3-0 libwebkit2gtk-4.0-37
Fedora 40+gtk3webkit2gtk4.14.1dnf install gtk3 webkit2gtk4.1
RHEL / CentOS / AlmaLinux / Rocky 8-9gtk3webkit2gtk34.0dnf install gtk3 webkit2gtk3
openSUSE Leap / Tumbleweedlibgtk-3-0libwebkit2gtk-4_1-04.1zypper install libgtk-3-0 libwebkit2gtk-4_1-0
Arch Linux / Manjarogtk3webkit2gtk-4.14.1pacman -S gtk3 webkit2gtk-4.1

几处容易记混的:

  • openSUSE 4.0 和 4.1 都提供,包名里的分隔符是下划线(4_1)不是点
  • Fedora 从 40 才有 webkit2gtk4.1,更早的版本只能用 4.0
  • RHEL 系那个叫 webkit2gtk3 的包,对应的其实是 ABI 4.0,名字有迷惑性
  • Arch 上 webkit2gtk 是 4.0,webkit2gtk-4.1 才是 4.1
Tip

不确定目标机器上装的是哪个版本,让用户跑一条 pkg-config --list-all | grep webkit 或者 ldconfig -p | grep webkit2gtk,一眼就看出来了。

36-4 Wails 怎么探测你的包管理器

wails doctor 在 Linux 上能报出「缺哪个包、用什么命令装」,靠的是内置的包管理器适配。目前支持这几种:

aptdnfemergeeopkgnixpkgspacmanxbpszypper

它的工作方式是:识别当前系统用哪个包管理器,然后拿一份候选包名列表去查询。以 apt 为例,libgtk-3 这个依赖对应的候选名是 libgtk-3-dev

如果你用的是某个 Ubuntu 衍生版,包名被改过,wails doctor 可能报「找不到」。这不影响构建,手动装上对应的包就行。想彻底解决,可以给 Wails 仓库提 PR,在对应包管理器的候选列表里加一个名字。

36-5 用 nfpm 打 deb 和 rpm

裸二进制可以发,但用户得自己解决依赖、自己创建桌面快捷方式。做成系统包体验会好很多。

nfpm 是个不错的选择——一份 YAML 配置同时产出 deb、rpm、apk 等格式,不需要在对应发行版上跑。

针对 ABI 4.1 的配置:

name: myapp
arch: amd64
version: 1.2.0
maintainer: 码上学 <me@example.com>
description: My Wails application
license: MIT

depends:
  - libgtk-3-0
  - libwebkit2gtk-4.1-0

overrides:
  rpm:
    depends:
      - libgtk-3-0
      - libwebkit2gtk-4_1-0
  archlinux:
    depends:
      - gtk3
      - webkit2gtk-4.1

contents:
  - src: ./build/bin/myapp
    dst: /usr/bin/myapp
  - src: ./packaging/myapp.desktop
    dst: /usr/share/applications/myapp.desktop
  - src: ./build/appicon.png
    dst: /usr/share/icons/hicolor/512x512/apps/myapp.png

针对 ABI 4.0(RHEL 系和老 Debian/Ubuntu):

depends:
  - gtk3
  - webkit2gtk3

overrides:
  deb:
    depends:
      - libgtk-3-0
      - libwebkit2gtk-4.0-37
  archlinux:
    depends:
      - gtk3
      - webkit2gtk

Fedora 40+ 单独一份:

depends:
  - gtk3
  - webkit2gtk4.1

打包命令:

nfpm package -f nfpm-webkit41.yaml -p deb -t ./dist/
nfpm package -f nfpm-webkit41.yaml -p rpm -t ./dist/
Note

要同时支持两条 ABI 线,就准备两份 nfpm 配置文件,配合两次不同 -tags 的构建。这是官方给的建议,没有更取巧的办法。

36-6 桌面入口文件

装进 /usr/bin 的程序在应用菜单里是看不到的,得配一个 .desktop 文件。放在 packaging/myapp.desktop

[Desktop Entry]
Type=Application
Name=My App
Comment=用 Wails 构建的桌面应用
Exec=/usr/bin/myapp
Icon=myapp
Terminal=false
Categories=Utility;
StartupWMClass=myapp

Icon 的值是图标文件名(不带扩展名),系统会去 /usr/share/icons/hicolor/ 下按尺寸找。StartupWMClass 影响任务栏图标能否正确关联,不写的话可能出现「打开后任务栏显示的是默认图标」。

36-7 AppImage 与其他分发形式

想要一个「下载即用、不装依赖」的单文件,AppImage 是常见选择。它把应用和依赖的库一起塞进一个可执行镜像。

Wails 本身不生成 AppImage,需要借助 linuxdeployappimagetool 这类工具。大致流程是:搭一个 AppDir 目录结构(放二进制、desktop 文件、图标),让工具把依赖的 so 收集进去,最后打包成 .AppImage

Warning

把 WebKit2GTK 打进 AppImage 会让体积飙到上百 MB,而且 WebKit 对系统的 GStreamer、字体配置有隐式依赖,容易出现「在打包机上好好的,换台机器就崩」。真要走这条路,务必在多个发行版上实测。

其他路径还有 Flatpak 和 Snap,它们的沙盒机制能比较好地隔离依赖,但配置复杂度更高。对多数项目来说,deb + rpm 覆盖主流用户已经够了。

36-8 Linux 独有的几个坑

音视频元素报 GStreamer 错误

页面里用了 <audio><video>,控制台冒出:

GStreamer element autoaudiosink not found. Please install it

装上 GStreamer 的 good 插件集就行:

# Arch
pacman -S gst-plugins-good
# Debian / Ubuntu
apt-get install gstreamer1.0-plugins-good
# Fedora
dnf install gstreamer1-plugins-good

这是 WebKitGTK 的上游问题,Arch 系遇到的频率更高。打包时记得把这个包也加进 depends

video 标签不触发 ended 事件

同样是 WebKitGTK 的 bug。视频播完不派发 ended,前端逻辑就卡住了。绕过办法是自己监听进度手动派发:

videoTag.addEventListener("timeupdate", (event) => {
  const target = event.target as HTMLVideoElement;
  if (target.duration - target.currentTime < 0.2) {
    target.dispatchEvent(new Event("ended"));
  }
});

panic 恢复失效

Linux 上偶尔会看到这样的崩溃:

signal 11 received but handler not on signal stack
fatal error: non-Go code set up signal handler without SA_ONSTACK flag

原因是 WebKit 注册了自己的信号处理器,没带 SA_ONSTACK 标志,导致 Go 无法把 SIGSEGV 之类的信号转成可恢复的 panic。

Wails 提供了一个运行时函数来修复:

import "github.com/wailsapp/wails/v2/pkg/runtime"

go func() {
	defer func() {
		if err := recover(); err != nil {
			log.Printf("Recovered from panic: %v", err)
		}
	}()

	// 紧挨着可能 panic 的代码之前调用
	runtime.ResetSignalHandlers()

	// 你的业务逻辑……
}()
Note

三条使用规则:每个需要 panic 恢复的 goroutine 里都要调一次;要紧挨着危险代码之前调,因为 WebKit 随时可能重新设置处理器;这个函数在非 Linux 平台上是空操作,跨平台代码里可以直接写,不用加条件编译。

NixOS 上 font-size 不生效

NixOS 配合 Wayland 时,CSS 的 font-size 可能完全不起作用。在 devShell 里补上环境变量:

shellHook = with pkgs; ''
  export XDG_DATA_DIRS=${gsettings-desktop-schemas}/share/gsettings-schemas/${gsettings-desktop-schemas.name}:${gtk3}/share/gsettings-schemas/${gtk3.name}:$XDG_DATA_DIRS;
  export GIO_MODULE_DIR="${pkgs.glib-networking}/lib/gio/modules/";
'';

常见误区

在 Ubuntu 22.04 上编,拿到 CentOS 8 上跑。 ABI 对不上,必然失败。先确认目标环境的 WebKit 版本再选构建标签。

deb 包里忘了写 depends。 用户装上之后一运行报缺库,还得自己排查。依赖一定要在包元数据里声明清楚。

只测了自己那台机器。 Linux 的碎片化是真实存在的。至少覆盖 Debian 系和 RHEL 系各一个版本。

把开发包当运行时依赖写进 depends。 libwebkit2gtk-4.1-dev 是编译用的,用户只需要 libwebkit2gtk-4.1-0。写成 dev 包会让用户白装一堆头文件。

小结

Linux 分发的核心难点是依赖管理,不是打包本身。搞清楚目标发行版用哪条 WebKit ABI,选对 -tags,在包里声明准确的运行时依赖,事情就成了一大半。

nfpm 是性价比高的工具,一份配置产出多种格式。要覆盖两条 ABI 线,准备两份配置两次构建。

.desktop 文件别漏,它决定了应用能不能出现在系统菜单里。

Linux 独有的几个坑——GStreamer 插件、video 的 ended 事件、信号处理器冲突——都有现成解法,遇到了对照本节处理即可。

下一章换个话题,聊聊怎么给 Go 代码做混淆,给业务逻辑加一层保护。