news 2026/10/14 17:45:53

自己替换自己有多难?ArtCraft Launcher跨平台自更新机制源码剖析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
自己替换自己有多难?ArtCraft Launcher跨平台自更新机制源码剖析

【免费下载链接】craft-launcher

The Craft App Launcher

项目地址:https://gitcode.com/gh_mirrors/cr/craft-launcher
点击查看免费下载

ArtCraft Launcher 是一个纯 Rust 编写的跨平台应用启动器,负责安装、更新和启动整个 Craft App Suite。它还有一个"隐藏技能":自己能更新自己。一个正在运行的程序如何安全地下载、校验并替换掉自己的可执行文件?这篇文章带你完整剖析它的跨平台自更新机制。

为什么"自己替换自己"这么难 🤔

自更新要同时跨过三道坎:

  1. 文件锁:Windows 会锁住正在运行的.exe,你根本没法在运行时直接覆盖它;
  2. 单实例锁:ArtCraft Launcher 同一时间只允许一个实例,新版本启动时旧版本还占着位置,会互相顶掉;
  3. 多形态安装:macOS 是.app打包目录,Windows 有 MSI 和绿色 zip 两种,Linux 有 AppImage、.deb、.rpm三种。每种"装进来的方式"都必须用同一种方式"换出去",否则安装会漂移。

源码作者在 crates/native/src/self_update.rs 开头用一张表把答案讲得很直白:

安装形态替换方式
macOS.app直接从 DMG 把新包覆盖到.app(运行时可写),然后重新打开
Windows MSI退出后由助手进程静默运行新 MSI(重装回原目录),再启动 exe
Windows 绿色 zip退出后把新 zip 解包覆盖到当前目录,设置文件不受影响
Linux AppImage把新 AppImage 重命名覆盖旧的(运行时可行),再启动
Linux.deb/.rpm交给系统包管理器(会弹密码框),然后重启

其余情况(Flatpak、FreeBSD、开发构建)则放弃自更新,只给下载链接。

第一步:先搞清楚"我是怎么被装上的" 🔍

