一、系统托盘(Tray)核心技术解析
1.1 多平台托盘体系架构
1.1.1 不同系统的实现差异
平台 图标尺寸规范 交互特性 上下文菜单位置 Windows 16x16 ~ 24x24 像素 左键单击触发主事件 图标正下方 macOS 22x22 像素(Retina) 强制右键显示菜单 跟随光标位置 Linux 24x24 像素 依赖桌面环境实现 各发行版差异较大
1.2 现代托盘功能演进
Electron 15+ 版本的核心改进:
高分辨率图标支持(SVG/多倍图) 动态菜单项更新(无需重建整个菜单) 托盘气泡通知的增强API 深色模式自动适配
import { Tray, Menu, nativeImage } from 'electron' const trayIcon = nativeImage. createFromPath ( 'icon.png' ) . resize ( { width: 16 , height: 16 } )
const appTray = new Tray ( trayIcon) const contextMenu = Menu. buildFromTemplate ( [ { label: '显示主窗口' , click : ( ) => mainWindow. show ( ) } , { type : 'separator' } , { label: '退出' , role: 'quit' }
] ) appTray. setContextMenu ( contextMenu)
二、高级托盘功能开发
2.1 动态图标与状态指示
2.1.1 实时图标更新
function updateTrayIcon ( usage: number ) { const canvas = createCanvas ( 16 , 16 ) const ctx = canvas. getContext ( '2d' ) ctx. beginPath ( ) ctx. arc ( 8 , 8 , 7 , 0 , 2 * Math. PI * usage) ctx. strokeStyle = '#4CAF50' ctx. lineWidth = 2 ctx. stroke ( ) appTray. setImage ( canvas. toDataURL ( ) )
} setInterval ( ( ) => { const usage = getCPUUsage ( ) updateTrayIcon ( usage)
} , 1000 )
2.1.2 多状态动画
class TrayAnimator { private frames: NativeImage[ ] = [ ] private currentFrame = 0 constructor ( framesPath: string [ ] ) { this . frames = framesPath. map ( p => nativeImage. createFromPath ( p) ) } start ( ) { setInterval ( ( ) => { appTray. setImage ( this . frames[ this . currentFrame] ) this . currentFrame = ( this . currentFrame + 1 ) % this . frames. length} , 100 ) }
}
const animator = new TrayAnimator ( [ 'frame1.png' , 'frame2.png' , 'frame3.png' ] )
animator. start ( )
2.2 交互事件深度处理
2.2.1 复合事件绑定
appTray. on ( 'click' , ( event, bounds) => handleTrayClick ( event, bounds) ) . on ( 'double-click' , ( ) => toggleMainWindow ( ) ) . on ( 'right-click' , ( ) => showContextMenu ( ) ) . on ( 'drop-files' , ( _, files) => handleFileDrop ( files) )
2.2.2 拖放功能集成
appTray. setIgnoreDoubleClickEvents ( true ) appTray. on ( 'drop-files' , ( event, files) => { if ( files. some ( f => f. endsWith ( '.txt' ) ) ) { processTextFiles ( files) }
} )
三、屏幕捕捉(Capturer)核心技术
3.1 屏幕捕捉模式对比
捕捉模式 API 适用场景 性能影响 全屏静态截图 desktopCapturer.getSources 快速截图 低 窗口实时流 navigator.mediaDevices.getUserMedia 录屏/直播 中 指定区域捕捉 结合DOM元素与流媒体 区域录制 高
3.2 静态截图实现方案
3.2.1 基础截图功能
import { desktopCapturer } from 'electron' async function captureFullScreen ( ) { const sources = await desktopCapturer. getSources ( { types: [ 'screen' ] , thumbnailSize: { width: 1920 , height: 1080 } } ) const primaryScreen = sources. find ( s => s. name === 'Entire Screen' ) if ( primaryScreen) { fs. writeFileSync ( 'screenshot.png' , primaryScreen. thumbnail. toPNG ( ) ) }
}
3.2.2 多显示器支持
const captureOptions = { types: [ 'screen' ] , thumbnailSize: { width: screen. getPrimaryDisplay ( ) . size. width, height: screen. getPrimaryDisplay ( ) . size. height}
} desktopCapturer. getSources ( captureOptions) . then ( sources => { sources. forEach ( ( source, index) => { fs. writeFileSync ( ` screen_ ${ index} .png ` , source. thumbnail. toPNG ( ) ) } )
} )
四、实时屏幕捕捉与流处理
4.1 流媒体捕捉实现
4.1.1 窗口流捕获
async function startCapture ( ) { const constraints = { audio: false , video: { mandatory: { chromeMediaSource: 'desktop' , chromeMediaSourceId: await getSourceId ( ) } } } const stream = await navigator. mediaDevices. getUserMedia ( constraints) const videoElement = document. getElementById ( 'preview' ) videoElement. srcObject = stream
} async function getSourceId ( ) { const sources = await desktopCapturer. getSources ( { types: [ 'window' , 'screen' ] } ) return sources[ 0 ] . id
}
4.2.2 帧处理优化
const video = document. querySelector ( 'video' )
const canvas = document. createElement ( 'canvas' )
const ctx = canvas. getContext ( '2d' ) video. addEventListener ( 'play' , ( ) => { function processFrame ( ) { canvas. width = video. videoWidthcanvas. height = video. videoHeightctx. drawImage ( video, 0 , 0 ) const imageData = ctx. getImageData ( 0 , 0 , canvas. width, canvas. height) if ( ! video. paused) requestAnimationFrame ( processFrame) } requestAnimationFrame ( processFrame)
} )
五、企业级集成方案
5.1 录屏工具开发实践
5.1.1 媒体录制核心
const chunks: Blob[ ] = [ ]
const mediaRecorder = new MediaRecorder ( stream, { mimeType: 'video/webm; codecs=vp9' , bitsPerSecond: 2500000
} ) mediaRecorder. ondataavailable = ( e) => { chunks. push ( e. data)
} mediaRecorder. onstop = ( ) => { const blob = new Blob ( chunks, { type : 'video/webm' } ) saveFile ( blob)
}
appTray. on ( 'click' , ( ) => { if ( mediaRecorder. state === 'recording' ) { mediaRecorder. stop ( ) } else { mediaRecorder. start ( 1000 ) }
} )
5.2 智能截图工具架构
区域选择
全屏截图
托盘点击事件
模式判断
激活DOM遮罩层
调用desktopCapturer
鼠标事件监听
计算选择区域
像素数据裁剪
保存/编辑图片
六、性能优化与安全加固
6.1 资源管理策略
优化方向 实现方案 效果提升 内存优化 使用SharedArrayBuffer 减少30%内存占用 CPU占用优化 动态调整捕捉帧率 降低40%CPU使用 存储优化 实时压缩算法 节省50%磁盘空间
6.2 安全增强方案
6.2.1 权限控制
ipcMain. handle ( 'request-capture' , ( event) => { if ( checkPermission ( 'screen-capture' ) ) { return desktopCapturer. getSources ( options) } else { dialog. showErrorBox ( '权限不足' , '需要屏幕捕捉权限' ) throw new Error ( 'Permission denied' ) }
} )
6.2.2 数据加密
function encryptScreenshot ( data: Buffer) { const iv = crypto. randomBytes ( 16 ) const cipher = crypto. createCipheriv ( 'aes-256-cbc' , SECRET_KEY , iv) return Buffer. concat ( [ iv, cipher. update ( data) , cipher. final ( ) ] )
}
七、跨平台兼容性处理
7.1 平台特性适配
7.1.1 macOS权限处理
function checkScreenCapturePermission ( ) { if ( process. platform !== 'darwin' ) return true const status = systemPreferences. getMediaAccessStatus ( 'screen' ) return status === 'granted'
}
if ( ! checkScreenCapturePermission ( ) ) { systemPreferences. askForMediaAccess ( 'screen' )
}
7.2 Linux桌面环境适配
桌面环境 兼容方案 已知问题 GNOME 使用org.gnome.Shell接口 需要用户手动授权 KDE Plasma 通过DBus接口调用 多显示器支持不完善 Xfce 依赖xrandr工具 无法获取窗口标题
八、调试与测试方案
8.1 自动化测试策略
describe ( '屏幕捕捉测试' , ( ) => { let window: BrowserWindowbefore ( ( ) => { window = new BrowserWindow ( { show: false } ) } ) it ( '应成功获取屏幕源' , async ( ) => { const sources = await desktopCapturer. getSources ( { types: [ 'screen' ] } ) assert ( sources. length > 0 ) } )
} )
8.2 性能监控工具
const perfHook = require ( 'electron-performance-hook' ) perfHook. monitor ( 'desktopCapturer' , { onStart : ( id) => console . time ( ` capture- ${ id} ` ) , onEnd : ( id) => console . timeEnd ( ` capture- ${ id} ` )
} )
结语:构建专业级桌面应用
通过本文的深度实践,开发者可以掌握:
托盘功能的精细化控制 高性能屏幕捕捉方案 企业级录屏工具架构 跨平台兼容性解决方案
建议进一步探索:
GPU加速渲染优化 基于WebCodecs的底层编解码 与AI模型的集成(如实时物体识别)