Electron自動更新失效報錯Error:?Object?has?been?destroyed的問題解決
Electron 自動更新失敗
在 Electron 應(yīng)用某次更新,出現(xiàn)了如下循環(huán)更新的問題:

此時,查詢?nèi)罩?,發(fā)現(xiàn)報錯如下 Error: Object has been destroyed:

問題原因
首先,通過查閱資料得知:在 Electron 中,當(dāng)一個窗口被銷毀后,與該窗口相關(guān)聯(lián)的 JavaScript 對象也會被銷毀,如果再次嘗試訪問已被銷毀的窗口對象時,就會發(fā)出上圖所示的錯誤。
通過日志可以很好的找到問題發(fā)生的地方(幸好我們主進(jìn)程中關(guān)鍵點都添加了明顯的日志信息,方便問題查找),很明顯是在 autoUpdater.on('update-available' 檢測到自動更新后的報錯,那就著重排查下這里。
autoUpdater.on('update-available', () => {
mainLogger.info('自動更新 有新版本')
disableStopMainWindowClose()
win.show()
mainWindow.destroy()
})
通過日志可以分析應(yīng)該是在 disableStopMainWindowClose 方法中的產(chǎn)生的問題:
export function disableStopMainWindowClose() {
mainWindow.off('close', onMainClose)
systemStatus.off()
}
function onMainClose(e: Electron.Event) {
if (isQuit) return
if (mainWindow.isFullScreen()) {
...
}
如何解決
為了避免這個錯誤,需要在窗口對象被銷毀時取消訂閱所有與該窗口相關(guān)的事件,并在需要訪問窗口對象時先檢查窗口對象是否已經(jīng)被銷毀。
所以需要在調(diào)用窗口方法前,先判斷窗口是否已被銷毀
function onMainClose(e: Electron.Event) {
if (isQuit) return
if (!mainWindow?.isDestroyed()) return
...
重新打包,上傳成功后,再次出發(fā)自動更新,即可正常了。順便說一下我們 Electron 應(yīng)用的更新流程。
打包
首先是打包,打包時需要更新 package.json 中的版本和說明
{
"version": "2.2.7",
"versionNotes": "發(fā)現(xiàn)新版本 v2.2.7!\n\n1. 修復(fù)客服已知問題"
}
修改完后,Mac 和 Windows 各自打包,并上傳到服務(wù)器。
自動更新流程
關(guān)于 Electron 應(yīng)用的自動更新,官方提供了更新應(yīng)用程序處理自動更新過程。
因為我們使用的 electron-builder 打包應(yīng)用,所以使用的是它內(nèi)置的更新程序Auto Update。
相比 Electron 中自帶的更新,它有以下優(yōu)勢:
- 不需要搭建專用的發(fā)布服務(wù)器,可上傳到任意服務(wù)器;
- 代碼簽名驗證可以在 macOS 和 Windows 上進(jìn)行;
- 支持下載進(jìn)度提示;
- 代碼簡單,工作量少。
實現(xiàn)過程
安裝依賴
yarn add electron-updater
主窗口調(diào)用
當(dāng)主窗口被激活顯示時,通過 checkLatestVersion 方法檢查是否有版本更新
mainWindow.on('show', checkLatestVersion)
檢測是否有更新
checkLatestVersion 方法定義在主進(jìn)程的 update.ts 文件中
// update.ts
...
export const checkLatestVersion = () => {
getLatestVersionInfo().then((version: any) => {
if (!version) return
mainLogger.info('檢查最新版本', version)
dialog
.showMessageBox(mainWindow, {
defaultId: 0,
cancelId: 3,
message: version.notes,
buttons: version.isCurrVersionAvailable
? ['更新', '取消']
: ['更新'],
})
.then(({ response }) => response === 0)
.then((isUpdate) => {
if (isUpdate) IS_MAC ? checkMacUpdate() : checkWinUpdate()
})
.finally(() => (isDialogOpen = false))
})
}
getLatestVersionInfo方法用于檢測更新,主要通過比對服務(wù)器的安裝包版本是否大于本地版本,在本地打完包后,會將本地的包上傳到服務(wù)器上,同時會有一份 RELEASE.json 文件,就是通過比對 RELEASE.json 文件中的 currentRelease 字段。
{
"currentRelease": "2.2.7",
"notes": "發(fā)現(xiàn)新版本 v2.2.7!\n\n1. 修復(fù)客服已知問題。"
}
當(dāng)大于本地版本即需要更新時,顯示更新窗口(包含更新版本、更新說明等),當(dāng)用戶點擊更新后,調(diào)用 Mac 或 Windows 的更新方法。
檢查更新前奏——創(chuàng)建更新窗口
const checkMacUpdate = () => {
const win = createAutoUpdateWindow()
...
}
首先通過 createAutoUpdateWindow 創(chuàng)建更新窗口
const createAutoUpdateWindow = () => {
const win = new BrowserWindow({
width: 560,
height: 120,
titleBarStyle: 'hidden',
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
},
})
win.loadURL(getLocalUrl('/auto-update'))
return win
}
上面代碼中創(chuàng)建了一個瀏覽器窗口,并加載 /auto-update 路由:
<template>
<section style="padding: 42px 32px">
<a-progress
:show-info="false"
:stroke-color="{
'0%': '#108ee9',
'100%': '#87d068'
}"
:percent="percent"
status="active"
/>
<center style="padding-top: 16px">正在更新中,更新完成后會自動重啟,請耐心等待。</center>
</section>
</template>
<script setup>
import { onMounted, ref } from 'vue'
const percent = ref(0)
const timer = setInterval(() => {
percent.value += 2
if (percent.value >= 95) clearInterval(timer)
}, 300)
</script>
頁面顯示一個假的進(jìn)度條即可,新版本下載完成后會自動關(guān)閉并安裝。
autoUpdater 自動更新
const checkMacUpdate = () => {
const win = createAutoUpdateWindow()
// 監(jiān)聽升級失敗事件
autoUpdater.on('error', (message) => {
mainLogger.error('自動更新', message)
})
// 監(jiān)聽發(fā)現(xiàn)可用更新事件
autoUpdater.on('update-available', () => {
mainLogger.info('自動更新 有新版本')
isUpdating = true
disableStopMainWindowClose()
win.show()
mainWindow.destroy()
})
// 監(jiān)聽沒有可用更新事件
autoUpdater.on('update-not-available', () => {
mainLogger.info('自動更新 沒有新版本')
win.close()
})
// 監(jiān)聽下載完成事件
autoUpdater.on('update-downloaded', () => {
mainLogger.info('自動更新 新版本下載完成')
// 重新啟動并安裝更新包 只有update-downloaded事件中可調(diào)用
autoUpdater.quitAndInstall()
})
mainLogger.info('自動更新 開始檢查', AUTO_UPDATE_JSON_URL)
// 設(shè)置安裝包所在服務(wù)器地址
autoUpdater.setFeedURL({ url: AUTO_UPDATE_JSON_URL, serverType: 'json' })
// 請求服務(wù)器是否有更新。 在使用此API之前,您必須調(diào)用setFeedURL
autoUpdater.checkForUpdates()
}
通過 autoUpdater Events 綁定相應(yīng)的事件,通過setFeedURL方法設(shè)置安裝包的地址,最后通過checkForUpdates檢查是否有更新,觸發(fā)綁定的各種事件。
當(dāng)檢測到有新版本時,顯示更新窗口,假進(jìn)度條冒充下載中,自動下載安裝包

總結(jié)
本文主要講解如何解決 Error: Object has been destroyed 這個 Electron 中最常見的問題,以及 Electron 自動更新的流程。通過解決這個問題,意識到需要在 Electron 主進(jìn)程中,要為代碼的關(guān)鍵點添加一些重要的日志信息,這樣在遇到問題時,能讓我們更加方便的定位問題。
以上就是Electron自動更新失效報錯Error: Object has been destroyed的問題解決的詳細(xì)內(nèi)容,更多關(guān)于Electron自動更新失效的資料請關(guān)注腳本之家其它相關(guān)文章!
- electron-vue+electron-updater實現(xiàn)自動更新(步驟源碼)
- Electron autoUpdater實現(xiàn)Windows安裝包自動更新的方法
- Windows下支持自動更新的Electron應(yīng)用腳手架的方法
- 如何使用electron-builder及electron-updater給項目配置自動更新
- electron-vue?運行報錯?Object.fromEntries?is?not?a?function的解決方案
- electron-vue中報錯Cannot?use?import?statement?outside?a?module的解決方案(親測有效!)
相關(guān)文章
Vue3中動態(tài)修改樣式與級聯(lián)樣式優(yōu)先順序圖文詳解
在項目中,我們時常會遇到動態(tài)的去綁定操作切換不同的CSS樣式,下面這篇文章主要給大家介紹了關(guān)于Vue3中動態(tài)修改樣式與級聯(lián)樣式優(yōu)先順序的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-04-04
如何用Vite構(gòu)建工具快速創(chuàng)建Vue項目
Vite是一個web開發(fā)構(gòu)建工具,由于其原生?ES?模塊導(dǎo)入方法,它允許快速提供代碼,下面這篇文章主要給大家介紹了關(guān)于如何用Vite構(gòu)建工具快速創(chuàng)建Vue項目的相關(guān)資料,需要的朋友可以參考下2022-05-05
Vue實現(xiàn)預(yù)覽docx/xlsx/pdf等類型文件功能
這篇文章主要介紹了如何在Vue中實現(xiàn)docx/xlsx/pdf等類型文件預(yù)覽功能,在實現(xiàn)過程中,需要注意文件的格式和轉(zhuǎn)換方式,以及插件和組件的使用方法和注意事項,需要的朋友可以參考下2023-05-05

