- 引入 electron-updater 实现自动更新功能 - 新增 Java 环境扫描与校验的 IPC 处理逻辑 - 实现离线账号登录功能 - 新增配置变更跨进程广播机制 - 重构游戏启动逻辑,使用主进程内存配置作为唯一权威来源 - 新增界面显示与语言设置的配置页面 - 添加 Windows 平台自动发布 CI 流水线 - 迁移旧版配置/认证文件到用户数据目录 - 修复崩溃日志路径、表单控件等多项 bug - 重构设置页组件系统统一界面样式
16 KiB
Koring Launcher 自动更新方案(v1 规划稿)
状态:M1 已完成(2026-08-28);M2 待开始 目标平台:Windows 优先(NSIS exe 安装包),macOS/Linux 后续复用同一套架构 决策记录:
- 安装器模式:保持 assisted 安装器(
oneClick: false+ 可改安装目录)→ 每次更新整包下载- 更新托管:GitHub Releases
- 当前交付:M1 基础设施已完成(electron-updater 依赖 + publish 配置 + 1.2.0 打包验证)
1. 背景与目标
- 项目:Electron 33 + React 19 + TS + electron-builder 25(Windows NSIS 安装包,
dist:dev/beta/run三模式打包) - 现状:
package.json版本 1.1.2,无任何更新机制;用户需手动下载新版安装包 - 目标:客户端内自动检查新版本 → 下载 → 静默重装 → 自动重启,先跑通 Windows
2. 技术选型
选 electron-updater(electron-builder 官方配套,与现有打包链无缝衔接)。
| 方案 | 说明 | 结论 |
|---|---|---|
| electron-updater | 自动生成 latest.yml 清单、SHA512 校验、进度事件、失败重试、断点续传 |
✅ 选用 |
| electron-simple-updater | 只支持替换 asar,不支持 NSIS 重装 | ❌ |
| update-electron-app | 只面向 GitHub,定制性差 | ❌ |
| 自研差分/自建服务 | 灰度、强制更新、统计需要时再评估 | 后期可选 |
版本兼容:electron-builder 25.1.8 ↔ electron-updater ^6.x(官方同仓库发布,6.x 与 24/25/26 打包器配套)。
3. 关键约束(已确认)
3.1 assisted 安装器 → 整包下载
当前 electron-builder.yml 为 assisted 安装器:
nsis:
oneClick: false
allowToChangeInstallationDirectory: true
electron-updater 的 NSIS 差分更新(blockmap 增量)只支持一键安装(per-user oneClick);
assisted 安装器安装目录不固定,退化为每次下载完整 koring-launcher-<version>-setup.exe。
已决策:接受整包下载,不改安装体验。含义:
- 每次更新下载全量安装包(预计几十 MB 级别),CDN/带宽按此评估;
- 后续若用户量大、包体过大,可再评估改 oneClick 启用差分,或自研增量(代价高,不优先)。
3.2 代码签名(重要)
Windows 下 electron-updater 会对下载的安装包做 Authenticode 校验:当前 exe 有签名时,要求新安装包发布者一致; 当前 exe 未签名时校验会被跳过(记警告)。
- 未签名:开发/内测可跑通全流程,但国内杀软对未签名 exe 误报率高;
- 正式对外发布前必须做代码签名(OV 证书起步,EV 更佳),并让发布流水线对 setup.exe 签名;
- 签名后 electron-builder 默认会校验一致性,无需额外配置,但要保证发布流水线签名证书与产物一致。
4. 整体架构
┌───────────────────────────── 客户端 ─────────────────────────────┐
│ React UI (src/) ⇄ preload.ts (contextBridge) ⇄ 主进程 │
│ │ electronAPI.onUpdateStatus() │ │
│ └────────── IPC ────────────────┘ │
│ 主进程 electron/updater.ts(封装 electron-updater) │
│ electron/handlers/update.ts(IPC handler) │
└──────────────────────────────┬──────────────────────────────────┘
│ HTTPS
▼
┌───────────────────────────┐
│ GitHub Releases (仓库) │
│ · koring-launcher-1.2.1 │
│ -setup.exe │
│ · latest.yml │
└───────────────────────────┘
(国内网络差 → 见 §5.3 加速对策)
5. 服务端:GitHub Releases
5.1 发布产物
electron-builder 配置 publish: { provider: github } 后,electron-builder --publish always
(或 --publish 搭配 CI token)会自动:
- 打包 Windows 产物;
- 创建/更新 GitHub Release(tag 取自版本号,如
v1.2.1); - 上传
koring-launcher-1.2.1-setup.exe+latest.yml(+latest.yml.blockmap,assisted 模式下不用但会生成)。
latest.yml 是更新清单(版本、文件路径、大小、sha512),electron-updater 靠它发现新版本并校验完整性:
version: 1.2.1
files:
- url: koring-launcher-1.2.1-setup.exe
sha512: <base64-sha512>
size: 81234567
path: koring-launcher-1.2.1-setup.exe
sha512: <base64-sha512>
releaseDate: '2025-01-01T00:00:00.000Z'
5.2 配置示例(electron-builder.yml 增加段)
publish:
provider: github
owner: <GitHub 用户名/组织>
repo: <仓库名>
# releaseType: release # 默认 release;beta 通道可设 draft/prerelease
打包时 electron-builder 会把 app-update.yml(含 provider 信息)写进 resources/,
electron-updater 在运行时读取它——没有 publish 配置就不会生成 app-update.yml,更新会直接报错(M1 验收点)。
5.3 国内网络注意(务必先评估)
electron-updater 的 GitHub provider 走 api.github.com(发现版本)与 github.com/.../releases/download/...(下载),
国内部分网络环境访问慢或不稳定。对策(按需选):
- 现状接受:很多应用直接走 GitHub,配合失败重试 + 手动"下载最新版"兜底按钮;
- CDN 加速(推荐后续做):改为
genericprovider,把latest.yml+ exe 同步到 OSS/COS + CDN(或 ghproxy 类代理),app-update.yml指向 CDN URL; - 自建/商业 CDN 代理 GitHub Releases:等用户量上来再评估。
方案设计上保持 provider 可切换:
electron/updater.ts只面向 electron-updater 统一 API, 未来从github切generic只需改 electron-builder.yml + 重新打包,业务代码不动。
6. Windows 更新流程(整包下载版)
应用启动
├─ 加载完成且空闲后(延迟 10~15s)→ 静默 checkForUpdates()
│ (避开启动加载与 Minecraft 下载抢带宽;首启/开发模式跳过)
├─ 无更新 → 结束,静默
└─ 有更新 → 发 update:status{state:'available', version}
│
▼
前端提示"发现新版本 vX.Y.Z"(非强制,可忽略/稍后)
│ 用户点"下载更新"
▼
autoUpdater.downloadUpdate()
├─ download-progress → update:status{state:'downloading', percent, speed, ...}
├─ 下载完成 → SHA512 校验(latest.yml)→ update:status{state:'downloaded'}
│
▼
前端提示"重启并安装"(可暂缓;退出时 autoInstallOnAppQuit 兜底)
│ 用户确认
▼
autoUpdater.quitAndInstall()
├─ 应用退出 → NSIS 静默安装(不弹 UI,沿用原安装目录)
└─ 安装完成自动重启 → 运行新版本
失败路径:
· 网络失败 → 提示重试(electron-updater 自带断点续传/重试)
· 校验失败 → 清除缓存重下;仍失败则提示手动下载最新版
· 静默安装失败 → 提示手动下载;保留旧版本可用
更新状态机(前端 store 用)
idle → checking → available → downloading → downloaded → installing → relaunch
└─not-available→ idle └─ error → idle(可重试)
7. 代码结构规划
electron/
updater.ts # 新增:封装 electron-updater
# · 初始化(读 app-update.yml、设日志)
# · 守卫:!app.isPackaged 时跳过(开发模式)
# · check() / download() / quitAndInstall() / 状态查询
# · 订阅 checking/available/not-available/download-progress/downloaded/error
# · 转发为 update:status 事件(带完整 payload)
handlers/update.ts # 新增:IPC handler
# · update:check → 触发检查
# · update:download → 触发下载
# · update:quitAndInstall → 重启安装
# · update:getState → 查询当前状态/版本信息
main.ts # 改:import { registerUpdateHandlers };注册;启动后延迟静默检查
preload.ts # 改:暴露
# · checkForUpdates() / downloadUpdate() / quitAndInstall()
# · onUpdateStatus(cb) → 订阅 update:status(沿用现有 on() 模式)
src/
api/update.ts # 新增:IPC 封装 + TS 类型(UpdateStatus)
stores/update.ts # 新增:zustand store,维护状态机
components/settings/... # 更新 UI:设置页"关于/更新"区块
# · 当前版本号 + 检查更新按钮
# · 下载进度条(百分比/速度/剩余大小)
# · "重启并安装"确认
components/... # 可选:新版可用 toast / 弹窗(非强制打扰)
依赖注意:electron-updater 必须放 dependencies(不能是 devDependencies),
否则 asar 打包后运行时找不到模块——最常见事故,M1 验收必须覆盖。
8. 版本与多通道
- 沿用现有
scripts/version.js升版(pnpm version:set 1.2.0),版本必须严格 semver 递增; - electron-updater 只认 package.json 的
version,升版后需重新打包发布; - dev / beta / run 三模式的通道隔离放加固阶段(M5):
- GitHub provider 多通道依赖 tag 约定(如
v1.2.1-beta.1),行为略绕,先只用默认 latest 通道跑通; - 届时按产品需要决定:beta 走 prerelease/draft release,run 走正式 release,或切 generic + 不同 URL。
- GitHub provider 多通道依赖 tag 约定(如
9. 里程碑与验收
| 阶段 | 内容 | 验收标准 |
|---|---|---|
| M1 基础设施 | ① dependencies 加 electron-updater;② electron-builder.yml 加 publish(github);③ 升版打包 pnpm dist:run |
产物目录出现 latest.yml;解包 asar 的 resources/app-update.yml 存在;electron-updater 在 asar 内可 require |
| M2 主进程 | updater.ts + handlers/update.ts + preload 暴露 | 手动触发 update:check 能返回状态;事件能推送到渲染进程(dev 下用 forceDevUpdateConfig 或打包版验证) |
| M3 前端 UI | update store + 设置页更新区块 + 启动静默检查 | 完整交互:检查/提示/进度/重启安装/失败重试 |
| M4 联调冒烟 | 发布 v1.2.0 → 再发布 v1.2.1,真机从 1.2.0 升到 1.2.1 | Windows 真机全流程通过,含取消下载、断网重试、校验失败场景 |
| M5 加固 | 可对外发布 |
10. 风险与对策
| 风险 | 影响 | 对策 |
|---|---|---|
| electron-updater 误放 devDependencies | 打包后更新直接报错 | M1 验收强制检查 asar 内依赖 |
| 未配置 publish → 无 app-update.yml | 运行时报 "app-update.yml not found" | M1 验收点;文档示例已给 |
| 未签名 exe 被杀软拦截 | 下载/安装被拦,更新失败 | 正式发布前签名(M5);内测接受现状 |
| assisted 静默安装弹 UI / 请求管理员 | 更新中断 | M4 用现有 build/installer-custom.nsh 专门联调;必要时加 runAfterFinish/静默参数处理 |
| api.github.com 国内访问差 | 检查/下载慢或失败 | 失败重试 + 手动下载兜底;后续 CDN 加速(§5.3) |
| 检查频率过高 | 浪费带宽、触发限流 | 启动延迟 10~15s + 手动按钮;间隔建议 ≥1h |
| 磁盘满 / %LOCALAPPDATA% 权限 | 下载/解压失败 | 失败回退提示,清理 updaterCacheDirName 缓存 |
| 版本号不递增 | 永远查不到更新 | CI/脚本校验 version:set 只允许升版 |
| 更新失败后应用状态异常 | 用户卡在旧版本 | 保持旧版可用;UI 提供手动下载入口;错误上报(可复用现有 crash 体系) |
11. 后续待决策(不阻塞 M1~M4)
- 是否需要强制更新 / 最低版本策略
- 国内加速方案何时落地(generic + OSS/COS/CDN)
- macOS / Linux 更新的排期(架构已预留,届时分别补 zip/dmg 与 AppImage 产物与签名)
12. SignPath 代码签名接入(2026-08-28 落地)
方案:electron-builder 自定义签名(win.sign: scripts/signpath-sign.js),
构建时对内部 exe(Koring Launcher.exe、elevate.exe、卸载器)与最终 setup.exe
逐个提交 SignPath 远程签名,签名发生在 blockmap / latest.yml 生成之前,
清单 sha512 与 blockmap 自动对应签名后产物,electron-updater 校验无缝。
SignPath 后台准备(已确认值):
- Organization ID:
31ecd033-d59e-492b-a70b-b00a54bbc7c2(已写入 workflow env) - API Token:用户详情页生成(CI 用途),放入 GitHub Secrets
SIGNPATH_API_TOKEN - slug:项目
Koring_Launcher;签名策略Koring_Launcher_Dev_builder(均写入 workflow env); 产物配置 DEFAULT 在项目仅一个配置时可省略SIGNPATH_ARTIFACT_CONFIG_SLUG
⚠️ 待办约束:
- 测试证书:当前策略 Purpose 为 Test signing(测试证书),用户机器默认不信任
(SmartScreen / 杀软警告;
signtool verify会报"不受信任"——预期现象), 正式对外发布需生产证书(OV/EV)+ 对应生产签名策略(届时只换SIGNPATH_SIGNING_POLICY_SLUG)。 - 审批流程:已在 SignPath 后台关闭人工审批(自动批准),CI 可全自动;策略 Purpose 已改为 Release signing。
新增/改动文件:
scripts/signpath-sign.js— 签名模块(无 token 自动跳过,本地构建不受影响).github/workflows/release.yml— 推送 tagv*(或手动填版本)→ 构建 → 签名 →electron-builder --publish always发布 GitHub Releaseselectron-builder.yml—win.sign挂载
CI Secrets:仅 SIGNPATH_API_TOKEN(必填)+ SIGNPATH_ARTIFACT_CONFIG_SLUG(可选);
组织 ID 与 slugs 已在 workflow 中写死。
2026-08-28 实测结果(与官方 PowerShell 模块对齐后的真实签名):
- 协议:
POST {base}/v1/{orgId}/SigningRequests(multipart/form-data,字段 ProjectSlug / SigningPolicySlug / ArtifactConfigurationSlug? / Description / 文件部件 Artifact)→ 响应 Location 头 = 请求 URL → 轮询status/isFinalStatus→ 完成后取 signedArtifactLink 下载; 认证Authorization: Bearer <token>。 - ✅ 98.3MB setup.exe 提交成功(无大小限制问题);自动批准生效(InProgress → Completed 无人工介入)
- ✅ 小文件端到端签名成功,
signtool verify显示签名链 Issued to: Lingke Network - ⚠️ 本机到 SignPath 下载 100MB+ 产物极慢(20min+),CI(GitHub Actions)网络环境不受影响; 模块已加下载重试(3 次)+ 临时文件替换
验证点(首次 CI 运行):确认 SignPath 请求全部 Completed、latest.yml 的 sha512
与上传的 signed setup.exe 一致、签名链显示 "Lingke Network"。