Chrome扩展注入脚本未接收StartTimer消息及注入相关问题
Chrome 扩展消息通信与注入问题解决方案
核心问题:点击 popup 按钮后内容脚本未收到消息
问题原因
chrome.runtime.sendMessage 是向扩展的**后台脚本(background.js)**发送消息,内容脚本(injected.js)无法直接接收该消息。要给内容脚本发消息,需要使用 chrome.tabs.sendMessage 并指定目标标签页 ID。
修复代码
修改 popup.js,获取当前活跃标签页并发送消息:
const startTimerBtn = document.getElementById("start-timer-btn") startTimerBtn.addEventListener("click", async () => { // 获取当前窗口的活跃标签页 const [tab] = await chrome.tabs.query({active: true, currentWindow: true}) if (tab) { // 向目标标签页的内容脚本发送消息 chrome.tabs.sendMessage(tab.id, { type: "StartTimer"}) } })
修改后点击按钮,injected.js 就能收到消息并打印 injected.js: start timer 日志。
额外问题解答
1. 避免向同一标签页重复注入脚本
通过在标签页的全局对象中设置标记,注入前先检查标记是否存在,存在则跳过注入。
修改 background.js 的 injectJS 函数
async function injectJS() { let blockUrlList = [] const res = await chrome.storage.local.get(["block_urls"]) blockUrlList = res.block_urls || [] if (!blockUrlList.length) return try { const qryOptions = { "url": blockUrlList.map(p => `*://*.${p}/*`)} const tabs = await chrome.tabs.query(qryOptions) for (const tab of tabs) { console.log('checking injection status for tab', tab.id, tab.url) try { // 检查标签页是否已注入脚本 const checkResult = await chrome.scripting.executeScript({ target: {tabId: tab.id}, func: () => window._hasInjectedTimerScript }) if (checkResult[0].result) { console.log('script already injected into tab', tab.id) continue } // 注入脚本 await chrome.scripting.executeScript({ target: {tabId: tab.id}, files: ['content/injected.js'] }) // 设置已注入标记 await chrome.scripting.executeScript({ target: {tabId: tab.id}, func: () => window._hasInjectedTimerScript = true }) console.log('successfully injected into tab', tab.id) } catch(err) { console.log('failed to handle tab', tab.id, err) } } } catch(err) { console.log('No matching tab', err) } }
修改 injected.js 添加标记初始化
// 初始化已注入标记 window._hasInjectedTimerScript = true; chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { if (message.type === "StartTimer") { console.log('injected.js: start timer') } else if(message.type === "StopTimer"){ console.log('injected.js: stop timer') } }); console.log("you have been injected")
2. 新标签打开/刷新时自动注入脚本
在 background.js 中监听标签页的更新和创建事件,当标签加载完成且 URL 匹配规则时自动执行注入逻辑:
// background.js 添加以下代码 // 监听标签页加载完成事件 chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => { if (changeInfo.status !== 'complete') return await injectScriptIfMatched(tabId, tab.url) }) // 监听新标签页创建事件 chrome.tabs.onCreated.addListener(async (tab) => { // 等待新标签页加载完成 const waitForLoad = () => new Promise(resolve => { const listener = (id, info) => { if (id === tab.id && info.status === 'complete') { chrome.tabs.onUpdated.removeListener(listener) resolve() } } chrome.tabs.onUpdated.addListener(listener) }) await waitForLoad() await injectScriptIfMatched(tab.id, tab.url) }) // 封装匹配检查与注入逻辑 async function injectScriptIfMatched(tabId, tabUrl) { const res = await chrome.storage.local.get(["block_urls"]) const blockUrlList = res.block_urls || [] if (!blockUrlList.length) return // 检查当前URL是否在拦截列表中 const isMatched = blockUrlList.some(domain => { const pattern = new RegExp(`^https?://.*\\.${domain}/.*`, 'i') return pattern.test(tabUrl) }) if (isMatched) { try { const checkResult = await chrome.scripting.executeScript({ target: {tabId: tabId}, func: () => window._hasInjectedTimerScript }) if (!checkResult[0].result) { await chrome.scripting.executeScript({ target: {tabId: tabId}, files: ['content/injected.js'] }) await chrome.scripting.executeScript({ target: {tabId: tabId}, func: () => window._hasInjectedTimerScript = true }) console.log('auto injected into tab', tabId) } } catch(err) { console.log('failed auto inject for tab', tabId, err) } } }
内容的提问来源于stack exchange,提问作者Ani
相关产品推荐
相关产品推荐

