Skip to content

热更新

前面只更新渲染进程的增量更新已经满足大部分人的需求了,但是还是有下面的几点满足不了所有人。

只更新更新渲染进程内容的不足

  1. 不能更新原生依赖,不能更新electron版本、不能更新其他额外文件等等不足

  2. 不能开启asar

  3. 不能只下载发生变更的文件,更新的颗粒度不够细

另外的方法

  1. 可以通过electron 对于加载default_app.asarapp.asar、和app目录有限级别的不同,实现对开启asar的程序进行热更、但还是无法实现electron版本更新, 还需要多次重启

优点

  1. 可以更新electron的版本

  2. 可以开启asar

  3. 方便版本回退

  4. 精细化更新,只更新变更的文件

缺点

  1. 多一个专门使用rust编写的应用程序updater

  2. 复杂度稍微有点提高

配置updateConfig.json, 生成

配置项类型说明
outputstringnpm run pack:rustUpdater产物基础输出目录
targetstring新版本所有文件gzip压缩后存放的路径
updateJsonNamestring新版本信息
versionstring新版本version
tempDirectorystring更新的目录
oldDirectorystring旧版本的文件迁移地址,可以方便版本回退
urlstring更新的url
updaterNamestring更新器名称

更新流程

  1. 获取更新程序electron_updater可以获取对应的版本

  2. 将文件重命名为配置项的updaterName

  3. 通过脚本,将不同系统的更新程序copyunpacked目录里面,参考脚本.electron-vite/builderHook/copyFileHook.js

  4. 当程序发布新版本时,调用npm run pack:rustUpdater生成当前的版本信息update-config.json即配置里面的updateJsonName,里面包含最新的版本号、每个必须文件的sha256信息和路径,和一个所有必须文件的gzip压缩的文件夹gzip1.0.0,即配置的 target + version;

  5. 旧版程序通过配置上的url配置访问url目录下的update-config.json

  6. 实例化UpdateElectron

参数类型描述
statusCallback(res: UpdateInfo)用于回调内部消息,一般情况下用不到
updaterNamestring更新 Updater 名称
versionstring当前版本号
exePathstring当前 exe 路径 app.getPath('exe')
tempDirectorystring临时目录
updateConfigNamestring更新配置文件名称
updateJsonUpdateJson更新配置文件
baseUrlstring更新下载 gzip 的基本地址 ${url}/${target}${version}
downloadFnDownloadFn下载函数
optionsHashElementOptions通过 options 配置文件排除文件夹或指定后缀 folders: { exclude: ['.*', 'node_modules', 'test_coverage'] }, files: { exclude: ['*.js', '*.json'] }
js
// 获取到的update-config.json的内容
const res = await request({ url: `${updateConfig.url}/${updateConfig.updateJsonName}.json`, })
const updateJson: UpdateJson = res.data;
// 获取临时路径
const dirDirectory = join(app.getAppPath(), '..', '..');
const tempDirectory = join(dirDirectory, updateConfig.tempDirectory);
// 下载函数
const downloadFn = async (url: string): Promise<Readable> => {
  const response = await request({
    method: 'get',
    url: url,
    responseType: 'stream',
  });
  return response.data;
}

// 通过 options 配置文件排除文件夹或指定后缀 防止有些东西被覆盖
const options = {files: {}}
const updateElectron = new UpdateElectron(statusCallback, updateConfig.updaterName, updateConfig.version, app.getPath('exe'), tempDirectory, updateConfig.updateJsonName, updateJson, `${updateConfig.url}/${updateConfig.target + updateJson.version}`, downloadFn, options)
// 获取到的update-config.json的内容
const res = await request({ url: `${updateConfig.url}/${updateConfig.updateJsonName}.json`, })
const updateJson: UpdateJson = res.data;
// 获取临时路径
const dirDirectory = join(app.getAppPath(), '..', '..');
const tempDirectory = join(dirDirectory, updateConfig.tempDirectory);
// 下载函数
const downloadFn = async (url: string): Promise<Readable> => {
  const response = await request({
    method: 'get',
    url: url,
    responseType: 'stream',
  });
  return response.data;
}

// 通过 options 配置文件排除文件夹或指定后缀 防止有些东西被覆盖
const options = {files: {}}
const updateElectron = new UpdateElectron(statusCallback, updateConfig.updaterName, updateConfig.version, app.getPath('exe'), tempDirectory, updateConfig.updateJsonName, updateJson, `${updateConfig.url}/${updateConfig.target + updateJson.version}`, downloadFn, options)
  1. 获取新版信息,如果存在版本号更新,则进入更新逻辑

  2. 下载对应的文件到临时目录上

  3. 调用更新

  4. 退出程序 app.quit(),必须手动调用,否则可能权限不够,更新程序结束不了该进程

  5. 等程序自动重启

详细代码参考src/main/services/HotUpdaterTest.ts

相关项目代码

https://github.com/mashirooooo/window_updater_node

https://github.com/mashirooooo/electron_updater

欢迎issue和pr

Released under the MIT License.