浏览器插件
浏览器插件概述
浏览器插件(也称为扩展程序)是基于 Web 技术(如 HTML、CSS、JavaScript)的小型应用,用于增强浏览器功能。用户可以通过应用商店安装这些插件,它们的能力包括:
- 修改网页内容:如广告拦截或样式修改。
- 扩展浏览器能力:例如快捷键、标签管理或下载工具。
- 数据存储与同步:通过浏览器的存储 API 保存配置或数据。
- 调用浏览器 API:如访问书签、历史记录或拦截网络请求。
插件在用户授权的情况下运行,需要在配置清单中明确声明所需的权限,并遵循沙箱机制以保护用户隐私。
沙箱(Sandbox)
沙箱是一种安全机制,通过隔离运行环境限制程序的访问权限,使其只能在特定范围内操作,从而避免恶意脚本破坏系统或窃取数据。
Chrome 浏览器插件构建基础
要构建 Chrome 插件,需要掌握以下要素:
- 基础技术:使用
HTML构建界面、CSS定义样式、JavaScript实现逻辑。 - 核心配置文件:
manifest.json是插件的配置清单,用于定义元数据、权限和功能。 - 核心组件:后台脚本
Service Worker、内容脚本 (Content Script) 和用户界面 (Popup/Action/Options)。 - 消息传递:各组件之间使用
chrome.runtime.sendMessage、chrome.runtime.onMessage等接口通信。 - 浏览器 API:通过
chrome.*命名空间访问浏览器功能,例如chrome.tabs、chrome.storage。
常见功能与应用
凭借 Chrome 提供的 API,插件可以定制浏览器行为和网页内容。例如:
- 界面自定义:可在浏览器工具栏显示按钮(
action),添加右键菜单项(Menus),或在侧边栏 (Side panel) 中提供 UI 界面。 - 控制浏览器:
- 覆盖浏览器页面和设置项,如在
manifest.json中配置chrome_settings_overrides。 - 使用
chrome.devtools创建开发者工具页。 - 使用
chrome.notifications显示通知。 - 操作标签页和窗口:通过
chrome.tabs、chrome.tabGroups和chrome.windows控制浏览器界面。 - 管理历史记录与书签:调用
chrome.history、chrome.bookmarks等接口。 - 自定义键盘快捷键:使用
chrome.commands。 - 身份验证:通过
chrome.identity。 - 管理其他插件:使用
chrome.management。 - 更新代理设置:调用
chrome.proxy。 - 管理下载:
chrome.downloads。
- 覆盖浏览器页面和设置项,如在
- 控制网络:
- 注入
JavaScript或CSS到页面修改行为或样式。 - 访问当前标签页的数据。
- 拦截和修改网络请求,通过
chrome.webRequest或声明式网络请求 API。 - 调用摄像头、麦克风进行录音或捕获屏幕。
- 修改网站设置(例如定位、Cookie 权限)。
- 注入
浏览器插件核心概念
Chrome 插件由多个组件组成,每个组件在沙箱中具有不同的权限:
- Service Worker:基于事件的后台脚本,用于处理数据、协调插件各部分任务,是扩展的事件管理器。
- 权限 (
Permissions):声明插件需要的浏览器功能或数据访问权。应遵循最小化原则,仅请求必需的权限。 - 内容脚本 (
Content Script):在网页环境中运行,可访问当前页面的 DOM,用于读取或修改页面内容,但无法直接使用大部分 Chrome 扩展 API。 - Action/Popup:用户与插件交互的界面,运行在扩展上下文中,可直接使用扩展 API,但无法直接访问网页 DOM。
- 消息传递:由于沙箱隔离,不同组件需通过消息传递接口(如
chrome.runtime.sendMessage、chrome.tabs.sendMessage、chrome.runtime.onMessage)进行通信。 - 存储 (
Storage):Chrome 提供了storageAPI 用于数据持久化(本地或同步)。 - 匹配模式:用于指定哪些网页或 URL 能触发插件的内容脚本或授予主机权限。
| 组件 | 权限范围 |
|---|---|
| 内容脚本 (Content Script) | 可访问当前网页的 DOM;无法直接调用大部分扩展 API;需要通过消息与后台脚本通信。 |
| 后台脚本 (Service Worker) | 可访问所有扩展 API,包括操作标签页、存储、网络请求等;无法访问网页 DOM;事件驱动、非持久运行。 |
| 弹出页/选项页 (Popup/Options) | 运行在扩展上下文,可直接使用扩展 API;不能直接访问网页 DOM,如需与页面交互需通过内容脚本。 |
浏览器插件架构概览
插件项目由多个文件和资源组成,通常包括:
- 配置清单 (
manifest.json):每个插件都必须包含此文件,声明插件名称、版本、权限、图标等信息。 - 后台脚本 (
Service Worker):负责处理事件并在后台运行逻辑。在 Manifest V3 中,后台脚本通过service_worker指定,并以懒加载方式响应事件后自动休眠。 - 界面元素:包括工具栏按钮 (
popup)、侧边栏 (side panel)、选项页 (options_page)、开发者工具页 (devtools_page) 等。 - 内容脚本 (
content_scripts):可注入到指定网页,对页面内容进行读取或修改。 - 设置页 (
options_page):供用户配置插件参数的页面。
插件的核心组成关系如图所示(示意图):后台脚本、弹出界面与内容脚本三者通过消息传递协作完成功能,其中 background 和 popup 通过 chrome.runtime.sendMessage 通讯,而发送给特定页面中的 content script 需使用 chrome.tabs.sendMessage 并指定标签页 ID。
Manifest V3 配置清单
每个插件都需要一个 manifest.json 文件,它提供插件的基本信息,例如名称、版本和权限等。Chrome 目前最新的配置清单版本为 Manifest V3 (MV3)。MV3 更注重安全与用户隐私,提升性能,并改善开发体验。
以下是一个示例 manifest.json,展示了常见的配置项:
{
"manifest_version": 3,
"name": "My Extension",
"version": "0.0.1",
"action": {
// 配置工具栏按钮相关属性
},
"default_locale": "en",
"description": "A plain text description",
"icons": {
"16": "images/icon-16.png",
"32": "images/icon-32.png",
"48": "images/icon-48.png",
"128": "images/icon-128.png"
},
"background": {
"service_worker": "service-worker.js",
"type": "module"
},
"devtools_page": "devtools.html",
"externally_connectable": {
"matches": ["*://*.example.com/*"]
},
"file_system_provider_capabilities": {
"configurable": true,
"multiple_mounts": true,
"source": "network"
},
"homepage_url": "https://path/to/homepage",
"host_permissions": [],
"incognito": "spanning",
"options_page": "options.html",
"permissions": ["tabs"],
"storage": {
"managed_schema": "schema.json"
},
"version_name": "aString",
"web_accessible_resources": []
}
在 MV3 中,某些属性如 background.service_worker 必须指定后台脚本名称。更多配置项请参考官方文档。
权限管理
大多数浏览器 API 调用都需要在 manifest.json 的 permissions 字段中声明。权限分为几类:
permissions:需要在安装时授予的权限,例如tabs、storage等。optional_permissions:可选权限,用户在运行时选择授予。content_scripts.matches:包含一个或多个 匹配模式,用于指定内容脚本可以注入到哪些主机。host_permissions:声明对某些主机的访问权,也使用匹配模式。例如访问https://*.example.com/*。optional_host_permissions:可选主机权限,用户在运行时授权。
声明权限可以有效限制插件被滥用,如果插件被恶意软件入侵,较小的权限范围可以降低风险。安装或运行时浏览器会根据权限显示警告提示。
一个包含权限的 manifest.json 示例:
{
"name": "Permissions Extension",
"permissions": [
"activeTab",
"contextMenus",
"storage"
],
"optional_permissions": [
"topSites"
],
"host_permissions": [
"https://www.developer.chrome.com/*"
],
"optional_host_permissions": [
"https://*/*",
"http://*/*"
],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
],
"manifest_version": 3
}
主机权限
某些 API 除了自身权限还需要主机权限,包括:
- 从后台脚本或扩展页面发起
fetch()请求。 - 通过
chrome.tabs读取或查询敏感标签页属性(如 URL、标题、faviconUrl)。 - 以编程方式注入内容脚本。
- 使用
chrome.webRequest监控和控制网络请求。 - 通过
chrome.cookies访问 Cookie。 - 使用
chrome.declarativeNetRequest重定向或修改请求及响应头。
包含警告的权限
如果插件请求多项高风险权限,Chrome 安装界面会向用户显示警告。常见的警告包括:
| 权限 | 警告说明 |
|---|---|
http://*/*、https://*/*、*://*/*、<all_urls> | 读取和更改所有网站的数据 |
https://HostName.com/ | 读取和更改指定网站的数据 |
accessibilityFeatures.modify | 更改无障碍设置 |
clipboardRead / clipboardWrite | 读取或修改剪贴板数据 |
debugger | 访问页面调试后端,读取和更改所有网站数据 |
downloads | 管理下载内容 |
geolocation | 检测实际位置 |
history | 读取和更改浏览历史 |
notifications | 显示通知 |
proxy | 读取和更改所有网站数据 |
sessions / history | 读取和更改所有登录设备上的浏览记录 |
tabs | 读取浏览记录 |
请求较多权限会降低用户信任,因此开发时应尽量采用可选权限或使用功能较弱但无需警告的 API。
Service Worker(后台脚本)
在 Manifest V3 中,Chrome 扩展的后台脚本采用 Service Worker 取代了旧版的 background page。Service Worker 充当插件的“后台大脑”,主要作用包括:
- 事件响应中心:响应多种事件,例如
chrome.runtime.onInstalled(安装时)、chrome.runtime.onMessage(收到消息时)、chrome.alarms.onAlarm(定时器事件)、chrome.webRequest.onBeforeRequest(监听网络请求)以及chrome.action.onClicked(点击插件图标时)。 - 无需打开页面即可在后台运行:Service Worker 与页面无关,当事件触发时被唤醒执行任务,任务完成后自动休眠,提高性能。
- 协调组件通信:通过
chrome.runtime.sendMessage和chrome.runtime.onMessage协调 popup、content script、options page 等各组件之间的数据交换。 - 增强安全性:Service Worker 运行在无 DOM 的独立线程中,更难被注入恶意脚本,提高安全性和性能。
匹配模式
匹配模式用于指定一组 URL,以决定内容脚本在哪些页面注入,或授予哪些主机权限。其基本结构为:
<scheme>://<host>/<path>
scheme:必须为 http、https、file 或通配符 *(匹配 http 和 https)。
host:主机名(如 www.example.com)。可以使用通配符 * 匹配子域名,例如 *.example.com 或仅使用 * 匹配所有域名。通配符必须是第一个字符,紧跟 . 或 /。
path:URL 路径(如 /example)。主机权限中路径是必需的但会被忽略,一般使用 /*。
匹配模式常用于以下场景:
- 注入内容脚本。
- 声明主机权限(某些 API 还需要此权限)。
- 授予通过网络访问的资源权限(
web_accessible_resources)。 - 设置
externally_connectable.matches以允许跨站消息发送。
特殊情况
"<all_urls>":匹配所有可允许的 URL,会影响所有托管方,因此使用时审核可能更严格。"file:///":允许扩展在本地文件上运行,用户需手动授予此权限。注意使用三个斜杠。- 本地主机和 IP 地址:开发时可以使用
http://localhost/*匹配任何端口的本地主机;IP 地址可以使用http://127.0.0.1/*;http://*:*/*可匹配任意端口。 - 顶级域名:Chrome 不支持仅匹配顶级域名,应在各个 TLD 下分别声明,例如
http://google.es/*和http://google.fr/*。
示例格式
https://*/*或https://*/:匹配使用https协议的所有 URL。https://*/foo*:匹配任意主机上,路径以foo开头的httpsURL,例如https://example.com/foo/bar.html。https://*.google.com/foo*bar:匹配google.com下路径以foo开头并以bar结尾的 URL。file:///foo*:匹配路径以foo开头的任何本地文件。http://127.0.0.1/*或http://127.0.0.1/:匹配 IP 地址127.0.0.1上的httpURL。http://localhost/*:匹配任何端口的本地主机。*://mail.google.com/*:匹配http://mail.google.com或https://mail.google.com。
数据存储
Chrome 提供多种 API 用于持久化存储数据,常用的有 chrome.storage 和 chrome.cookies。
chrome.storage 模块
chrome.storage 用于在插件内部持久化数据,支持本地存储和云同步。常用方法包括:
| 方法 | 说明 |
|---|---|
chrome.storage.local.get(keys) | 获取本地数据 |
chrome.storage.local.set(items) | 设置本地数据 |
chrome.storage.local.remove(keys) | 删除指定键 |
chrome.storage.local.clear() | 清空全部本地数据 |
chrome.storage.sync.get/set/remove/clear | 与本地方法类似,但会同步到云端(空间有限制) |
chrome.storage.onChanged.addListener(cb) | 监听数据变化 |
示例代码:
// 保存数据到本地
chrome.storage.local.set({ theme: 'dark' });
// 获取数据
chrome.storage.local.get(['theme'], (result) => {
console.log('当前主题:', result.theme);
});
// 删除数据
chrome.storage.local.remove(['theme']);
// 监听变化
chrome.storage.onChanged.addListener((changes, area) => {
if (area === 'local' && changes.theme) {
console.log('主题变更为:', changes.theme.newValue);
}
});
使用 chrome.storage 需要在 manifest.json 中声明权限:
"permissions": [ "storage" ],
local 与 sync 的区别
| 特性 | chrome.storage.local | chrome.storage.sync |
|---|---|---|
| 存储位置 | 本地 | 云端同步(需登录 Google 账户) |
| 空间限制 | 较大(约 5 MB) | 较小(约 100 KB) |
| 是否同步 | 否 | 是(可跨设备) |
| 适合用途 | 缓存数据、用户偏好等 | 插件设置项、用户登录信息 |
如果有特殊需求,可添加 unlimitedStorage 权限取消 chrome.storage.local 的容量限制:
"permissions": ["storage", "unlimitedStorage"]
chrome.cookies 模块
chrome.cookies 允许插件读取、设置和监听网页的 Cookie,可操作当前标签页或指定域名下的 Cookie。常用方法:
| 方法 | 说明 |
|---|---|
chrome.cookies.get(details) | 获取指定 Cookie |
chrome.cookies.getAll(details) | 获取匹配的一组 Cookie |
chrome.cookies.set(details) | 设置 Cookie(可跨域) |
chrome.cookies.remove(details) | 删除 Cookie |
chrome.cookies.onChanged.addListener(cb) | 监听 Cookie 改变事件 |
示例代码:
// 获取某个 cookie
chrome.cookies.get({ url: 'https://example.com', name: 'session' }, (cookie) => {
console.log(cookie?.value);
});
// 设置 cookie
chrome.cookies.set({
url: 'https://example.com',
name: 'session',
value: 'abc123',
expirationDate: Math.floor(Date.now() / 1000) + 3600,
});
// 删除 cookie
chrome.cookies.remove({ url: 'https://example.com', name: 'session' });
使用 chrome.cookies 需要在 manifest.json 中声明权限,并为访问的域名授予主机权限:
"permissions": ["cookies", "https://example.com/"],
打包发布指南
要发布 Chrome 扩展,需要注册开发者账号并支付一次性费用,然后上传扩展包并通过审核。流程如下:
注册开发者账号
- 使用 Google 账号登录 Chrome 网上应用店的开发者信息中心。
- 按提示填写个人信息并支付一次性注册费用(约 5 美元)。
- 注册完成后即可进入开发者控制台管理扩展。
付费成为开发者
完成账号注册后,需要支付费用以激活开发者资格。支付时可使用国内发行的国际信用卡,选择合适的地区和地址信息即可。
发布流程
- 在开发者中心上传扩展的压缩包(包含
manifest.json和所有资源文件)。 - 根据提示配置扩展的描述、图标等元数据。
- 如果提示需要验证,请完成 Google 账号的两步验证。
- 上传成功后等待审核,审核通过后即可在 Chrome 网上应用店上线。
整个流程需要一定时间,请耐心等待审核结果。