自更新的第一步是自我认知。Install枚举(self_update.rs#L37-L48)列出了五种可自更新的形态,current()会调用detect()判断当前进程属于哪一种:

  • macOS:向上找.app目录,读Info.plist里的CFBundleIdentifier,确认是自家 bundle;
  • Windows:exe 旁边有portable.txt就是绿色版;否则查注册表HKCU\Software\Learning Machines LLC\ArtCraft Launcher的InstallDir或默认安装目录,匹配上才算 MSI 安装;
  • Linux:读APPIMAGE环境变量判断 AppImage;在沙箱(Flatpak)里直接返回None;/usr/bin下的二进制则用dpkg-query和rpm -q确认包管理器。

这个判断的结果会写进 UI 能力位 Capabilities::self_update——能力为false时,界面上的按钮会从"更新并重启"降级为"下载",优雅兜底。

第二步:下载新安装包,先验明正身 📦

更新走的是和普通 Craft 应用完全相同的下载通道。pick_asset()会根据当前安装形态挑对应文件(MSI 安装就挑.msi,AppImage 就挑.AppImage),再由 download() 完成下载,规则很严格:

  • 文件名必须合法(防路径穿越);
  • 必须有 SHA-256 校验值:优先用 Release 里的 digest,没有就抓 SHA256SUMS.txt 补上;
  • 发布方没提供校验和的文件直接拒绝安装——"没有凭证背书的东西绝不落地"。

Release 结构 对 GitHub 返回的一切视为不可信输入,下载链接必须指向仓库自己的 release 下载地址,否则整条 asset 被丢弃。

第三步:等老进程退出,助手进程接力 ⏳

这是整套机制最精妙的部分,核心思想只有一句:老进程负责换文件,新进程由一个"看守者"负责启动。

  1. 下载并校验完成后,先写入一个 self-update 标记(self-update.txt,记录 tag 和时间戳),防止更新完重启后又被提示更新同一版本造成死循环;
  2. 通过 claim_restart() 等待其他正在安装的应用全部结束(最多等 10 分钟,可手动取消),避免重启把别人的安装"腰斩";
  3. 启动一个脱离父进程的助手:Unix 上是一段sh脚本(helper_command),每 0.1 秒轮询kill -0 $pid等老进程退出;Windows 上是一个隐藏窗口的 PowerShell(windows_helper),先Wait-Process再跑 MSI 或解包脚本,最后Start-Process启动新 exe;
  4. 老进程退出,助手把新版本拉起来。

那新实例启动时,万一旧实例还没完全死透怎么办?single_instance.rs 里有个版本握手机制:后启动的实例会向监听端口发hello <版本>,运行中的实例回答running <版本>——后来者版本更新,就先退位让路。所以哪怕新旧版本短暂共存,结果也一定是新版接管、旧版退出。

几个平台细节很能体现功力:

  • AppImage 替换(replace_appimage):先拷一份临时文件到旁边,rename原子覆盖。运行中的副本挂载自已"断链"的 inode,所以覆盖不影响自己运行;
  • Windows MSI:用/passive /norestart静默重装到同一目录(MSI 向导记录的安装目录,用户级安装无需管理员);
  • macOS.app:直接从下载的 DMG 把新 bundle 拷过去——.app是目录,运行时可写,连重启都能省一步等待。

用户看到的是什么?✨

对普通用户来说,整个流程只有两个入口:

  • 检测到新版本后,窗口顶部出现一条横幅("ArtCraft Launcher v0.2.0 可用"),按钮是"更新并重启";每个新版本只弹窗询问一次(launcher_update_dialog);
  • 更新进行中,横幅变成进度条,依次显示Downloading…→Verifying…→Waiting for other installs…→Installing, then restarting…(views.rs#L150-L172);
  • 如果开启了自动更新,trigger_auto_updates() 会在后台自动排队执行,每个版本只尝试一次。

检查更新本身也把自己算进去了:backend 在后台线程把整套 Craft 应用加上自己一起查最新版本,发现新版且 24 小时内没更新过时,才发出LauncherUpdate事件(backend.rs#L256-L266)。

小结

ArtCraft Launcher 的自更新设计可以总结为四个原则:

  1. 同进同出——用什么形态装的,就用什么形态换;
  2. 先验后装——没有 SHA-256 背书的新包一律拒绝;
  3. 助手接力——老进程只负责善后,启动新版的脏活交给脱离的助手进程;
  4. 优雅兜底——能力判断不过就降级为"请下载",绝不硬来。

想继续深挖,推荐从 self_update.rs 开始读起,它的文件头注释本身就是一份优秀的跨平台自更新设计文档。

【免费下载链接】craft-launcher

The Craft App Launcher

项目地址:https://gitcode.com/gh_mirrors/cr/craft-launcher
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 17:45:49

Oracle 12c新建PDB并关联监听的稳态实践指南

1. 项目概述&#xff1a;为什么在Oracle 12c里“新建PDB并关联监听”是绕不开的基本功你刚接手一个某高校实验室的数据库运维任务&#xff0c;核心系统跑在Oracle 12c上——不是19c&#xff0c;也不是21c&#xff0c;就是那个已经进入扩展支持期、但仍在大量政企和教育类项目中…

作者头像 李华
网站建设 2026/10/14 17:45:38

STM32驱动AM2301A:输入捕获精准解析DHT类单总线传感器

1. 为什么AM2301A不能直接用HAL_Delay硬等——从协议底层看DHT类传感器的致命时间窗口AM2301A&#xff08;即DHT21&#xff09;不是普通IC或SPI器件&#xff0c;它走的是单总线异步通信协议&#xff0c;靠一根DATA线完成供电、时钟同步和数据传输三重任务。很多人第一次用STM32…

作者头像 李华
网站建设 2026/10/14 17:45:36

Qt 6.5原生录音器:QAudioInput实现跨平台WAV录制

1. 项目概述&#xff1a;为什么一个“很简单的例子”反而最难写好Qt录音器这个标题乍看平平无奇&#xff0c;但我在带新人做音视频项目时发现&#xff0c;恰恰是这种标着“很简单”的小例子&#xff0c;最容易踩坑、最常被误用、也最考验对Qt多媒体底层机制的理解深度。它不是简…

作者头像 李华
网站建设 2026/10/14 17:44:26

C51单片机流水灯仿真入门:Proteus+Keil搭建与避坑指南

简介&#xff1a;一套基于C51单片机的流水灯Proteus仿真学习资料&#xff0c;面向51单片机初学者和电子实训课程学员&#xff0c;可解决多花样流水灯编程、仿真验证与代码烧录等入门问题。工程内包含C语言源码、Keil工程文件、Proteus仿真工程文件、Hex可烧录文件以及运行演示视…

作者头像 李华
网站建设 2026/10/14 17:44:23

Codex 多智能体接力怎么不丢信息?用交接单固定输入与限制

Codex 多智能体接力怎么不丢信息?用交接单固定输入与限制 本文围绕“多智能体交接单”设计一个可离线复核的教学场景:不调用在线模型、不连接设备、不上传业务数据。核验日期为 2026-10-14。 一、先定义本题真正要避免的错误 把子任务只写成“继续处理”时,下一位既不知道可…

作者头像 李华