如何在Safari浏览器中通过getDisplayMedia实现屏幕截图?
失效原因
原代码在Safari无法运行核心是两点API兼容问题:
ImageCaptureAPI 目前全版本桌面/移动端Safari都没有原生支持,调用时会直接抛出构造函数未定义的错误- Safari对
getDisplayMedia屏幕共享API有严格的调用校验,非安全上下文、脱离用户主动交互事件栈的调用会被直接拒绝权限
兼容实现方案
弃用Safari不支持的ImageCapture,改用隐藏video元素承接屏幕共享流,等流加载完成后取帧绘制到canvas即可,该方案兼容Safari 13+(目前主流覆盖的Safari版本),同时不影响Chrome、Firefox的运行效果。
console.log('--imageCapture'); const btn = document.querySelector('#btn') btn.addEventListener('click',()=>{ screenshot() }) async function screenshot(){ const canvas = document.createElement("canvas"); // 创建隐藏video承接视频流 const video = document.createElement('video'); video.muted = true; video.playsInline = true; // iOS Safari必填,否则流会触发全屏播放无法取帧 try { // 申请屏幕共享权限,必须在点击事件的直接调用链中触发,不能放到异步回调里延迟调用 const stream = await navigator.mediaDevices.getDisplayMedia({ video: { cursor: 'always' } // 可选配置:是否捕获鼠标光标 }); const track = stream.getVideoTracks()[0]; // 绑定流到video并播放 video.srcObject = stream; await video.play(); // 等待视频元数据加载,拿到准确的宽高 if (video.readyState < 2) { await new Promise(resolve => video.onloadedmetadata = resolve); } // 停止屏幕共享 track.stop(); video.srcObject = null; // 绘制帧到canvas canvas.width = video.videoWidth; canvas.height = video.videoHeight; canvas.getContext('2d').drawImage(video, 0, 0); // 生成截图base64 const frame = canvas.toDataURL("image/png"); // 后续自行处理截图:下载、上传等逻辑都在这里加 } catch (e) { console.log(e); } }
兼容注意事项
- 页面必须运行在HTTPS协议或localhost本地调试环境下,非安全上下文Safari会直接禁用所有媒体设备相关API
getDisplayMedia不能放在setTimeout、接口请求回调等异步延迟逻辑里调用,必须绑定在用户点击、按键等主动交互的同步执行栈中,否则会被Safari判定为非用户主动操作直接拦截- iOS端Safari必须给video元素配置
playsInline属性,否则视频流会强制进入全屏播放模式,无法正常取帧 - Safari目前仅支持整屏、单个应用窗口的共享捕获,不支持Chrome类浏览器的单标签页捕获、标签页音频采集能力,不影响截图功能
- Safari 13以下的旧版本没有开放屏幕共享相关的API,无前端侧技术方案实现自动截图,只能引导用户使用系统快捷键完成截图。
内容的提问来源于stack exchange,提问作者hu hao
相关产品推荐
相关产品推荐

