d80e9e1357
leo 08-05:「Windows 版一定要重編,因為我只有 Mac,我需要人家測試,
要做到最完善不要給人家找麻煩,然後當測試者給我截圖安裝成功就要提交 ms store」
## 缺口
Windows 打包腳本全在**舊的 arcrun-tray(fyne 版)**,
新的 arcrun-app(Wails,t193/t194 整批 UI 重做)**完全沒有 Windows 產線**
⇒ Windows 封測者只能拿到 v0.15.7 的舊 fyne 版。
## 新增
· tray_windows.go — Windows 系統匣(energye/systray)
行為與 macOS 版逐項對齊:左鍵開視窗/右鍵只有「結束 Arcrun」/關窗不結束。
⚠️ 為什麼 Windows 能用 systray 而 macOS 不能(wiki 有全文):
macOS 上它在 Wails 之下根本不建托盤(setInternalLoop 只在 systray.Run() 呼叫),
改用 systray.Run() 又搶 macOS 主 loop ⇒ macOS 最後走原生 NSStatusItem。
**Windows 走 Win32 訊息迴圈,沒有主執行緒限制**,所以這裡用 systray 是對的,
不是抄 macOS 失敗的做法。
trayApp 與 ICO 都在本檔自帶(tray_darwin.go 有 //go:build darwin,Windows 看不到)。
· build-win.sh — 交叉編譯 zip(CGO_ENABLED=1 + mingw-w64,Wails Windows 要 WebView2 綁定)
**同綑 collector.exe**:daemon 本體是 collector direct,沒同綑=裝了不會同步
(t194 在 Mac 版就漏過一次)。supervise.go 的 collectorBinPath() 已處理 .exe 副檔名。
· build-msix.sh — MS Store 用的 msix(沿用 makemsix,Mac 上就打得出來)
與舊 fyne 版差別:**Wails 是兩個 exe**,兩個都要進 msix root。
Identity 三值走環境變數(要與 Partner Center 完全一致),預設佔位並印警告。
## 驗
· Windows zip:兩個檔都是正牌 PE(MZ 標頭)/Arcrun.exe 11.4MB+collector.exe 16.1MB
· 退避修復確實編進 Windows 版(不剝符號重編一份,grep 到 MarkFailed/ShouldRetry/
retrySkipReason 各 2 處;出貨版用 -s -w 剝符號故查不到,屬預期)
· MSIX:16 檔、含 AppxBlockMap;zip 回讀兩個 exe 的 sha256 與原檔**逐一相符**;
manifest Executable="Arcrun.exe"、Version=0.18.4.0
· **macOS 版不受影響**:編譯通過、三支機械閘全過
## 兩個踩到的坑(已修)
· zip 用相對路徑在 cd 後失效(zip I/O error,fallback 湊巧成功但不可靠)⇒ 改絕對路徑
· 全形括號緊接變數會被當成變數名(腳本自己的註解就警告過)⇒ 改 ${VAR}
## 殘項
· Identity 仍是 PLACEHOLDER ⇒ **這顆 msix 還不能送 Store**,等 leo 給 Partner Center 三值
· 未在真 Windows 上跑過(誠實界定:只證明編得出來,不證明跑起來對)
73 lines
2.7 KiB
Go
73 lines
2.7 KiB
Go
//go:build windows
|
||
|
||
package main
|
||
|
||
// tray_windows.go — Windows 系統匣(t196,2026-08-05)
|
||
//
|
||
// 為什麼 Windows 用 energye/systray 而 macOS 不用(wiki mistakes 有全文):
|
||
// macOS 上 systray 在 Wails 之下**根本不會建立托盤**——`setInternalLoop(true)` 只在
|
||
// `systray.Run()` 裡呼叫,走 `RunWithExternalLoop` 時 `registerSystray()` 第一行就 return;
|
||
// 而改用 `systray.Run()` 又會與 Wails 搶 macOS 主 loop(SIGTRAP)。
|
||
// ⇒ macOS 最後改走原生 `NSStatusItem`(tray_darwin.m)。
|
||
//
|
||
// **Windows 沒有這個限制**:托盤走 Win32 訊息迴圈(自己的 goroutine 就能跑),
|
||
// 不像 macOS 的 NSStatusItem 硬性要求主執行緒。所以這裡用 systray 是合適的,
|
||
// 不是「抄 macOS 失敗的做法」。
|
||
//
|
||
// 行為與 macOS 版**逐項對齊**(tray_darwin.go/.m):
|
||
// · 左鍵點 icon → 直接開視窗(不彈選單)
|
||
// · 右鍵 → 只有「結束 Arcrun」一項
|
||
// · 關視窗 → 隱藏不結束(daemon 常駐;在 app.go 的 OnBeforeClose 處理)
|
||
|
||
import (
|
||
_ "embed"
|
||
|
||
"github.com/energye/systray"
|
||
)
|
||
|
||
// trayApp 讓回呼找得到 App(與 tray_darwin.go 同名同用途;
|
||
// 該檔有 //go:build darwin,Windows 編譯時不存在,故這裡自帶一份)。
|
||
var trayApp *App
|
||
|
||
// Windows 系統匣要 .ico(PNG 會顯示成空白/方塊)。
|
||
// build/windows/icon.ico 是 Wails 產生 exe 圖示用的同一顆,一併拿來當托盤圖。
|
||
//
|
||
//go:embed build/windows/icon.ico
|
||
var trayIconICO []byte
|
||
|
||
// setupTray 建立系統匣圖示。
|
||
//
|
||
// 與 macOS 版的介面契約相同(main.go 只呼叫 setupTray(app)),
|
||
// 但這裡**不阻塞**:systray 自己開 goroutine 跑訊息迴圈,Wails 主迴圈不受影響。
|
||
func setupTray(app *App) {
|
||
trayApp = app
|
||
// RunWithExternalLoop 回傳 start/end;Windows 下 start 不阻塞。
|
||
trayStart, trayEnd = systray.RunWithExternalLoop(func() {
|
||
systray.SetIcon(trayIconICO)
|
||
systray.SetTitle("Arcrun")
|
||
systray.SetTooltip("Arcrun — 你的知識庫同步小幫手")
|
||
|
||
// 🔴 右鍵選單:**只有結束**(leo 08-05:「依照 google drive,托盤裡只剩下
|
||
// 按右鍵會結束,其他設定都在這個頁面」)。
|
||
quit := systray.AddMenuItem("結束 Arcrun", "結束 Arcrun(同步會停止)")
|
||
quit.Click(func() {
|
||
if trayApp != nil {
|
||
trayApp.Quit()
|
||
}
|
||
})
|
||
|
||
// 左鍵=直接開視窗,不彈選單(Google Drive 式)。
|
||
systray.SetOnClick(func(menu systray.IMenu) {
|
||
if trayApp != nil {
|
||
trayApp.ShowWindow()
|
||
}
|
||
})
|
||
// 右鍵才顯示選單。
|
||
systray.SetOnRClick(func(menu systray.IMenu) {
|
||
if menu != nil {
|
||
_ = menu.ShowMenu()
|
||
}
|
||
})
|
||
}, func() {})
|
||
}
|