一、系统托盘(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. videoWidth
canvas. height = video. videoHeight
ctx. 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: BrowserWindow
before ( ( ) => {
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模型的集成(如实时物体识别)