原因
因为我这个electron不是用安装包安装的,所以不能用electron自带的各种更新方式来更新,所以要想另外一种办法来实现更新。
实现方法
首先搜索了一下看看有没有和我一样有类似需求的解决方案,果然在NPM里发现了electron-asar-hot-updater这个插件,因为作为一个简单的electron程序,所有代码都是保存在app.asar文件里的,所以思路就是只需要用新的asar文件替换旧的再重新打开软件就可以实现更新。但是我没有直接用这个插件,原因是我本来就有检查更新的接口,不想沿用插件里的更新服务器接口,。
步骤
检查更新
这一步只需要检查是否需要更新并获得下载链接就可以。
在软件内检查更新,如果需要更新,获取下载链接后通过ipcRenderer发送给electron。
1
| electron.ipcRenderer.send('updateEvent', download_url);
|
下载更新
Electron收到更新事件后,开始下载更新并通过ipcMain传回下载进度并在前端显示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| ipcMain.on("updateEvent", (event, download_url) => { downloadFileWorker(download_url, working_path + "/resources"); });
function downloadFileWorker(patchUrl, baseDir) {
const downloadFile = 'update.zip';
let receivedBytes = 0; let totalBytes = 0;
const req = request({ method: 'GET', uri: patchUrl });
const out = fs.createWriteStream(path.join(baseDir, downloadFile)); req.pipe(out);
req.on('response', (data) => { totalBytes = parseInt(data.headers['content-length'], 10); });
req.on('data', (chunk) => { receivedBytes += chunk.length; showProgress(receivedBytes, totalBytes); });
req.on('end', () => { update(); }); }
function showProgress(received, total) { const percentage = (received * 100) / total; mainWindow.webContents.send('downloadProgress', percentage.toFixed(0)); }
|
完成更新
更新的步骤是先关闭electron软件,然后替换文件,替换完成后重启软件,更新完成。
更新的详细信息
改进
这一步在electron-asar-hot-updater是使用了一个C#控制台程序来完成的,但是还是存在依赖的问题(在WIN7系统上需要安装.Net Framework),所以我需要一个更好的解决方法。
我先尝试了用.Net Core来打包一个self contained的控制台程序,这样就不存在依赖问题,但是打包出来的体积太大,放弃。
然后我想是不是可以用Go Lang做一个小程序来完成同样的功能(不知道在WIN7上是否不需要依赖,未测试),没有依赖而且体积小,查了一些Go Lang的基础后,成功写了一个Go版本的Updater。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| package main
import ( "fmt" "os" "os/exec" "time" )
var ( update = "" asar = "" executable = "" )
func main() { update = os.Args[1] asar = os.Args[2] executable = os.Args[3] time.Sleep(time.Duration(5) * time.Second) renameFile(update, asar) openExe(executable) }
func renameFile(update string, asar string) { info, fileErr := os.Stat(update) if os.IsNotExist(fileErr) { return } fmt.Println(info) err := os.Rename(update, asar) if err != nil { fmt.Println(err) } }
func openExe(executable string) { cmd := exec.Command("cmd.exe", "/C", "start", "/b", executable) if err := cmd.Run(); err != nil { fmt.Println("Error: ", err) } return }
|
步骤
下载完成后,把路径信息传给Updater.exe,关闭软件。(我这里把Updater.exe放在了和app.asar同一个文件夹下)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| function update() { var downloaded = working_path + '/resources/update.zip'; var updateAsar = working_path + '/resources/update.asar'; var appAsar = working_path + '/resources/app.asar'; let executable = process.execPath; const WindowsUpdater = working_path + "/resources/updater.exe";
try { if (!fs.existsSync(downloaded)) return; fs.renameSync(downloaded, updateAsar); winArgs = `${JSON.stringify(WindowsUpdater)} ${JSON.stringify(updateAsar)} ${JSON.stringify(appAsar)} ${JSON.stringify(executable)}` spawn('cmd', ['/s', '/c', '"' + winArgs + '"'], { detached: true, windowsVerbatimArguments: true, stdio: 'ignore' }) app.quit(); } catch (err) { console.error(err); } }
|
然后Updater接收到更新命令,等待5s(确保软件完全关闭)后替换文件,重新打开软件,更新完成。
缺陷
更新的时候会有一个黑黑的控制台窗口一闪而过,还没找到解决方法,但是除了闪一下并没有任何影响。
Author:
Alan
Permalink:
http://blog.vampuck.com/2021/03/22/electron-update/
License:
Copyright (c) 2020 CC-BY-NC-4.0 LICENSE
Read: 37