23、Electron桌面应用:Electron集成、系统托盘、窗口管理、硬件加速
说实话,WebRTC 做视频会议,大部分时间都在折腾浏览器。但真到了产品化阶段,你会发现——用户要的是一个能双击打开的桌面应用,而不是一个需要输入网址的页面。这时候,Electron 就派上用场了。
我个人习惯把 Electron 看作「浏览器 + Node.js 的合体」。它用 Chromium 渲染界面,用 Node.js 跑本地逻辑。说白了,你写的 WebRTC 代码几乎不用改,就能直接跑在桌面上。但这里有几个坑,我今天跟你聊聊。
Electron 集成:从零到一
先搭个最简单的架子。你肯定已经装好了 Node.js,那咱们直接开干:
mkdir webrtc-desktop
cd webrtc-desktop
npm init -y
npm install electron --save-dev
然后创建一个 main.js,这是 Electron 的主进程入口:
const { app, BrowserWindow } = require('electron')
function createWindow () {
const win = new BrowserWindow({
width: 1280,
height: 720,
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
})
win.loadURL('http://localhost:3000') // 你的 WebRTC 前端地址
}
app.whenReady().then(createWindow)
嗯,这里要注意。我早期做项目时直接把 nodeIntegration 设为 true,结果发现渲染进程能直接调 require('child_process'),这太危险了。生产环境建议用 contextBridge 暴露有限的 API。
系统托盘:让应用常驻后台
视频会议应用最怕什么?用户不小心关掉了窗口,然后会议断了。系统托盘就是解决方案——窗口可以关,但进程还在,用户随时能点回来。
const { Tray, Menu } = require('electron')
let tray = null
app.whenReady().then(() => {
tray = new Tray('icon.png')
const contextMenu = Menu.buildFromTemplate([
{ label: '显示窗口', click: () => mainWindow.show() },
{ label: '静音切换', type: 'checkbox', checked: false },
{ type: 'separator' },
{ label: '退出', click: () => app.quit() }
])
tray.setToolTip('WebRTC 视频会议')
tray.setContextMenu(contextMenu)
})
我曾经踩过一个坑:托盘图标在 macOS 上必须是 22x22 的 @2x 图,否则糊得一塌糊涂。Windows 上倒是随意些,但建议准备 16x16 和 32x32 两套。
窗口管理:别让用户手忙脚乱
多人视频会议里,窗口行为很关键。用户可能同时开着聊天、共享屏幕、参会者列表。如果每个都弹一个新窗口,桌面就乱套了。
我建议用单窗口 + 多视图模式。Electron 的 BrowserView 可以嵌入子视图:
const { BrowserView } = require('electron')
const view = new BrowserView()
mainWindow.setBrowserView(view)
view.setBounds({ x: 0, y: 0, width: 300, height: 600 })
view.webContents.loadURL('https://chat.example.com')
这样所有功能都在一个窗口里,用户只需要拖动分割线调整布局。你想想看,是不是比满屏弹窗舒服多了?
另外,窗口状态要记住。用户调整了大小、位置,下次打开应该恢复原样:
const settings = require('electron-settings')
mainWindow.on('close', () => {
settings.set('windowBounds', mainWindow.getBounds())
})
app.on('ready', () => {
const bounds = settings.get('windowBounds')
if (bounds) mainWindow.setBounds(bounds)
})
硬件加速:性能的隐形杀手
WebRTC 本身就很吃资源,编码解码、渲染视频流,全靠 GPU 撑着。Electron 默认开启了硬件加速,但有时候反而会出问题。
为什么会这样?因为 Electron 的 Chromium 版本和你的显卡驱动可能不兼容。我遇到过几次:用户反馈视频卡顿,一查发现是硬件加速导致渲染崩溃,回退到软件渲染反而流畅了。
你可以这样控制:
app.disableHardwareAcceleration() // 全局关闭
// 或者针对特定窗口
const win = new BrowserWindow({
webPreferences: {
enableWebGL: false,
enableHardwareAcceleration: false
}
})
但别一刀切。我建议在启动时检测 GPU 信息:
const gpuInfo = app.getGPUFeatureStatus()
if (gpuInfo.webgl === 'disabled') {
console.warn('WebGL 不可用,关闭硬件加速')
app.disableHardwareAcceleration()
}
说白了,硬件加速是个好东西,但别迷信它。遇到诡异问题,先关了试试。
知识体系总览
下面这张图帮你理清本章的核心逻辑:
核心要点:Electron 集成的本质是「Web 页面 + 本地能力」。系统托盘保证应用不死,窗口管理让交互不乱,硬件加速决定性能上限。这三者配合好了,你的 WebRTC 桌面应用才算真正能用。
小技巧:调试 Electron 时,可以用 --inspect 参数启动,然后在 Chrome 浏览器里打开 chrome://inspect,就能像调试网页一样调试 Electron 的主进程。我几乎天天用这个。
注意:Electron 打包后的应用体积不小,一个空壳子就 100MB+。如果用户机器配置低,启动速度会慢。建议用 electron-builder 的 asar 压缩,并且按平台分包,别一股脑全塞进去。
好了,这一章就聊到这儿。桌面应用开发是个细致活,尤其是跟 WebRTC 这种实时通信结合,每一步都要稳。你动手试试,有问题随时翻回来看看。