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

136 lines
9.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.dart``kernel_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 amd64`sing-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 Extension`kUseNativeVpnMacOS`),Windows 本轮继续用子进程 + UAC。两者共用 `DesktopVpnBridge` 之外的所有上层(UI / 状态 / API)。
## 4. UI / 页面方案:复用 desktop shell,零新设计
`core/responsive/form_factor.dart` 按平台 + 窗口宽度判形态:Windows 为桌面平台,窗口宽 ≥680 → `DesktopShell`,与 macOS 桌面**同一份代码、同一套设计 token**(`design/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.dart``windowManager.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.yaml``fonts:` 段(4 family)→ `useBundled` 改为生产默认 true → 主题设 `fontFamilyFallback`
- **托盘/应用图标**`assets/tray_icon.png` + `app_icon.ico`(已有),真机验证显示即可。
- **标题栏**:保持原生,不做 frameless。
- **DPI**manifest 已 PerMonitorV2,真机验证高分屏不糊/不溢出。
## 5. 已识别的构建风险(真机迭代时盯)
1. **`jni` FFI 插件**`client/windows/flutter/generated_plugins.cmake``FLUTTER_FFI_PLUGIN_LIST``jni`,对 Windows 可疑,可能编译失败 → 先查来源(哪个依赖传递引入),必要时确认其 Windows 支持或移除该依赖。
2. **`/WX`warnings 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 get``flutter analyze``dart 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`,主题设 `fontFamilyFallback`Windows 微软雅黑 / macOS 苹方)。增量 ≈ 23MB。
### Phase 2 — Inno Setup 安装包
8.`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`
9. 文档化:更新 `client/windows/README.md` 增加打包/出安装包步骤。
### 打包方案选型
- **A) Inno Setup**(采纳):免费、脚本化、最主流,与「含安装包」一致。
- B) MSIX:与 `requireAdministrator` 沙箱冲突,不合适。
- C) 绿色 zip:无开始菜单/卸载,不满足需求。
## 7. 协作模式
- Claude 无法在 macOS 构建 Windows:所有真机步骤提供逐条可复制的 PowerShell 指令;用户回贴报错/日志 → Claude 改代码 → 循环。
- 主要不确定性是插件 Windows 编译兼容性(尤其 `jni`),可能需数轮迭代。
## 8. 验收标准
- [ ] `flutter build windows`(Release)在真机成功,无报错。
- [ ] 运行后单次 UAC 提权,主界面为 `DesktopShell`(原生标题栏 + 侧栏 + 内容区),无布局溢出。
- [ ] 登录 → 选节点 → connect 成功,`curl https://api.ipify.org` 返回节点公网 IP。
- [ ] 停止 / 重连 / kill-switch / 托盘最小化与退出 / 开机自启均正常;退出无残留 TUN 适配器与孤儿 sing-box 进程。
- [ ] Inno Setup 安装包可安装、生成快捷方式、运行、卸载干净。