Files
pangolin/docs/superpowers/specs/2026-06-21-windows-client-design.md
T
wangjia 5c9731f3df docs: Windows 客户端 bring-up + 安装包设计方案(spec)
brainstorming 定稿:真机测试 / MVP+Inno Setup 深度 / 子进程+UAC 数据面 /
复用 DesktopShell 原生标题栏 / 拉丁全量+Noto Sans SC 7000字子集打包。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 22:20:50 +08:00

9.8 KiB
Raw Blame History

Windows 客户端 bring-up + 安装包 — 设计方案

  • 日期:2026-06-21
  • 分支:feature/windows
  • 范围:把已写好但从未在真 Windows 上构建/运行的 Windows 客户端跑通端到端,并产出 Inno Setup 安装包。

1. 背景与现状

Windows 客户端的代码已基本就绪,但 client/windows/README.md 明确标注「未在真 Windows 机器上构建/验证过」(开发在 macOS)。本方案不是从零开发,而是 bring-up(真机构建跑通)+ productionization(安装包)

已存在且看起来正确的部分

组件 文件 状态
Dart 桥接层(含完整 Windows 分支) client/lib/bridge/desktop_vpn_bridge.dartkernel_process.dart 已写:wintun.dll 检查、%LOCALAPPDATA%\Pangolin\kernel 配置目录、.exe 解析、Process.kill 停止
平台分派 client/lib/bridge/vpn_bridge_provider.dart Windows → DesktopVpnBridge
Flutter runner 脚手架 client/windows/runner/main.cpp 已写,默认窗口 1280×720
UAC manifest client/windows/runner/runner.exe.manifest requireAdministrator(sing-box 子进程继承管理员权建 TUN)
CMake 打包内核 client/windows/CMakeLists.txt install 步骤把 sing-box.exe+wintun.dll 拷到 exe 同级
二进制拉取脚本 app/kernel/fetch-desktop-bin.sh windows amd64sing-box.exe + wintun 0.14.1SHA256 pin
UI / 页面 client/lib/shell/screens/widgets/ 跨平台,复用 desktop shell(见 §4
系统托盘 / 单实例 client/lib/system_tray.dart 跨平台,已声明支持 Windows

从未做的部分(本方案目标)

  • 在真 Windows 机器上 flutter build windows / flutter run
  • 端到端连通验证(登录→选节点→connect→出网 IP 为节点 IP)。
  • Inno Setup 安装包。

明确不做(本轮范围外)

  • 代码签名(EV/OV 证书)。
  • Windows CI job。
  • 免 UAC 的特权 helper 服务(类比 macOS SMJobBless)→ 列入 BACKLOG。
  • frameless 自定义标题栏 → 本轮用原生标题栏。

2. 决策记录(来自本次 brainstorming

  1. 测试环境:用户有实体 Windows 机器;Claude 在 macOS 改代码并给逐条 PowerShell 指令,用户真机执行并回贴日志,循环迭代。
  2. 深度MVP bring-up + Inno Setup 安装包。
  3. 数据面架构:沿用「整 app UAC 提权 + sing-box.exe 子进程继承管理员权 + wintun TUN 全局代理」的子进程方案(DesktopVpnBridge),改 native helper。
  4. UI:复用现有 DesktopShell,无 Windows 专属页面设计。
  5. 窗口标题栏:原生 Windows 标题栏(系统最小/最大/关闭按钮),app 内 ContentTopBar 位于其下。

3. 数据面架构(沿用既有)

Flutter app (pangolin_vpn.exe, requireAdministrator)
   └─ DesktopVpnBridge (Dart) ── 写 config_*.json → %LOCALAPPDATA%\Pangolin\kernel\
        └─ DesktopKernelProcess ── Process.start("sing-box.exe", run -c config)
              ├─ sing-box.exe ── 加载同目录 wintun.dll → 建 TUN → 全局代理
              └─ Clash API (127.0.0.1:随机端口) ← Dart 轮询状态/流量/切节点/kill-switch

与 macOS 的差异:macOS 走原生 System ExtensionkUseNativeVpnMacOS),Windows 本轮继续用子进程 + UAC。两者共用 DesktopVpnBridge 之外的所有上层(UI / 状态 / API)。

4. UI / 页面方案:复用 desktop shell,零新设计

core/responsive/form_factor.dart 按平台 + 窗口宽度判形态:Windows 为桌面平台,窗口宽 ≥680 → DesktopShell,与 macOS 桌面同一份代码、同一套设计 tokendesign/colors_and_type.css 单源)。

┌─ 原生标题栏 ───────────────── – □ × ┐
├─────────┬───────────────────────────┤
│ 侧栏 204 │ ContentTopBar (52, 标题/返回) │
│ 6 项导航 ├───────────────────────────┤
│ ·连接    │  内容区:Connect / Nodes /    │
│ ·节点    │  Stats / Account / Contact / │
│ ·统计    │  Settings(+账户下钻子页)      │
│ ·我的    │                             │
│ ·联系    │                             │
│ ·设置    │                             │
└─────────┴───────────────────────────┘

页面内容、配色、字体全部来自单源,Windows 不单独画页面。系统托盘 + 关闭即最小化 + 单实例锁已是跨平台代码。

