dx bundle --release --platform windows --package-types nsis 产出的安装包
(target/dx/<name>/bundle/windows/nsis/*-setup.exe)的升级语义,与未来
应用内升级方案的设计空间。生成器:dioxus-cli 0.7.10(StickerProcess.nsi
模板可在 target/dx/.../nsis/ 下查看)。
生成的 NSIS 安装器天然支持升级——新版 setup.exe 直接运行即完成升级:
| 机制 | 行为 |
|---|---|
| 安装目录 | 固定 $LOCALAPPDATA\Programs\StickerProcess,新旧版本同目录 |
| 文件覆盖 | NSIS File 指令默认 SetOverwrite on,旧文件被新文件替换 |
| 注册表 | 卸载项固定 key com.stickerprocess.app,覆盖更新不产生重复的"添加/删除程序"条目;DisplayVersion 随 Cargo.toml 版本更新 |
| 卸载器 | 旧 uninstall.exe 被新版覆盖 |
| 用户数据 | settings.toml 在 %APPDATA%\StickerProcess,升级/卸载均不受影响 |
- 无应用内更新检查:未接入
dioxus-updater插件,不会自动提示新版本。 无运行中防护→ 已解决(2026-09-21),见下节「升级防护」。无版本比较→ 已解决(2026-09-21),见下节「升级防护」。
build/nsis-hooks.nsh 通过 Dioxus.toml 的 [bundle.windows.nsis] installer_hooks
被 dx !include 进生成的 installer.nsi(不 fork 模板——dx 升级模板时不用跟着改;
若将来 dx 自己定义 .onInit,会编译期报重复定义,是大声失败)。钩子只有一个入口
.onInit(任何 Section 之前运行,晚了就没意义):
| 检查 | 行为 |
|---|---|
| 程序正在运行 | taskkill(不带 /F,即 WM_CLOSE 优雅退出)→ 等 800ms 复查 → 仍在则交互式询问 OK/Cancel(OK 才 /F 强杀,Cancel 中止安装)。静默安装不弹窗,直接 /F。检测不靠窗口标题( FindWindow 会随标题改动失效),只看 taskkill 退出码(0 = 确实结束了进程,128 = 没找到)。 |
| 已装版本更新 | 读注册表 DisplayVersion 与安装器自身的 FileVersion 比较(模板把 {{version}} 写进了 VERSIONINFO)。已装更新 → 交互式确认"仍要装旧版吗",静默安装直接拒绝并以退出码 3 结束(CI/无人值守不会把旧包盖上去)。读不到任一版本就放行——不为防守卡死正常安装。 |
版本比较直接用 NSIS 自带 WordFunc.nsh 的 ${VersionCompare}(字段数不同按缺位补 0,
故已装 0.1.0 与安装包 0.1.0.0 判为相等),没有手写解析。
两个易踩的点(都已在 hooks 里规避):
- 钩子文件不经过 handlebars 渲染,所以里面不能写
{{version}};新版本号只能从 安装器自身的 VERSIONINFO 读(${GetFileVersion} "$EXEPATH")。 - NSIS 默认按 ANSI 代码页读脚本;hooks 里的中文注释要求
makensis以 UTF-8 读入 (dx 自己调用时已带该参数——本项目实测dx bundle --package-types nsis通过)。
验证(2026-09-21 实测,非推测):
- 版本比较 8/8 用例(含
0.1.0vs0.1.0.0判等、0.10 > 0.1的数字比较): 用抽取出的STP_IsDowngrade编一个最小安装器跑静默安装,结果写文件读回。 - 降级拦截端到端:伪造 HKCU 测试键(
…\Uninstall\com.stickerprocess.guardtest)DisplayVersion=9.9.9→ 静默安装退出码 3 且未写任何文件;0.0.1/0.1.0/ 无值 → 正常继续。测试键结束后删除,真实键未被动过。 - 运行中防护端到端:把 app 复制成
StickerProcessGuardTest.exe跑起来 → 静默安装 rc 0 且继续,2 秒内该进程消失(supervisor 报 exit code 0,即优雅退出而非强杀); 无实例时 1.1s 直接放行。
原计划 fork 自定义模板;实际 dx 的模板已支持 installer_hooks([bundle.windows.nsis]),
注入一个 .nsh 就够——不必维护模板副本(fork 的话 dx 每次升级模板都要手动跟)。
实现与验证见上面「升级防护」。
启动时(或手动按钮)GET 一个版本清单 URL(如 GitHub Releases 的
latest.json),比较 DisplayVersion,发现新版弹 toast + 打开下载链接。
不引入签名体系,几十行代码;适合 GitHub Releases 作为分发渠道。
Tauri 式更新:签名 manifest(ed25519)+ 增量下载 + 静默替换重启。 需要:
- 服务器托管 manifest 与安装包(GitHub Releases 可用)
- 签名密钥对管理与 CI 集成
dioxus-updater插件接入与端点配置
适合正式对外分发后使用;个人工具现阶段收益有限。
- 静态构建(
E6_INPROCESS_RESEARCH.md§7)落地后,安装包已不再捆绑ffmpeg.exe(Dioxus.toml的resources已移除,2026-09-06)—— shared exe 缺 DLL 在干净机器上无法启动,捆绑无意义;sidecar 引擎改为 启动探测可用性后按需启用。 - release 构建已隐藏终端窗口(
windows_subsystem),升级体验无黑框。