★ 本人在公司項目中實現的Electron更新功能。
★ 將實現更新過程的每一步都總結了出來,以及過程中我遇到了哪些問題,如何去解決的問題,有哪些注意事項。
★ 使用貼合實際應用的HTTP服務器做為載體實現更新,而非github。
開始:
程序配置:
-
構建工具:Electron-builder
-
更新工具:Electron-updater
在進行更新時,Electron
框架提供了更新的模塊。但是我的程序是使用Electron-builder
進行的構建。我就使用了Electron-builder
這個構建工具提供的自動更新的工具Electron-updater
來實現更新:
更新的思路流程:
-
首先安裝
electron-updater
:npm i electron-updater
-
進行更新的配置,官網有提供,在
build
下的publish
中進行設置publish: { provider: "generic", //generic通用HTTP服務器,當然有些人使用github做為更新載體這個地方的值就寫github,我使用的是http服務器,在局域網中使用。url: "http://xxxxxx/electron-updater" // 指向服務器對應更新的目錄,這個路徑的后綴electron-updater是我自定義的,具體原因文章最后講。channel: "latest", },
-
單獨新建了一個文件,來寫更新的邏輯代碼,重點來咯…
(下列代碼意思都有詳細注釋)
/*** 應用更新*/ const { app, dialog, ipcMain, nativeImage } = require("electron"); const { autoUpdater } = require("electron-updater"); const log = require("electron-log"); // 為了輸出更新的日志:為安裝了 electron-log => npm i electron-log const path = require("path");function initAppUpdate(win) {// 配置日志,這個日志在 windows:C:\Users\Administrator\AppData\Roaming\你的程序名\logsautoUpdater.logger = log;autoUpdater.logger.transports.file.level = "info";// 禁用增量更新:代表用戶每次進行更新,都會將服務器上完整的程序進行下載更新,而不會更新指定修改的塊文件。// 當然肯定是增量更新更好,但是為什么我禁用了呢,文章最后講。autoUpdater.disableDifferentialDownload = true// 退出時自動安裝:當用戶使用程序的時候,按兵不動。等待用戶關閉程序了退出了之后,程序自動安裝,這樣下次用戶再次打開就是更新后的程序,但我為了讓客戶感知到更新,我禁用了退出時自動安裝。autoUpdater.autoInstallOnAppQuit = false;// 檢查更新(應用啟動時觸發)app.whenReady().then(() => {autoUpdater.checkForUpdates();});// 監聽下載完成事件(這里就是具體給用戶展示的更新的對話框,這個對話框的視圖在文章開頭我貼出來了)autoUpdater.on("update-downloaded", () => {dialog.showMessageBox(win, {type: "info",buttons: ["稍后", "立即安裝"],message: "更新已下載",detail: "新版本已就緒,是否立即安裝?",defaultId: 1, // 默認選中"立即安裝"(索引1)cancelId: 0, // 按Esc鍵等同于點擊"取消"}).then((res) => {if (res.response === 1) autoUpdater.quitAndInstall(); // 如果他對話框點擊“立即安裝”,就退出開始安裝});});// 錯誤處理autoUpdater.on("error", (err) => {log.error("更新失敗", err);});checkUpdate(win); }// 渲染進程觸發的檢查更新(這個我在程序里有個專門讓用戶用來檢測更新的地方) function checkUpdate(win) {ipcMain.handle("checkUpdate", async () => {const res = await autoUpdater.checkForUpdates();if (!res.isUpdateAvailable) {dialog.showMessageBox(win, {type: "info",buttons: ["我知道了"],message: "當前版本已經是最新版本",icon: loadIcon(),});}}); }// 加載圖標(兼容開發和生產環境) function loadIcon() {try {let iconPath = path.join(__static, "right.png");return nativeImage.createFromPath(iconPath);} catch (e) {console.error("加載圖標失敗:", e);return null;} }// 這個函數,要引入到主進程的啟動程序文件里,還要將win傳參給該函數 // 為什么要傳遞win呢? 因為你不傳的話,這個提示更新的dialog就和程序是兩個程序。如果你傳了win給dialog的話,dialog就在當前win上彈出。 module.exports = { initAppUpdate };
-
將上面的
initAppUpdate
函數引入啟動程序文件,我這里的是background.js
:
-
更新的配置到此已經都完成了。接下來要確定程序的版本號,在
package.json
中有version
這個鍵,設置一個程序版本號。比如你這次打包的程序是1.0.0,那么下次更新就是1.0.1。程序的更新是去檢測版本號是不是更新了,版本號更新了才會拉取更新的程序文件。(每次更新構建的時候,記得提高版本號) -
打包構建:運行
npm run electron:build
,在構建后的目錄就會有latest.yml
這個文件和 程序文件等。 -
構建成功后,你需要在服務器上建一個目錄,用來放程序文件等。
-
在你服務器新建一個目錄(我命名為
electron-updater
),上傳文件:-
第一個文件:
latest.yml
這個文件包含了更新的版本信息以及程序包的信息等。 -
第二個文件:
xxx.exe
,應用程序。 -
第三個文件:
xxx.exe.blockmap
,塊映射文件。用于增量更新,每次更新只更新變動的文件。但是有需要注意的事項:
- 你想要實現增量更新,需要將
.blockmap
塊映射文件上傳到對應的服務器目錄下,并且你還要保留更新前版本的塊映射文件。因為增量更新,需要比對更新前的塊映射文件和準備要更新的塊映射文件之間的差異,來實現增量更新。 - 比如:你服務器上的程序版本現在是1.0.0,現在程序要更新為1.0.1,那么你想讓客戶端實現增量更新,你的服務器需要放置的文件有
- 版本
1.0.1
的latest.yml
文件 - 版本
1.0.1
的xxx.exe
文件 - 版本
1.0.1
的xxx.exe.blockmap
文件 - 版本
1.0.0
的xxx.exe.blockmap
文件
- 版本
- 還有一個增量更新的注意事項,寫在下面了👇
- 你想要實現增量更新,需要將
-
-
先把你在服務器上創建的放置更新文件、程序文件的目錄映射出去。也就是為了解決文章開始寫到的配置
publish
的時候,其中有個url:http://xxxxxx/electron-updater
,這個url
就是直接訪問我們新建的這個目錄。-
我新建的目錄名字叫做
electron-updater
目錄名稱。但是我在服務器上創建的electron-updater
并不和 url 中的electron-updater
是一個哦,是因為我用electron-updater
這個路徑代理了electron-updater
這個目錄,當然代理的路徑也可以改為別的,那么這時 url 的對應路徑也要改。 -
如何讓
http://xxxxxx/electron-updater
訪問到服務器上創建的electron-updater
放置文件的目錄呢?使用代理服務器!當我開發測試的時候,我使用的是
nginx
來映射的目錄。測試了一下,發現實現了更新的功能、以及增量更新,一切都成功了。但是了解到使用方的服務器代理使用的apache
,所以我又使用apache
來實現,這次遇到問題了,在測試實現增量更新的時候,一直報錯響應頭的Content-Type
錯誤,針對該錯誤我去apache
添加響應頭,測試依舊有新報錯,隨后就沒有再去嘗試了。所以開頭寫到了,我采用了完整更新,而非增量更新。完整更新都是可以正常下載更新,只有使用apache
的時候增量更新有問題。但使用nginx
是不用格外配置就可以成功實現 完整更新 和 增量更新,所以沒有代理服務器要求的,使用nginx
方便一些。-
nginx 配置
: -
apache 配置
:# 映射本地目錄到URL路徑 Alias "/electron-updater" "D:/xxx/electron-updater" ...
-
-
-
總結:
- 注意我在配置更新的時候,禁用了退出程序后自動更新,當然也可以打開這個配置哦。用戶打開程序再次退出關閉后,自動更新程序,這個功能還是挺不錯的。
- 保存路徑:
- 程序更新日志保存路徑:
C:\Users\Administrator\AppData\Roaming\你的程序名\logs
- 程序更新下載后的保存路徑:
C:\Users\Administrator\AppData\Local\xxxxx_electron-updater\pending
- 程序更新日志保存路徑:
- 一定要注意有新版本后,要提高程序的版本號,再
build
打包構建哦~ - 此外我還設置了一個小功能,就是不僅在程序剛打開的時候去檢測是否有更新。用戶在使用的過程中也加了按鈕可以讓用戶點擊查看是否需要更新,如果不需要更新,會提示用戶此版本為最新版本,多么貼心的功能… (前面的代碼里面有寫到)
此時Electron的更新功能,或者說Electron的自動更新就算圓滿結束!