Chrome扩展Manifest V3中二维码识别的脚本通信与API调用问题
解决Manifest 3下Chrome扩展二维码识别的跨脚本权限问题
核心思路是拆分功能到不同权限的脚本:
- Content Script:负责定位页面中的二维码元素,获取裁剪坐标
- Background Service Worker:调用
tabs.captureVisibleTab截图,作为消息中转 - Offscreen Document:处理图片裁剪与二维码解析(拥有DOM访问权限,可使用canvas和QRCode库)
1. 配置Manifest.json
确保声明所需权限和脚本入口:
{ "manifest_version": 3, "name": "二维码识别工具", "version": "1.0", "permissions": ["tabs", "activeTab", "offscreen"], "background": { "service_worker": "background.js" }, "content_scripts": [ { "matches": ["<all_urls>"], "js": ["content.js"] } ], "offscreen": { "matches": ["<all_urls>"], "default_path": "offscreen.html" } }
2. Content Script (content.js)
负责触发识别、获取元素坐标,给Background发消息:
// 示例:假设用户点击页面中的二维码元素触发识别 document.addEventListener('click', async (e) => { // 这里替换成你的二维码元素判断逻辑 if (e.target.classList.contains('qr-code')) { const rect = e.target.getBoundingClientRect(); // 发送坐标和当前tab信息给Background chrome.runtime.sendMessage({ type: 'CAPTURE_QR', tabId: (await chrome.tabs.getCurrent()).id, left: rect.left, top: rect.top, width: rect.width, height: rect.height }); } }); // 接收Background返回的解析结果 chrome.runtime.onMessage.addListener((msg) => { if (msg.type === 'QR_RESULT') { console.log('解析结果:', msg.data); // 这里可以处理结果,比如弹窗展示 } });
3. Background Service Worker (background.js)
处理截图请求,管理Offscreen文档,中转消息:
// 确保Offscreen文档已创建 async function ensureOffscreenDocument() { if (await chrome.offscreen.hasDocument()) return; await chrome.offscreen.createDocument({ url: 'offscreen.html', reasons: ['DOM_SCRAPING'], justification: '解析二维码需要DOM环境处理图片' }); } // 监听Content Script的消息 chrome.runtime.onMessage.addListener(async (msg, sender) => { if (msg.type === 'CAPTURE_QR') { await ensureOffscreenDocument(); // 调用截图API chrome.tabs.captureVisibleTab(sender.tab.windowId, { format: 'png' }, async (dataUrl) => { // 把截图和裁剪参数发给Offscreen chrome.runtime.sendMessage({ type: 'PROCESS_QR', dataUrl, left: msg.left, top: msg.top, width: msg.width, height: msg.height, tabId: msg.tabId }); }); } }); // 接收Offscreen返回的解析结果,转发给Content Script chrome.runtime.onMessage.addListener((msg) => { if (msg.type === 'QR_RESULT') { chrome.tabs.sendMessage(msg.tabId, { type: 'QR_RESULT', data: msg.data }); } });
4. Offscreen相关文件
offscreen.html
<!DOCTYPE html> <html> <body> <script src="qrcode.min.js"></script> <!-- 引入QRCode解析库 --> <script src="offscreen.js"></script> </body> </html>
offscreen.js
负责图片裁剪和二维码解析:
chrome.runtime.onMessage.addListener(async (msg) => { if (msg.type === 'PROCESS_QR') { const { dataUrl, left, top, width, height, tabId } = msg; const img = new Image(); img.src = dataUrl; img.onload = () => { // 创建canvas裁剪指定区域 const canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; const ctx = canvas.getContext('2d'); ctx.drawImage(img, left, top, width, height, 0, 0, width, height); // 解析二维码 const qrReader = new QRCode(); qrReader.callback = (error, result) => { if (error) { console.error('解析失败:', error); chrome.runtime.sendMessage({ type: 'QR_RESULT', tabId, data: null }); } else { chrome.runtime.sendMessage({ type: 'QR_RESULT', tabId, data: result }); } }; qrReader.decode(canvas.toDataURL()); }; } });
关键说明
- 为什么用Offscreen?因为Background是Service Worker,无DOM环境;Content Script不能调用
tabs.captureVisibleTab;Offscreen是唯一同时拥有DOM访问和消息传递能力的环境。 - 权限注意:
activeTab权限确保只在用户交互时访问当前标签,offscreen权限用于创建Offscreen文档。 - 原
getQr函数的问题:混合了需要tabs权限的截图操作和需要DOM的canvas操作,拆分后各脚本各司其职。
内容的提问来源于stack exchange,提问作者Juan Rodriguez
相关产品推荐
相关产品推荐

