夜雨聆风学习资料网

ARTICLE · 1176942

Web2App v2 架构级升级 Windows-only

Web2App v2 架构级升级 Windows-only
     点击/上方的蓝字/关注我
🚀公众号后台复【布道者】查看最新AI技术学习路线🚀

Windows-only · 结构性不可繁殖 · 

668 KB 子应用产物 · 可执行文件图标完美

前几天,我发布了 Web2App v1.0.0——一个能把任意网页打包成单文件桌面应用的小工具。

它足够简单:输入 URL,选个图标,点一下打包,得到一个 exe。

它也足够受欢迎:v1 收获了超出预期的 star 和反馈,被用在内网系统封装、内部工具桌面化、个人效率工具等各种场景。

但 v1 有两个我们始终无法回避的问题:打包出来的应用本身就是母版——用户可以用它继续打包新应用。这在玩具级 demo 里无伤大雅,但在商用场景里,意味着你分发出去的每一个应用,都是一个潜在的"繁殖源"。另外,打包出来的应用 exe 文件的图标是默认的 w2a——这会对用户造成一定的困扰,即使我们在应用运行后的标题栏和任务栏都获得了正确的用户提供的图标。

v2.0.0,我们用一次彻底的架构重构,解决了这个问题。未来只会解决将 URL 打包成桌面应用之外的其他问题,比如 WebView 对复杂网页的支持、打开页面内的链接、在新窗口打开链接、性能优化、资源抓取等。


v2.0.0 做了什么

放弃子应用的自繁殖特性

v1 的子应用携带完整的打包器代码,只是隐藏了入口。通过在命令行执行子应用时添加 --master 参数就可以出现 URL填写的表单页面,都不需要你有能力修改二进制就能恢复打包能力。

v2 采用三个 crate 架构:

  • child:精简运行时(~670 KB),只负责"读配置 → 开网页",物理上不含任何打包器代码
  • master:打包器(~1.5 MB),编译期内嵌 child 模板,用户填表后生成 child 产物
  • tail-core:共享数据层(尾部协议、PNG 解码、URL 工具),零 GUI 依赖

子应用(child)和打包器(master)是两个独立的二进制。child 里找不到 pack、UpdateResource、winicon 这些符号,它们不是被隐藏了,而是根本不存在。

我们用字节级测试证明了这一点:打包 URL 的产物的裸主体 == child 模板,与 master 无关。

依然是真正的单文件子应用,零安装零辅助文件

产物 = child.exe 模板 + 尾部配置。尾部格式:

<payload JSON> <MAGIC:16B "__WEB2APP_TAIL__"> <len:u64 LE>

从文件末尾倒数 24 字节定位。不修改 PE 结构,不依赖注册表,不需要安装。用户拿到的就是一个 exe,双击即运行。

重复打包覆盖旧配置,体积不膨胀——因为协议天然支持"剥离旧尾部再写新尾部"。

用户自定义图标也可以覆盖子应用可执行文件图标

是 UpdateResource 注入,非快捷方式。很多"网页转桌面应用"的工具用快捷方式实现自定义图标,但那会引入额外的 .lnk 文件,破坏单文件承诺。

Web2App 通过 Windows UpdateResource API 把用户 PNG 转成多尺寸 ICO(16/32/48/256),直接写入 exe 的 .rsrc 资源节。产物仍是单文件,Explorer 里显示用户自定义图标。

用户打包 URL 时不选图标,会回落 w2a 默认图标,不会阻塞打包过程。

点击关闭按钮的确定性

我还解决解决了 tao + WebView2 的"永不退出"问题,这是 v2 解决的一个隐蔽但致命的问题。

实测发现:在 tao 0.37 + wry 0.57/WebView2 环境下,单条 WM_CLOSE(Alt+F4、任务栏关闭、taskkill、UI 自动化)发出后,tao 的 CloseRequested 事件可能永不派发——消息被 WebView2 的嵌套 COM 消息泵吞没,进程 30 秒以上不自退。

