由于electron环境下无法直接调用webrtc来获取屏幕流,因此需要调用者自己稍作处理,具体做法如下。
获取设备窗口
调用相关的API获取设备的窗口,主线程发送一个IPC消息handle。
// electron主线程
import { desktopCapturer, webContents } from "electron";
// 修复electron18.0.0-beta.5 之后版本的BUG: 无法获取当前程序页面视频流
const selfWindws = async () =>
await Promise.all(
webContents
.getAllWebContents()
.filter(item => {
const win = BrowserWindow.fromWebContents(item);
return win && win.isVisible();
})
.map(async item => {
const win = BrowserWindow.fromWebContents(item);
const thumbnail = await win?.capturePage();
// 当程序窗口打开DevTool的时候 也会计入
return {
name:
win?.getTitle() + (item.devToolsWebContents === null ? "" : "-dev"), // 给dev窗口加上后缀
id: win?.getMediaSourceId(),
thumbnail,
display_id: "",
appIcon: null
};
})
);
// 获取设备窗口信息
ipcMain.handle("IPC消息名称", async (_event, _args) => {
return [
...(await desktopCapturer.getSources({ types: ["window", "screen"] })),
...(await selfWindws())
];
});
渲染线程
渲染线程(前端)发送消息封装处理(相应写法自己调整)。
// xxx.ts
export const getDesktopCapturerSource = async () => {
return await window.electron.ipcRenderer.invoke<Electron.DesktopCapturerSource[]>("IPC消息名称", []);
}
获取媒体流
获取指定窗口的媒体流。
// yyy.ts
function getScreenSizeInfo() {
// 指定宽高可以使图片高清,scaleFactor屏幕的缩放因子,高分屏这个值会大于1
const { size, scaleFactor } = screen.getPrimaryDisplay();
return {
width: size.width * scaleFactor,
height: size.height * scaleFactor
}
}
export function getInitStream(source: any): Promise<MediaStream | null> {
const sizeInfo = getScreenSizeInfo();
return new Promise((resolve, _reject) => {
// 获取指定窗口的媒体流
// 此处遵循的是webRTC的接口类型 暂时TS类型没有支持 只能断言成any
(navigator.mediaDevices as any).getUserMedia({
audio: false,
video: {
mandatory: {
chromeMediaSource: 'desktop',
chromeMediaSourceId: source.id,
minWidth: sizeInfo.width,
maxWidth: sizeInfo.width,
minHeight: sizeInfo.height,
maxHeight: sizeInfo.height,
},
}
}).then((stream: MediaStream) => {
resolve(stream);
}).catch((error: any) => {
console.log(error);
resolve(null);
})
});
}
获取设备窗口信息
前端调用设备窗口信息。
import { getDesktopCapturerSource } from "xxx.ts";
import { getInitStream } from "yyy.ts";
import ScreenShot from "js-web-screen-shot";
export const doScreenShot = async ()=>{
// 下面这两块自己考虑
const sources = await getDesktopCapturerSource(); // 这里返回的是设备上的所有窗口信息
// 这里可以对`sources`数组下面id进行判断 找到当前的electron窗口 这里为了简单直接拿了第一个
const stream = await getInitStream(sources[0]);
new ScreenShot({
enableWebRtc: true, // 启用webrtc
screenFlow: stream!, // 传入屏幕流数据
level: 999,
});
}
编写Mac软件
当你需要开发MacOS端应用时,系统顶部存在标题栏,js无法正确获取到标题栏的高度,会导致工具栏展示不完整,如下图所示:
为了解决此问题,插件提供了menuBarHeight
参数,用于指定标题栏高度。
import ScreenShot from "js-web-screen-shot";
new ScreenShot({
menuBarHeight: 22
});
在electron环境中没有API来获取这个高度,此处提供一些参考值(根据自己的实际情况进行微调):
场景 | 菜单栏高度(逻辑像素) | 说明 |
---|---|---|
普通分辨率非 Retina 显示器 | 22pt | 最常见的标准高度 |
Retina 显示器 | 22pt(实际像素是 44px) | Retina 显示器下缩放倍率为 2,视觉尺寸不变但像素是两倍 |
开启「放大」/ 缩放显示(HiDPI 模式) | 24pt+ | 使用「放大文本」或非原生分辨率时,系统会调整菜单栏高度 |
刘海屏 MacBook(如 M1/M2 Pro) | 24pt+ | 刘海下菜单栏实际显示区域变高以避开摄像头(比如 macOS Monterey 开始) |
Accessibility 启用大字号 | 24pt+ | 系统辅助功能或调整字体大小设置可能使菜单栏高度增加 |
示例代码
如果你看完本页的使用方法,依然不是很理解的话,这里准备了一份在electron环境下使用本插件的demo,请移步electron-js-web-screen-shot-demo。