Chrome扩展更新重注入脚本:如何检查URL匹配Manifest的matches模式?
问题背景与需求
我开发了一款Chrome扩展,利用chrome.runtime.onInstalled事件在扩展更新时重新注入脚本。在installContentScript()函数里,我尝试用以下代码给所有iframe重注入脚本,虽然能运行,但因为无差别注入导致报错:
chrome.webNavigation.getAllFrames({ tabId: id }, (frames) => { for (const frame of frames) { try { chrome.scripting.executeScript({ target: { tabId: id, frameIds: [frame.frameId] }, files: javaScripts, }); } catch(e) { console.log(e); } } });
我的核心问题是:给定一个URL,如何检查它是否匹配Manifest中内容脚本字段定义的matches模式?
Manifest示例:
{ "matches": ["*://mail.google.com/*"], "js": ["script.js"], "all_frames": true, "run_at": "document_idle" }
解决方案
你可以通过两种方式实现URL与Manifest中matches模式的匹配校验,以下是具体方法:
方法1:利用Chrome内置匹配API(推荐)
Chrome的declarativeContent模块提供原生的模式匹配能力,无需手动解析规则,直接调用即可:
async function isUrlMatchesManifest(url) { // 获取当前扩展的Manifest配置 const manifest = chrome.runtime.getManifest(); const contentScripts = manifest.content_scripts || []; for (const scriptConfig of contentScripts) { const matchPatterns = scriptConfig.matches || []; // 创建PageStateMatcher实例,传入匹配规则 const matcher = new chrome.declarativeContent.PageStateMatcher({ pageUrl: { urlMatches: matchPatterns.join(',') } }); // 校验当前URL是否匹配 const isMatch = await matcher.match({ url }); if (isMatch) return true; } return false; }
注意:使用该方法需要在Manifest中声明declarativeContent权限:
{ "permissions": ["declarativeContent"] }
方法2:手动实现模式转正则匹配
如果不想额外申请权限,可以手动将matches模式转换为正则表达式,再进行URL匹配:
// 单个模式与URL的匹配逻辑 function matchesPattern(url, pattern) { // 将Chrome匹配模式转换为正则表达式 let regexStr = pattern .replace(/\*/g, '.*') // 通配符*转为任意字符匹配 .replace(/\?/g, '.') // 通配符?转为单个字符匹配 .replace(/\./g, '\\.') // 转义点号 .replace(/\^/g, '^'); // 保留^的起始匹配含义 // 给正则添加首尾锚点,避免部分匹配 regexStr = `^${regexStr}$`; return new RegExp(regexStr).test(url); } // 遍历Manifest中所有内容脚本规则,校验URL是否匹配 function isUrlMatchesManifest(url) { const manifest = chrome.runtime.getManifest(); const contentScripts = manifest.content_scripts || []; for (const scriptConfig of contentScripts) { const matchPatterns = scriptConfig.matches || []; for (const pattern of matchPatterns) { if (matchesPattern(url, pattern)) return true; } } return false; }
改造重注入逻辑
将匹配校验加入原注入代码,只给符合规则的iframe注入脚本:
chrome.webNavigation.getAllFrames({ tabId: id }, async (frames) => { for (const frame of frames) { try { // 先校验当前frame的URL是否符合规则 const shouldInject = await isUrlMatchesManifest(frame.url); if (shouldInject) { chrome.scripting.executeScript({ target: { tabId: id, frameIds: [frame.frameId] }, files: javaScripts, }); } } catch(e) { console.log(e); } } });
内容的提问来源于stack exchange,提问作者Jesse Sliter
相关产品推荐
相关产品推荐