鼠标点 X 通常没事,因为伴随消息风暴。但"关闭即退出"不能依赖运气。

v2 使用了用两层确定性的方法来兜底:

  • WNDPROC 哨兵:在 WebView 构建前替换窗口过程,WM_CLOSE 在进入框架之前即被捕获
  • 看门狗线程:独立线程 sleep 300ms 后 process::exit(0),绕开消息泵竞争

关闭后,宿主进程、WebView2 子进程、临时文件全部清理,零残留。


这次战略转变为什么是 Windows-only

v1 尝试实现跨平台代码一致。可是在 v2 版本,我们做了一个艰难但明确的决定:只做 Windows 的 Web2App 应用。

这不是个人的特殊偏好,是技术与用户群体的综合判断:

WebView 后端成熟度:Windows 上 WebView2 是 Win11 预装、微软官方维护、API 稳定的运行时。macOS 用 WKWebView 尚可,但 Linux 上 WebKitGTK 需要用户自行安装 libwebkit2gtk-4.1-0,发行版碎片化导致无法保证运行时存在。

单文件可行性:Windows 的 PE + 尾部追加 = 真单文件,UpdateResource 注入图标也不会破坏单文件。macOS 必须是 .app bundle(目录结构),Linux 无原生单文件方案(AppImage 需 FUSE,.deb/.rpm 是包不是文件)。Web2App 的核心承诺是单文件,这在 Linux/macOS 上要么无法实现,要么成本极高。

构建测试成本:3 个平台 × 3 个 crate,会导致 CI 矩阵膨胀;每个平台的窗口生命周期、关闭消息、焦点处理机制不同,关闭的确定性这类问题需要在每个平台独立验证;Linux 生态过分碎片化,发行版/桌面环境组合无法穷举测试。

用户群体的性价比:在桌面系统市场上 Windows 占绝对多数。跨平台的复杂性会拖慢 Windows 端的迭代,反而会损害主要用户群体的体验。

Web2App 的核心价值(单文件、自定义图标、零依赖)在 Windows 上可以完美实现,在其他平台上要么做不到,要么代价远超于回报。


给 Linux 和 macOS 社区的话

v2 的代码不再包含 Linux/macOS 分支。但 v1 的跨平台代码仍然保留在 Git 历史中。

如果你是 Linux 或 macOS 的开发者,觉得"网页转单文件桌面应用"这件事值得做,我鼓励你 fork v1 并继续优化,代码是 MIT 协议开源的,你可以完全自由发挥。

跨平台的挑战是真实的问题:WebView 运行时碎片化、单文件方案缺失、构建测试矩阵膨胀——这些都是硬骨头。但正因为难,做好了才会有巨大的价值。

Web2App 的尾部协议、PNG 编解码、URL 工具等数据层代码是跨平台的,欢迎复用。如果你的 fork 做出了一些成果,欢迎你来专门告诉我。


最后

v2.0.0 已经发布,包含:

  • 完整的三个 crate workspace 架构
  • 54 个单元测试 + 24 个端到端断言
  • child 668 KB / master 1.47 MB
  • 关闭的确定性有兜底
  • 字节级结构性不可自繁殖已经证明

如果你觉得 Web2App 对你有用,欢迎:

  • 🎁 立即分享:让周围的人为小众软件惊艳
  • ⭐ 点个 Star:github.com/31i45/Web2App
  • 💬 提交反馈:用得不爽、发现 bug、想要新功能,都欢迎提 Issue
  • 🔧 参与贡献:代码、文档、测试,任何形式的 PR 都欢迎

网页应用桌面化,本来不该那么复杂的,主流的方案都太厚重了,Web2App 是最小巧的,单文件、零依赖、双击即可运行。

🚀公众号后台复【布道者】查看最新AI技术学习路线🚀

相关学习资料