fix: Windows 桌面应用打包问题修复
- 删除通用 desktop target,重命名 platform targets 为简短形式 (desktop-mac/win/linux)
- 构建产物文件名统一为 nex-{os}-{arch}[.exe] 格式
- Windows 托盘图标使用 .ico 格式(运行时按平台选择)
- Windows 原生对话框使用 user32.MessageBoxW 替代 msg * 命令
- 更新 README.md 和 package-macos.sh 中的引用
- 添加单元测试覆盖 MessageBoxW 封装和图标选择逻辑
- 同步更新 desktop-app spec 规范文档
This commit is contained in:
33
backend/cmd/desktop/icon_test.go
Normal file
33
backend/cmd/desktop/icon_test.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"nex/embedfs"
|
||||
)
|
||||
|
||||
func TestIconSelection_Windows(t *testing.T) {
|
||||
if runtime.GOOS != "windows" {
|
||||
t.Skip("图标格式选择测试仅在 Windows 上运行")
|
||||
}
|
||||
|
||||
if err := testIconLoad("assets/icon.ico"); err != nil {
|
||||
t.Fatalf("Windows 应加载 .ico 文件: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIconSelection_NonWindows(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("图标格式选择测试在非 Windows 平台运行")
|
||||
}
|
||||
|
||||
if err := testIconLoad("assets/icon.png"); err != nil {
|
||||
t.Fatalf("非 Windows 平台应加载 .png 文件: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func testIconLoad(path string) error {
|
||||
_, err := embedfs.Assets.ReadFile(path)
|
||||
return err
|
||||
}
|
||||
@@ -12,7 +12,9 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/getlantern/systray"
|
||||
@@ -329,7 +331,13 @@ func setupStaticFiles(r *gin.Engine) {
|
||||
|
||||
func setupSystray(port int) {
|
||||
systray.Run(func() {
|
||||
icon, err := embedfs.Assets.ReadFile("assets/icon.png")
|
||||
var icon []byte
|
||||
var err error
|
||||
if runtime.GOOS == "windows" {
|
||||
icon, err = embedfs.Assets.ReadFile("assets/icon.ico")
|
||||
} else {
|
||||
icon, err = embedfs.Assets.ReadFile("assets/icon.png")
|
||||
}
|
||||
if err != nil {
|
||||
zapLogger.Error("无法加载托盘图标", zap.String("error", err.Error()))
|
||||
}
|
||||
@@ -446,7 +454,7 @@ func showError(title, message string) {
|
||||
script := fmt.Sprintf(`display dialog "%s" buttons {"OK"} default button "OK" with title "%s"`, message, title)
|
||||
exec.Command("osascript", "-e", script).Run()
|
||||
case "windows":
|
||||
exec.Command("msg", "*", message).Run()
|
||||
messageBox(title, message, MB_ICONERROR)
|
||||
case "linux":
|
||||
exec.Command("zenity", "--error", fmt.Sprintf("--title=%s", title), fmt.Sprintf("--text=%s", message)).Run()
|
||||
}
|
||||
@@ -459,8 +467,29 @@ func showAbout() {
|
||||
script := fmt.Sprintf(`display dialog "%s" buttons {"OK"} default button "OK" with title "关于 Nex Gateway"`, message)
|
||||
exec.Command("osascript", "-e", script).Run()
|
||||
case "windows":
|
||||
exec.Command("msg", "*", message).Run()
|
||||
messageBox("关于 Nex Gateway", message, MB_ICONINFORMATION)
|
||||
case "linux":
|
||||
exec.Command("zenity", "--info", "--title=关于 Nex Gateway", fmt.Sprintf("--text=%s", message)).Run()
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
MB_ICONERROR = 0x10
|
||||
MB_ICONINFORMATION = 0x40
|
||||
)
|
||||
|
||||
var (
|
||||
user32 = syscall.NewLazyDLL("user32.dll")
|
||||
procMessageBoxW = user32.NewProc("MessageBoxW")
|
||||
)
|
||||
|
||||
func messageBox(title, message string, flags uint) {
|
||||
titlePtr, _ := syscall.UTF16PtrFromString(title)
|
||||
messagePtr, _ := syscall.UTF16PtrFromString(message)
|
||||
procMessageBoxW.Call(
|
||||
0,
|
||||
uintptr(unsafe.Pointer(messagePtr)),
|
||||
uintptr(unsafe.Pointer(titlePtr)),
|
||||
uintptr(flags),
|
||||
)
|
||||
}
|
||||
|
||||
30
backend/cmd/desktop/messagebox_test.go
Normal file
30
backend/cmd/desktop/messagebox_test.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMessageBoxW_WindowsOnly(t *testing.T) {
|
||||
if runtime.GOOS != "windows" {
|
||||
t.Skip("MessageBoxW 仅在 Windows 上测试")
|
||||
}
|
||||
|
||||
messageBox("测试标题", "测试消息", MB_ICONINFORMATION)
|
||||
}
|
||||
|
||||
func TestShowError_WindowsBranch(t *testing.T) {
|
||||
if runtime.GOOS != "windows" {
|
||||
t.Skip("Windows 原生对话框测试仅在 Windows 上运行")
|
||||
}
|
||||
|
||||
showError("测试错误", "这是一条测试错误消息")
|
||||
}
|
||||
|
||||
func TestShowAbout_WindowsBranch(t *testing.T) {
|
||||
if runtime.GOOS != "windows" {
|
||||
t.Skip("Windows 原生对话框测试仅在 Windows 上运行")
|
||||
}
|
||||
|
||||
showAbout()
|
||||
}
|
||||
Reference in New Issue
Block a user