本轮属于 Windows 的窗口层调整(小工作量,并入 Phase 1):

  • 窗口尺寸:默认 920×640,最小宽度 720(低于 680 会掉进 MobileShell 致侧栏消失)。在 system_tray.dartwindowManager.ensureInitialized() 后用 setMinimumSize / 默认尺寸设定,或在 main.cpp 调整初始尺寸并设最小尺寸。
  • 字体(决定:打包,全平台离线):放弃 google_fonts 运行时拉取,改本地打包 ttf,生产置 useBundled=true(影响全平台,顺带消除 macOS 联网拉字体隐患)。
    • 拉丁三件套全量变量字体:Sora ~0.3MB + Manrope ~0.15MB + JetBrains Mono ~0.2MB(合计 <1MB)。
    • Noto Sans SC 取 7000 字子集(通用规范汉字表,用 fonttools pyftsubset 生成)≈ 1.5–2.5MB,覆盖几乎全部 UI 文案 + 节点名。
    • fontFamilyFallback 兜到 Windows 自带微软雅黑(macOS 兜苹方),子集外生僻字不显示豆腐块。
    • 总增量 ≈ 2–3MB。落地:ttf 入 client/fonts/ → 恢复 pubspec.yamlfonts: 段(4 family)→ useBundled 改为生产默认 true → 主题设 fontFamilyFallback
  • 托盘/应用图标assets/tray_icon.png + app_icon.ico(已有),真机验证显示即可。
  • 标题栏:保持原生,不做 frameless。
  • DPImanifest 已 PerMonitorV2,真机验证高分屏不糊/不溢出。

5. 已识别的构建风险(真机迭代时盯)

  1. jni FFI 插件client/windows/flutter/generated_plugins.cmakeFLUTTER_FFI_PLUGIN_LISTjni,对 Windows 可疑,可能编译失败 → 先查来源(哪个依赖传递引入),必要时确认其 Windows 支持或移除该依赖。
  2. /WXwarnings as errors+ _HAS_EXCEPTIONS=0:插件源码有告警即 fail,可能需 per-target 放宽。
  3. 插件 Windows 兼容性tray_manager / window_manager / flutter_secure_storage_windows / screen_retriever_windows / launch_at_startup 在当前锁定版本下需能编过、运行正常。
  4. 内核二进制下载fetch-desktop-bin.sh 依赖 wintun.net 与 sing-box GitHub release 可达,国内网络可能需代理。
  5. path_provider 目录一致性:代码硬编码 %LOCALAPPDATA%\Pangolin\kernel,验证与运行时实际目录一致、可写。

6. 工作分解

Phase 1 — MVP bring-up(真机跑通端到端)

  1. macOS 侧预检Claude 可独立做):flutter pub getflutter analyzedart analyze 确认无编译期/分析错误;查 jni 来源,必要时从 Windows 插件列表处理。
  2. 窗口层调整:默认窗口尺寸 920×640 + 最小宽 720。
  3. 真机构建(用户执行,Claude 给指令):装 Flutter + Visual StudioC++ 桌面负载)→ app/kernel/fetch-desktop-bin.sh windows amd64 → 管理员终端 flutter build windows / flutter run -d windows --dart-define=PANGOLIN_API_URL=...
  4. 按报错迭代:用户贴 build/运行日志,Claude 改代码,循环到 build 通过。
  5. 端到端连通:登录 → 选节点 → connect → curl https://api.ipify.org 出口为节点公网 IP。
  6. 功能验证:停止、自动重连、kill-switch、托盘(关闭最小化/显示/退出)、开机自启、UAC 单次弹窗、退出时内核拆隧道无残留 TUN/孤儿进程。
  7. 字体打包(见 §4,全平台生效):拉丁三件套全量 + Noto Sans SC 7000 字子集(pyftsubset)入 client/fonts/,恢复 pubspec fonts: 段,生产置 useBundled=true,主题设 fontFamilyFallbackWindows 微软雅黑 / macOS 苹方)。增量 ≈ 2–3MB。

Phase 2 — Inno Setup 安装包

  1. client/windows/installer/pangolin.iss
    • 源:build\windows\x64\runner\Release\(含 pangolin_vpn.exe + Flutter 运行时 + sing-box.exe + wintun.dll + data\)。
    • 装到 Program Files\Pangolin
    • 开始菜单 + 桌面快捷方式(启动项继承 exe 的 requireAdministrator)。
    • 卸载清理 %LOCALAPPDATA%\Pangolin
  2. 文档化:更新 client/windows/README.md 增加打包/出安装包步骤。

打包方案选型

  • A) Inno Setup(采纳):免费、脚本化、最主流,与「含安装包」一致。
  • B) MSIX:与 requireAdministrator 沙箱冲突,不合适。
  • C) 绿色 zip:无开始菜单/卸载,不满足需求。

7. 协作模式

  • Claude 无法在 macOS 构建 Windows:所有真机步骤提供逐条可复制的 PowerShell 指令;用户回贴报错/日志 → Claude 改代码 → 循环。
  • 主要不确定性是插件 Windows 编译兼容性(尤其 jni),可能需数轮迭代。

8. 验收标准

  • flutter build windowsRelease)在真机成功,无报错。
  • 运行后单次 UAC 提权,主界面为 DesktopShell(原生标题栏 + 侧栏 + 内容区),无布局溢出。
  • 登录 → 选节点 → connect 成功,curl https://api.ipify.org 返回节点公网 IP。
  • 停止 / 重连 / kill-switch / 托盘最小化与退出 / 开机自启均正常;退出无残留 TUN 适配器与孤儿 sing-box 进程。
  • Inno Setup 安装包可安装、生成快捷方式、运行、卸载干净。