Electron Linux桌面应用:获取desktopCapturer源更多信息的方法问询
问题背景
我正在Linux平台开发一款Electron桌面应用,已实现全屏/单屏截图功能,核心截图代码如下:
function getMainSource(desktopCapturer, screen, done) { let options = { types: ['window', 'screen'], thumbnailSize: screen.workAreaSize }; desktopCapturer .getSources(options) .then(sources => { for (const thisSource of sources) { console.log(`SOURCE NAME (${thisSource.id}) ::`, thisSource.name); } const isMainSource = s => s.name === 'Entire Screen' || s.name === 'Screen 1' || s.name === 'Entire screen'; console.log(`isMainSource => `,sources); done(sources.filter(isMainSource)[0]); //done(sources[3]); }) .catch(err => { return console.log('cannot capture screen:', err); }); }
但desktopCapturer.getSources()返回的源对象仅包含name、id、thumbnail、display_id、appIcon这5个属性,示例如下:
{ name: 'Landing Page- Project.docx - LibreOffice Writer', id: 'window:117440667:0', thumbnail: NativeImage { .... ... }, display_id: '', appIcon: null }
其中name仅为窗口标题,无法始终提供准确的应用信息,希望获取每个应用的更多信息(如精确应用名、浏览器URL)。
解决方案
一、Electron结合系统命令补充信息
1. 提取窗口ID关联进程信息
从desktopCapturer返回的id中拆分出窗口ID(格式为window:<windowId>:<screenId>),再通过Linux系统命令获取对应进程的应用名:
const { execSync } = require('child_process'); // 从源ID中提取窗口ID function extractWindowId(sourceId) { return sourceId.split(':')[1]; } // 通过窗口ID获取进程ID function getPidByWindowId(windowId) { try { const output = execSync(`xprop -id ${windowId} _NET_WM_PID`).toString(); return output.trim().split(' ')[2]; } catch (err) { console.error('获取进程ID失败:', err); return null; } } // 通过进程ID获取精确应用名 function getAppNameByPid(pid) { try { return execSync(`ps -p ${pid} -o comm=`).toString().trim(); } catch (err) { console.error('获取应用名失败:', err); return null; } }
在你的截图逻辑中,可直接调用这些方法为每个源补充信息:
.then(sources => { const enrichedSources = sources.map(source => { const windowId = extractWindowId(source.id); const pid = getPidByWindowId(windowId); const appName = pid ? getAppNameByPid(pid) : null; return { ...source, pid, appName }; }); // 后续处理逻辑,例如筛选主屏幕源 const mainSource = enrichedSources.filter(s => s.name === 'Entire Screen' || s.name === 'Screen 1' || s.name === 'Entire screen' )[0]; done(mainSource); })
2. 获取浏览器标签页URL(Chrome/Chromium系)
针对Chrome或Chromium浏览器窗口,可通过远程调试接口获取当前标签页URL。需要确保浏览器启动时开启了远程调试端口(如--remote-debugging-port=9222),然后通过HTTP请求获取信息:
const axios = require('axios'); async function getChromeTabUrl(pid) { try { // 从进程参数中提取远程调试端口 const cmdline = execSync(`cat /proc/${pid}/cmdline`).toString().split('\0'); const debugPortArg = cmdline.find(arg => arg.startsWith('--remote-debugging-port=')); if (!debugPortArg) return null; const port = debugPortArg.split('=')[1]; // 获取所有标签页数据 const tabs = await axios.get(`http://localhost:${port}/json/list`); // 匹配对应窗口的标签页(这里简化取第一个,可结合窗口ID进一步筛选) return tabs.data[0].url; } catch (err) { console.error('获取Chrome URL失败:', err); return null; } }
二、纯Linux Shell脚本方案
如果需要批量获取窗口与应用的关联信息,可编写Shell脚本,再通过Electron的child_process模块调用:
#!/bin/bash # 遍历所有窗口,输出窗口ID、标题、进程ID、应用名 wmctrl -l | while read -r windowId _ _ title; do pid=$(xprop -id "$windowId" _NET_WM_PID | awk '{print $3}') appName=$(ps -p "$pid" -o comm=) echo "$windowId|$title|$pid|$appName" done
在Electron中调用并解析结果:
const { exec } = require('child_process'); exec('./window-info.sh', (err, stdout) => { if (err) { console.error('执行脚本失败:', err); return; } const windowInfos = stdout.trim().split('\n').map(line => { const [windowId, title, pid, appName] = line.split('|'); return { windowId, title, pid, appName }; }); // 将解析结果与desktopCapturer的源关联 });
三、注意事项
- 上述方法依赖Linux系统工具(
xprop、wmctrl、ps),可通过sudo apt install x11-utils wmctrl安装。 - 浏览器URL获取仅对支持远程调试的浏览器有效,且需要用户浏览器开启对应端口,适合可控场景。
- 不同Linux桌面环境(GNOME/KDE/Xfce)的窗口属性可能存在差异,需根据实际环境适配。
内容的提问来源于stack exchange,提问作者Maninder Singh
相关产品推荐
相关产品推荐

