webview 与 app 节点:把站点变成桌面应用
前面四十九章产出的都是"站点"——浏览器里输入地址访问。这一章给它一个窗口:class: "app" 服务节点 = 本地 HTTP 服务 + WebView2 桌面窗口,配置即得、自动降级、还能和 xs pack 组合成双击即用的单 exe。
本章导读
window 描述符与前端生命周期。50.1 第一个桌面应用
把任意现成站点的服务节点改成 class: "app",加一段 window 描述符:
{
"enabled": true, "class": "app", "name": "main",
"ip": "127.0.0.1", "port": 0,
"host_default": { "name": "app", "path": "wwwroot", "devlang": "c",
"devfile": "script/http_main.c" },
"window": {
"title": "我的应用", "width": 1280, "height": 800,
"url": "/", "devtools": false,
"close": "stop", "install_fallback": "ask"
}
}
启动 xs:先弹加载窗(服务就绪前的占位),本地 HTTP 就绪后自动打开 url 指向的主界面。注意两个与 http 类不同的缺省:ip 默认 127.0.0.1(回环绑定不触发 Windows 防火墙弹窗)与 port 允许 0(自动分配,见 50.3)。window 九个字段的逐字段约束(含 min_width / min_height / install_fallback 取值表)见 xs.json 字段参考。
构建变体须编入 webview 扩展:build.bat webview(或 all);无扩展的变体配置照常解析、只是没有窗口(见 50.4 矩阵)。
50.2 生命周期与 close 语义
- 启动:加载窗先行(遮住服务初始化的空窗期)→ 服务就绪 → 自动导航到主界面
close: "stop"(默认):用户关窗 = 优雅停机,走与 Ctrl+C 相同的停机链——不是杀进程close: "hide":关窗只隐藏、服务继续;再次双击同一应用时经单实例检测(按 exe 路径派生的命名 mutex)唤起既有窗口,新进程直接退出。v1 无托盘图标;hide 模式下停服务走信号路径- 崩溃隔离:WebView2 渲染器是独立进程,页面崩溃不传染 xs;窗口线程任何失败只降级为日志,绝不让引擎装配走 fail 路径
50.3 port: 0 自动分配
桌面应用的端口不该让用户看见,也不该和其他应用打架——port: 0 交给 OS 原子分配(仅 app 类允许,其他类 fail-fast):
- 回读:绑定成功后实际端口写进
XS_ServerInfo.PortBound(同时回写 Port,端点标识与脚本视图一致);前端拼 URL 用的就是它 - 脚本读法:
xsServerFind("main")->PortBound,配进页面让前端知道自己是谁(如 WS 地址) - 热重载粘滞:按服务名记粘滞表(跨 generation 存活),换代时显式绑回旧端口——已开窗口无感知;粘滞端口被占则候选失败按既有失败清理
- 边界:粘滞表不落盘。跨重启要端口稳定请配固定端口(外部系统要回调你时尤其如此)
50.4 降级矩阵与打包发布
| 构建变体 | 平台 | WebView2 | 行为 |
|---|---|---|---|
| webview 扩展 | Windows | 已装 | 完整窗口功能 |
| webview 扩展 | Windows | 缺失 | 按 install_fallback:ask 问询 / silent 静默装 / headless 直接降级;失败一律 headless |
| webview 扩展 | Linux | — | headless,日志打出访问 URL |
| 无扩展 | 任意 | — | 同 headless + 一行提示;配置照常解析 |
发布组合拳:xs pack(第 48 章)把站点打进二进制 + xsw.exe(无控制台的 GUI 子系统变体,随发布包提供)——产物是双击即用的单 exe 桌面应用:加载窗 → 界面 → 关窗停机,全程没有黑框。零运行时 DLL:导入表仅系统 DLL,WebView2Loader.dll 运行时从已装 Runtime 目录定位,缺 Runtime 按 install_fallback 兜底。
常见错误
编程练习
小结速查
class: "app" = http 前端化(配置同义 + window 9 字段) · 加载窗→就绪→开 URL→关窗停机 = 生命周期 · port:0 + PortBound = 隐形端口(跨重启要稳配固定) · 降级矩阵 = 窗口 best-effort 服务为本体 · xs pack + xsw.exe = 双击即用的桌面 exe