Electron 升级到 45 后 getDisplayMedia 屏幕共享失效怎么排查【免费下载链接】electron:electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS项目地址: https://gitcode.com/GitHub_Trending/el/electron应用升级到 Electron 45 之后页面里navigator.mediaDevices.getDisplayMedia()拿不到屏幕共享流这是 Electron 45 破坏性变更文档中明确记录的行为变化屏幕捕获类权限请求在session.setPermissionRequestHandler中的上报方式从media改成了display-capture。如果你的应用自定义了权限处理逻辑升级后屏幕共享失效基本都出在这一处。本文按 Electron 仓库中 breaking-changes.md、session.md 和 desktop-capturer.md 的说明给出一条从权限处理到流回传的排查路径。45 版本改了什么屏幕捕获请求改报display-capture按 45.0 的破坏性变更说明通过navigator.mediaDevices.getDisplayMedia()发起的捕获请求以及通过getUserMedia()配合chromeMediaSource/chromeMediaSourceId约束发起的请求即 desktopCapturer 文档描述的方式现在都以display-capture权限类型传给session.setPermissionRequestHandler。45 之前这些请求被上报为media且details.mediaTypes是空数组只能靠这个空数组和摄像头/麦克风请求区分。升级后media只用于摄像头和麦克风设备。display-capture请求的details是 MediaAccessPermissionRequest 结构其中mediaTypes会列出video和/或audio表示请求的是屏幕视频和/或屏幕音频。变更文档直接点明了失效场景如果你的权限请求处理器“放行media、拒绝其他所有权限”那么屏幕共享在 45 上会被一并拒绝。display-capture的 Permissions-Policy 响应头从 45 起也应用到带chromeMediaSource约束的getUserMedia()调用上默认允许列表是self跨域iframe用这种方式捕获屏幕需要在 iframe 元素上加allowdisplay-capture。setDisplayMediaRequestHandler的流程本身没有变仍然在权限请求被放行之后才执行。第一步检查是否自定义了权限请求处理器这是判断问题是否由 45 的行为变化引起的分叉点。如果应用没有调用过setPermissionRequestHandler或setPermissionCheckHandler没有走自定义权限逻辑那么display-capture这个变更不是失效原因直接跳到“平台侧的已知限制”一节检查系统权限。如果应用有自定义处理器重点看它的放行条件是否覆盖了display-capture。典型的失效代码是只放行media// 升级前能工作升级到 45 后屏幕共享被拒绝 session.defaultSession.setPermissionRequestHandler((webContents, permission, callback) { if (permission media) { return callback(true) } callback(false) // display-capture 在这里被拒绝了 })修复方式是按 45.0 变更文档给出的示例在处理器中同时放行media和display-capturesession.defaultSession.setPermissionRequestHandler((webContents, permission, callback, details) { if (permission media || permission display-capture) { return callback(true) } callback(false) })session.md中还给出了按来源区分处理的写法比如只对指定站点放行屏幕捕获session.defaultSession.setPermissionRequestHandler((webContents, permission, callback, details) { if (permission media) { return callback(true) } if (permission display-capture) { return callback(new URL(details.requestingUrl).origin https://meet.example.com) } callback(false) })按自己的信任边界改写上面示例的放行条件即可。第二步检查setPermissionCheckHandlersession.md对权限机制的说明是大多数 Web API 会先做一次权限检查permission check检查被拒绝后才会发起权限请求permission request并且文档明确要求“要获得完整的权限处理必须同时实现setPermissionCheckHandler”。setPermissionCheckHandler的permission参数列表里同样包含display-capture对应 Screen Capture API。它的处理函数返回true表示允许、返回false表示拒绝。如果你的检查处理器对display-capture一律返回false屏幕捕获同样过不了权限这一关表现和第一步的拒绝一样。排查时把两处 handler 的日志一起打出来确认session.defaultSession.setPermissionCheckHandler((webContents, permission, requestingOrigin) { console.log(permission check:, permission, requestingOrigin) return true // 示例按实际信任边界改 }) session.defaultSession.setPermissionRequestHandler((webContents, permission, callback, details) { console.log(permission request:, permission, details.mediaTypes) if (permission media || permission display-capture) { return callback(true) } callback(false) })在触发一次getDisplayMedia()时如果日志里看到权限类型是display-capture说明请求确实走完了权限上报问题不在这一层继续下一步。第三步确认setDisplayMediaRequestHandler正常回传流权限放行之后Electron 才会调用setDisplayMediaRequestHandler注册的处理器由它决定把哪个流交给页面。如果前两步都正常但页面上仍然拿不到流检查这个处理器是否注册、回调是否用desktopCapturer.getSources的结果调用了callback。desktop-capturer.md文档中的完整示例// main.js const { app, BrowserWindow, desktopCapturer, session } require(electron) app.whenReady().then(() { const mainWindow new BrowserWindow() session.defaultSession.setDisplayMediaRequestHandler((request, callback) { desktopCapturer.getSources({ types: [screen] }).then((sources) { // 授权第一个找到的屏幕。 callback({ video: sources[0], audio: loopback }) }) // 可选实验项可用时改用系统选择器。 // 注意目前为实验功能。若系统选择器可用它会被使用 // 上面的媒体请求处理器不会被调用。 }, { useSystemPicker: true }) mainWindow.loadFile(index.html) })// renderer.js const startButton document.getElementById(startButton) const video document.querySelector(video) startButton.addEventListener(click, () { navigator.mediaDevices.getDisplayMedia({ audio: true, video: { width: 320, height: 240, frameRate: 30 } }).then(stream { video.srcObject stream video.onloadedmetadata (e) video.play() }).catch(e console.log(e)) })!-- index.html -- html body button idstartButtonStart/button video width320 height240 autoplay/video script srcrenderer.js/script /body /html注意两点useSystemPicker: true是实验选项目前仅 macOS 15 可用如果系统选择器可用且该选项为truesetDisplayMediaRequestHandler的回调不会被调用。排查时建议先不带这个选项确认自定义回调确实被触发。如果回调里callback(null)页面侧就拿不到流确认getSources有返回源、且回调参数包含video。验证方式按上面的renderer.js触发一次捕获即可验证修复效果点击 Start 后getDisplayMedia()的 Promise 以MediaStream解析video.srcObject赋值后视频开始播放说明权限上报、检查、setDisplayMediaRequestHandler回传这条链都通了。在权限 handler 的日志里确认请求类型已变为display-capture且details.mediaTypes按请求内容列出video和/或audio与 MediaAccessPermissionRequest 结构一致。如果 Promise 被拒绝catch有输出而 handler 日志里权限是callback(false)回到第一、二步检查放行条件。平台侧的已知限制权限放行后仍拿不到流的场景权限逻辑都正确但流仍异常时按 desktopCapturer 文档的 Caveats 一节核对系统权限macOS 10.15 及以上捕获屏幕内容需要用户同意可以用systemPreferences.getMediaAccessStatus检测状态。macOS 14.2 及以上捕获音频必须在Info.plist中加入NSAudioCaptureUsageDescription键从终端或 IDE 直接运行 Electron 时这个键要加在父程序终端/IDE上因为系统把该权限记在负责进程上。缺失或被拒绝时的失效是静默的desktopCapturer仍会产生一条音频轨但该轨处于ended状态、永不产生数据JavaScript 侧看不到任何警告或错误。macOS 14.2 及以上的旧回退开关已失效Electron 39–44 可以通过app.commandLine.appendSwitch(disable-features, MacCatapLoopbackAudioForScreenShare)回退到旧的系统音频捕获路径但该 feature flag 在 Electron 45 已从上游移除、不再有任何效果。如果升级前靠这个开关工作升级后必须补NSAudioCaptureUsageDescription。LinuxPipeWiredesktopCapturer.getSources在 PipeWire 下只返回一个源同时请求 window 和 screen 类型时选中源会按窗口捕获返回。另按文档说明getDisplayMedia不允许用deviceId约束选择源见 W3C 规范如果你的约束对象里带了deviceId取流失败也与此有关。以上路径覆盖了 45 升级场景文档记录的全部相关变化权限上报类型、Permissions-Policy 的 iframe 限制、系统选择器实验行为以及 macOS 音频权限的静默失效。排查顺序就是先确认是否命中display-capture变更再依次核对两个权限 handler 和setDisplayMediaRequestHandler最后才是操作系统层面的权限。【免费下载链接】electron:electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS项目地址: https://gitcode.com/GitHub_Trending/el/electron创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考