Electron应用自动更新回调失效问题排查
Electron自动更新回调无法触发问题
问题描述
我正在为Electron应用实现自动更新功能,但回调函数无法正常工作。控制台日志显示showMessage trapped、Checking for Updates以及Preload,说明代码执行到preload函数为止都正常,但回调函数始终无法触发。
关键代码
updater.ts
export default class Updater { mainWindow: BrowserWindow; constructor(mainWindow: BrowserWindow) { this.mainWindow = mainWindow; } showMessage(message: String) { console.log('showMessage trapped'); console.log(message); this.mainWindow.webContents.send('updateMessage', message); } }
main.ts
const createWindow = () => { mainWindow = new BrowserWindow({ frame: false, show: false, width: 400, height: 600, icon: getAssetPath('icon.png'), webPreferences: { preload: app.isPackaged ? path.join(__dirname, 'preload.js') : path.join(__dirname, '../../.erb/dll/preload.js'), nodeIntegration: true, contextIsolation: true, }, }); mainWindow.on('closed', () => { mainWindow = null; }); mainWindow.webContents.openDevTools({ mode: 'undocked' }); updater = new Updater(mainWindow); }; app .whenReady() .then(() => { createWindow(); app.on('activate', () => { if (mainWindow === null) createWindow(); }); autoUpdater.checkForUpdates(); updater?.showMessage('Checking for Updates'); }) .catch(console.log);
preload.ts
import { contextBridge, ipcRenderer, IpcRendererEvent } from 'electron'; const updateApp = { updateMessage: (callback: any) => { console.log("Preload"); ipcRenderer.on('updateMessage', callback); }, }; contextBridge.exposeInMainWorld('update', updateApp);
App.tsx
export default function App() { let msg:String; useEffect(() => { window.update.updateMessage(updateMessage); }, []); const updateMessage = (e: any, message: String) => { console.log('updateMessageCallback'); console.log(message); console.log('message logged in view'); }; const showPopUp = () => { window.my_modal_1.showModal(); }; return ( <div className="min-h-screen flex flex-col"> <StartingPopUp showPopUp={showPopUp} /> <TitleBar /> <UpdateNotification message={msg} /> <Navbar /> <Logo /> <div className="flex flex-col flex-1 p-6"> <CommandsContainer /> </div> <Progress /> </div> ); }
控制台日志
showMessage trapped Checking for Updates Preload
问题分析与解决
问题出在消息发送时机早于渲染进程注册监听,以及回调函数定义顺序问题,具体修复点如下:
- 调整消息发送时机,确保渲染进程加载完成
main.ts中updater?.showMessage是在窗口创建后立即执行的,但此时渲染进程页面还未加载完成,监听事件还没注册。需要等到页面加载完成后再发送消息:
// 修改createWindow函数 const createWindow = () => { mainWindow = new BrowserWindow({ // 原有配置不变 }); // 等待页面加载完成后执行更新操作 mainWindow.webContents.on('did-finish-load', () => { autoUpdater.checkForUpdates(); updater?.showMessage('Checking for Updates'); }); mainWindow.on('closed', () => { mainWindow = null; }); mainWindow.webContents.openDevTools({ mode: 'undocked' }); updater = new Updater(mainWindow); }; // 移除app.whenReady中的autoUpdater和showMessage调用 app .whenReady() .then(() => { createWindow(); app.on('activate', () => { if (mainWindow === null) createWindow(); }); }) .catch(console.log);
- 修复React中回调函数的定义顺序
App.tsx中useEffect调用时,updateMessage函数还未完成初始化,导致传入的是undefined。需要先定义回调函数再注册监听:
export default function App() { let msg:String; // 先定义回调函数 const updateMessage = (e: any, message: String) => { console.log('updateMessageCallback'); console.log(message); console.log('message logged in view'); }; // 再注册监听 useEffect(() => { window.update.updateMessage(updateMessage); // 组件卸载时移除监听,避免内存泄漏 return () => { ipcRenderer.removeListener('updateMessage', updateMessage); }; }, []); // 其余代码不变 }
- 在preload中补充移除监听的方法
为避免内存泄漏,需要在preload中暴露移除监听的接口:
import { contextBridge, ipcRenderer, IpcRendererEvent } from 'electron'; const updateApp = { updateMessage: (callback: (event: IpcRendererEvent, message: string) => void) => { console.log("Preload"); ipcRenderer.on('updateMessage', callback); }, removeUpdateListener: (callback: (event: IpcRendererEvent, message: string) => void) => { ipcRenderer.removeListener('updateMessage', callback); } }; contextBridge.exposeInMainWorld('update', updateApp);
- 改用useState管理消息状态
原代码中msg是普通变量,React无法监听其变化更新UI,需要替换为useState:
import { useState, useEffect } from 'react'; export default function App() { const [msg, setMsg] = useState<string>(''); const updateMessage = (e: any, message: string) => { console.log('updateMessageCallback'); console.log(message); console.log('message logged in view'); setMsg(message); }; // 其余代码不变 }
完成以上修改后,回调函数即可正常触发,UI也会同步更新消息内容。
内容的提问来源于stack exchange,提问作者Chamindu Vidyarathne
相关产品推荐
相关产品推荐

