Manifest V3版Chrome屏幕录制扩展关闭弹窗后后台持续录屏实现咨询
Chrome扩展后台录屏需求
我正在开发一款可实现屏幕/标签页录制功能的Chrome扩展。
现有代码
manifest.json
{ "name": "My Recorer", "version": "1.0", "manifest_version": 3, "background": { "service_worker": "background.js" }, "action": { "default_popup": "popup.html" }, "permissions": ["activeTab", "declarativeContent", "storage","tabs", "desktopCapture"] }
background.js
chrome.runtime.onInstalled.addListener(function (tab) { console.log(tab) })
popup.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div> <button style="width: 100%; margin: 5%;" id="start">Record</button> <button style="width: 100%; margin: 5%" id="stop">stop</button> </div> <script src="popup.js"></script> </body> </html>
popup.js(录屏逻辑实现)
let start = document.getElementById('start'), stop = document.getElementById('stop'), mediaRecorder; start.addEventListener('click', async function(){ console.log("Start") let stream = await recordScreen(); let mimeType = 'video/webm'; mediaRecorder = createRecorder(stream, mimeType); let node = document.createElement("p"); node.textContent = "Started recording"; document.body.appendChild(node); }) stop.addEventListener('click', function(){ mediaRecorder.stop(); let node = document.createElement("p"); node.textContent = "Stopped recording"; document.body.appendChild(node); }) async function recordScreen() { return await navigator.mediaDevices.getDisplayMedia({ audio: true, video: { mediaSource: "screen"} }); }
存在问题
当前扩展的录屏功能可正常运行,但关闭扩展弹窗后,录屏进程会直接终止,已录制的内容也会丢失。需要实现扩展弹窗不可见后仍保持录屏正常运行的后台录屏效果,预期实现效果参考下图:
解决方案
出现该问题的原因是Chrome扩展的popup页面属于临时上下文,关闭后页面会被直接销毁,运行在popup里的录屏逻辑、MediaRecorder实例都会同步被回收。Manifest V3版本可通过offscreenAPI创建常驻后台的离屏页面承载录屏逻辑,实现步骤如下:
- 修改manifest.json,新增
offscreen权限:
// 其余配置保持不变,仅更新permissions字段 "permissions": ["activeTab", "declarativeContent", "storage","tabs", "desktopCapture", "offscreen"]
- 新建离屏页面文件
offscreen.html:
<!DOCTYPE html> <html> <body> <script src="offscreen.js"></script> </body> </html>
- 新建离屏逻辑文件
offscreen.js,承载核心录屏代码:
let mediaRecorder; const recordedChunks = []; // 监听来自后台的消息 chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => { if (message.type === 'start-recording') { const stream = await navigator.mediaDevices.getDisplayMedia({ audio: true, video: { mediaSource: "screen"} }); const mimeType = 'video/webm'; mediaRecorder = new MediaRecorder(stream, { mimeType }); mediaRecorder.ondataavailable = (e) => { if (e.data.size > 0) recordedChunks.push(e.data); }; mediaRecorder.onstop = () => { const blob = new Blob(recordedChunks, { type: mimeType }); const url = URL.createObjectURL(blob); // 自动下载录制好的视频 const a = document.createElement('a'); a.href = url; a.download = `recording_${Date.now()}.webm`; a.click(); URL.revokeObjectURL(url); recordedChunks.length = 0; }; mediaRecorder.start(); } else if (message.type === 'stop-recording') { if (mediaRecorder?.state === 'recording') { mediaRecorder.stop(); mediaRecorder.stream.getTracks().forEach(track => track.stop()); } } });
- 修改
background.js,负责创建离屏页面和转发消息:
async function ensureOffscreenDocument() { const existingContexts = await chrome.runtime.getContexts({ contextTypes: [chrome.runtime.ContextType.OFFSCREEN_DOCUMENT] }); if (existingContexts.length > 0) return; await chrome.offscreen.createDocument({ url: 'offscreen.html', reasons: [chrome.offscreen.Reason.USER_MEDIA], justification: '用于后台录制屏幕内容' }); } chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => { if (message.type === 'start-recording' || message.type === 'stop-recording') { await ensureOffscreenDocument(); chrome.runtime.sendMessage(message); } });
- 修改
popup.js,仅保留按钮交互和消息发送逻辑:
const start = document.getElementById('start'); const stop = document.getElementById('stop'); start.addEventListener('click', async () => { await chrome.runtime.sendMessage({ type: 'start-recording' }); const node = document.createElement("p"); node.textContent = "已开始录制"; document.body.appendChild(node); }); stop.addEventListener('click', async () => { await chrome.runtime.sendMessage({ type: 'stop-recording' }); const node = document.createElement("p"); node.textContent = "已停止录制,视频将自动下载"; document.body.appendChild(node); });
修改后录屏逻辑运行在常驻的离屏页面中,关闭popup不会影响录制进程,停止录制后会自动下载录制好的视频文件。
内容的提问来源于stack exchange,提问作者GMAC
相关产品推荐
相关产品推荐

