Wails2 系列 08:跨平台能力:托盘、开机启动、窗口材质和条件编译
cbowen

适合读者

适合准备把 Wails 应用发布到多个桌面平台,并开始处理平台差异的开发者。

问题场景

桌面应用一旦跨平台,就会遇到很多差异:托盘行为不一样,开机启动实现不一样,窗口材质不一样,通知权限不一样,文件路径和系统 API 也不一样。

最直接的写法是在业务服务里判断:

1
2
3
4
5
if runtime.GOOS == "windows" {
// Windows logic
} else if runtime.GOOS == "darwin" {
// macOS logic
}

少量判断没问题,但如果每个服务都这么写,平台细节就会渗透到整个项目。

项目观察

当前项目中有几个值得观察的平台文件组:

  • internal/app/systray_*:不同平台的托盘实现。
  • internal/service/app/autostart_*:不同平台的开机启动实现。
  • internal/service/app/material_*:窗口材质能力按平台拆分。
  • internal/service/app/os_info_*:系统信息能力按平台拆分。

这些文件对外提供相近方法,对内使用不同平台实现。

拆分原则

跨平台结构的目标是:业务层调用稳定接口,平台层隐藏差异。

可以优先使用 Go 的平台文件命名:

1
2
3
4
autostart_darwin.go
autostart_windows.go
autostart_linux.go
autostart_other.go

它们可以暴露同一个方法:

1
func EnableAutoStart() error

业务服务不需要知道注册表、LaunchAgent 或 desktop 文件分别怎么写。

同时,也可以保留少量高层平台判断。比如窗口关闭时,不同平台用户习惯确实不同,这类产品行为判断可以放在应用服务中。但底层系统 API 细节应尽量下沉。

改造示例

不推荐这样散落平台细节:

1
2
3
4
5
6
7
8
9
10
11
func (s *SettingsService) EnableAutoStart() error {
switch runtime.GOOS {
case "windows":
// write registry
case "darwin":
// call mac API
case "linux":
// write desktop file
}
return nil
}

可以定义稳定接口:

1
2
3
4
5
type AutoStartManager interface {
Enable() error
Disable() error
IsEnabled() bool
}

或者使用平台文件提供同名函数:

1
2
3
func (s *SettingsService) EnableAutoStart() error {
return platform.EnableAutoStart()
}

目录上保持差异集中:

1
2
3
4
5
internal/platform/autostart/
├── autostart_darwin.go
├── autostart_windows.go
├── autostart_linux.go
└── autostart_other.go

业务服务只表达“启用开机启动”,具体怎么启用由平台实现决定。

检查清单

  • 平台 API 细节是否集中在平台文件中?
  • 业务服务是否避免大量 runtime.GOOS 判断?
  • 不同平台实现是否对外提供一致方法?
  • 不支持的平台是否有明确 fallback?
  • 文件命名是否利用了 Go 的平台后缀?
  • 平台能力是否可以单独阅读和维护?
  • 新增平台差异时,是否知道应该增加哪个平台文件?

下一篇

下一篇会收束到发布链路:一个结构清晰的 Wails 项目,不只开发时清楚,也应该让构建、版本和发布流程清楚。

 评论
评论插件加载失败
正在加载评论插件