Chrome扩展activeTab权限跨域页面onUpdate执行脚本时失效问题
我的背景脚本通过chrome.tabs.onUpdated监听页面加载完成(changeInfo.status === 'complete'),从local storage检查录制状态,若为true则注入reloaded.js。reloaded.js会打开包含test.js的test.html iframe,test.js直接调用tabCapture进行屏幕录制。
当用户在https://example.com启动扩展后导航到https://example.com/foo时一切正常,但跳转到https://chromium.org时权限被收回,触发报错:
Unchecked runtime.lastError: Extension has not been invoked for the current page (see activeTab permission). Chrome pages cannot be captured
调研后发现:当URL从原域名变更到其他域名且用户未在新页面触发扩展操作时,activeTab权限无法生效。请问该如何解决?
附带代码
manifest.json
{ "manifest_version": 3, "name": "Appoq", "version": "1.0", "description": "Description of my extension", "permissions": ["scripting", "activeTab", "tabs", "tabCapture", "storage"], "action": { "default_popup": "popup.html", "default_title": "Click Me" }, "background": { "service_worker": "background.js" }, "host_permissions": ["<all_urls>"], "web_accessible_resources": [ { "resources": [ "tabcapture.html", "/reload/test.html" ], "matches": [ "<all_urls>" ] } ] }
background.js
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) { if (changeInfo.status === 'complete') { chrome.storage.local.get('sharingEnabled', function(result) { if (result.sharingEnabled == 'recording') { chrome.scripting.executeScript({ target: { tabId: tabId }, files: ['reloaded.js'], }, () => {}); } }) } })
test.js
chrome.tabs.query({ active: true, currentWindow: true }, function(tabsw) { const currentTabId = tabsw[0].id; console.log("Current tab ID is: " + currentTabId); chrome.tabCapture.getMediaStreamId({ consumerTabId: currentTabId }, (streamId) => { console.log(streamId) chrome.scripting.executeScript({ files: ["content.js"], target: {tabId: currentTabId} }, function () { chrome.tabs.sendMessage(currentTabId, {reloadStreamId: streamId, hello: "getReloadStreamId"}); }); }); });
解决方案
方法1:请求全局页面权限(简单但不推荐)
将activeTab权限替换为<all_urls>,添加到permissions数组中。这样扩展对所有页面拥有持久权限,无需用户触发即可操作。但缺点是权限范围过大,不符合最小权限原则,可能导致审核不通过。
方法2:通过用户交互重新获取activeTab权限
当检测到跨域名跳转且录制状态为开启时,引导用户主动触发扩展操作以重新获取权限:
- 在
background.js中,对比当前页面域名与上次存储的域名,判断是否跨域名跳转。如果是,设置扩展图标徽章提示用户点击。 - 在
popup.js中监听用户点击事件,此时因用户主动交互,activeTab权限会被授予当前页面,重新执行录制逻辑。
修改后的background.js示例:
chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => { if (changeInfo.status === 'complete') { const { sharingEnabled } = await chrome.storage.local.get('sharingEnabled'); if (sharingEnabled === 'recording') { const { lastDomain } = await chrome.storage.local.get('lastDomain'); const currentDomain = new URL(tab.url).hostname; if (lastDomain && lastDomain !== currentDomain) { chrome.action.setBadgeText({ tabId, text: '!' }); chrome.action.setTitle({ tabId, title: '点击重新激活录制' }); } else { await chrome.scripting.executeScript({ target: { tabId }, files: ['reloaded.js'], }); } await chrome.storage.local.set({ lastDomain: currentDomain }); } } });
popup.js示例:
document.addEventListener('DOMContentLoaded', async () => { const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); const { sharingEnabled } = await chrome.storage.local.get('sharingEnabled'); if (sharingEnabled === 'recording') { await chrome.scripting.executeScript({ target: { tabId: tab.id }, files: ['reloaded.js'], }); chrome.action.setBadgeText({ tabId: tab.id, text: '' }); } });
方法3:改用桌面捕获API(推荐)
使用chrome.desktopCapture.chooseDesktopMedia替代tabCapture,该API无需activeTab权限,只需添加desktopCapture权限。用户需要手动选择录制目标,但可彻底避免跨域名权限问题。
修改manifest.json添加权限:
"permissions": ["scripting", "tabs", "desktopCapture", "storage"],
修改test.js逻辑:
chrome.tabs.query({ active: true, currentWindow: true }, function(tabsw) { const currentTabId = tabsw[0].id; chrome.desktopCapture.chooseDesktopMedia(['tab'], (streamId) => { if (!streamId) return; chrome.scripting.executeScript({ files: ["content.js"], target: { tabId: currentTabId } }, () => { chrome.tabs.sendMessage(currentTabId, { reloadStreamId: streamId, hello: "getReloadStreamId" }); }); }); });
内容的提问来源于stack exchange,提问作者Aviato

