Chrome 插件(扩展程序)可以为浏览器增加新功能,修改网页行为,与用户交互。本教程将带你从零开始,掌握 Chrome 插件开发的全部核心知识,最终能够开发、调试并发布自己的插件。
目录
-
Chrome 插件概述
-
开发环境准备
-
Manifest V3 配置文件
-
第一个插件:Hello World
-
插件核心组件详解
- 5.1 弹出页面 (Popup)
- 5.2 背景脚本 (Background Service Worker)
- 5.3 内容脚本 (Content Scripts)
- 5.4 选项页面 (Options Page)
- 5.5 右键菜单 (Context Menus)
- 5.6 桌面通知 (Notifications)
- 5.7 页面操作 (Page Action) vs 浏览器操作 (Browser Action)
-
消息传递机制
- 6.1 单向消息传递
- 6.2 带回调的消息传递
- 6.3 长时间连接
-
数据存储
- 7.1 chrome.storage
- 7.2 chrome.storage.local 与 chrome.storage.sync
- 7.3 使用示例
-
权限与 API
- 8.1 常用权限
- 8.2 动态权限请求
-
调试与测试
-
打包与发布
-
高级主题
- 11.1 DevTools 面板
- 11.2 覆盖页面 (Override Pages)
- 11.3 使用 WebAssembly
- 11.4 国际化 (i18n)
-
最佳实践与注意事项
-
结语
1. Chrome 插件概述
Chrome 插件(扩展程序)是运行在浏览器中的小程序,可以增强浏览器功能或与当前浏览的页面交互。插件通常由 HTML、CSS、JavaScript 以及一个清单文件(manifest.json)组成。每个插件都有一个唯一的标识(扩展 ID),并可申请特定权限来访问 Chrome API 或用户数据。
插件的常见用途:
- 修改网页样式或内容(如广告拦截器)
- 添加浏览器侧边栏、按钮
- 提供生产力工具(如密码管理器)
- 与第三方服务集成
从 2022 年起,Chrome 要求所有插件使用 Manifest V3,新插件必须以 V3 开发。
2. 开发环境准备
开发 Chrome 插件无需复杂的环境,只需:
- 最新版 Chrome 浏览器
- 一个代码编辑器(VS Code、Sublime Text 等)
- 基本的 HTML、CSS、JavaScript 知识
推荐步骤:
-
在本地创建一个文件夹,作为插件项目根目录。
-
编写代码。
-
在 Chrome 中加载未打包的扩展程序进行测试:
- 打开
chrome://extensions/ - 开启“开发者模式”
- 点击“加载已解压的扩展程序”,选择你的项目文件夹
- 打开
每次修改代码后,在扩展程序页面点击刷新按钮(🔄)即可重新加载插件。
3. Manifest V3 配置文件
manifest.json 是插件的“身份证”,必须放在根目录。一个最基本的 V3 清单文件如下:
{
"manifest_version": 3,
"name": "我的第一个插件",
"version": "1.0.0",
"description": "一个简单的Chrome插件示例",
"icons": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
},
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
},
"background": {
"service_worker": "background.js"
},
"permissions": [
"storage",
"activeTab"
],
"host_permissions": [
"<all_urls>"
],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"],
"css": ["content.css"]
}
],
"options_ui": {
"page": "options.html",
"open_in_tab": false
}
}
关键字段说明:
manifest_version:必须为 3。name、version、description:插件基本信息。icons:插件图标,推荐提供多种尺寸。action:定义浏览器工具栏上的按钮(V3 中统一使用action,不再区分browser_action和page_action)。default_popup指定点击按钮后弹出的 HTML 页面。background:后台脚本,V3 中使用 Service Worker,不能是持久化页面。service_worker指定脚本文件。permissions:需要声明的权限,如storage(存储)、activeTab(当前标签页)等。host_permissions:需要访问的主机权限,如"<all_urls>"表示所有网址。content_scripts:注入到网页中的脚本,会在页面加载时运行。matches指定匹配的 URL 模式。options_ui:选项页面,用户可在扩展管理页面点击“选项”打开。
4. 第一个插件:Hello World
我们创建一个最简单的插件:点击工具栏图标,弹出一个显示“Hello World”的弹出窗口。
步骤 1:创建项目文件夹
新建文件夹 hello-extension,在其中创建以下文件:
manifest.jsonpopup.htmlpopup.js(可选)icon.png(任意图片,作为图标)
步骤 2:编写 manifest.json
{
"manifest_version": 3,
"name": "Hello World 插件",
"version": "1.0",
"description": "第一个插件",
"icons": {
"16": "icon.png",
"48": "icon.png",
"128": "icon.png"
},
"action": {
"default_popup": "popup.html",
"default_icon": "icon.png"
}
}
步骤 3:编写 popup.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body { width: 200px; height: 100px; display: flex; justify-content: center; align-items: center; font-family: sans-serif; }
h1 { color: #4CAF50; }
</style>
</head>
<body>
<h1>Hello World!</h1>
<script src="popup.js"></script>
</body>
</html>
步骤 4:编写 popup.js(可选)
console.log('Popup 已打开');
步骤 5:加载插件
- 打开
chrome://extensions/ - 开启“开发者模式”
- 点击“加载已解压的扩展程序”,选择
hello-extension文件夹 - 插件加载后,工具栏会出现图标,点击即弹出 Hello World。
恭喜!你已经完成了第一个 Chrome 插件。
5. 插件核心组件详解
5.1 弹出页面 (Popup)
弹出页面是一个简单的 HTML 页面,在用户点击工具栏图标时显示。它的生命周期很短:每次点击都会重新加载,关闭即销毁。因此适合做简单的交互,不适合保存状态。如果需要在弹出页面中存储数据,可以结合 chrome.storage 或 localStorage(但注意 localStorage 在弹出页面中与普通网页一样是隔离的)。
弹出页面可以访问部分 Chrome API,但权限取决于插件的 permissions。
示例:在弹出页面中显示当前标签页的 URL。
<!-- popup.html -->
<body>
<div id="url">当前页面URL:</div>
<script src="popup.js"></script>
</body>
// popup.js
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
document.getElementById('url').innerText += tabs[0].url;
});
注意:需要 activeTab 或 tabs 权限。
5.2 背景脚本 (Background Service Worker)
背景脚本是插件的“大脑”,用于监听浏览器事件、处理长时间运行的任务。V3 中,它是 Service Worker,在需要时启动,空闲时终止,因此不能使用全局变量持久保存状态。必须将数据存储到 chrome.storage 或 IndexedDB 中。
常用场景:
- 监听扩展安装、更新
- 监听浏览器事件(如标签页更新、书签变化)
- 与内容脚本通信,转发消息
- 管理右键菜单、桌面通知
示例:监听插件安装事件。
// background.js
chrome.runtime.onInstalled.addListener((details) => {
if (details.reason === 'install') {
console.log('插件已安装');
// 初始化存储等操作
} else if (details.reason === 'update') {
console.log('插件已更新');
}
});
清单文件必须声明 background.service_worker。
5.3 内容脚本 (Content Scripts)
内容脚本注入到网页中,可以访问并修改 DOM,但无法直接使用大部分 Chrome API(如 chrome.tabs)。它们运行在独立的作用域,与页面脚本隔离,但可以通过 DOM 与页面脚本通信(通过 window.postMessage)或通过消息传递与后台脚本通信。
示例:在页面中所有链接后添加“🔗”符号。
// content.js
const links = document.querySelectorAll('a');
links.forEach(link => {
link.insertAdjacentText('afterend', ' 🔗');
});
清单文件中需配置 content_scripts,或在运行时通过 chrome.scripting.executeScript 动态注入。
5.4 选项页面 (Options Page)
为用户提供插件的设置界面,用户可在扩展管理页面点击“选项”按钮打开。选项页面可以是一个完整的 HTML 页面,通常用于保存用户偏好设置。
示例:一个简单的选项页面,允许用户设置背景颜色。
<!-- options.html -->
<body>
<label>背景颜色:<input type="color" id="bgColor"></label>
<button id="save">保存</button>
<script src="options.js"></script>
</body>
// options.js
document.getElementById('save').addEventListener('click', () => {
const color = document.getElementById('bgColor').value;
chrome.storage.sync.set({ bgColor: color }, () => {
console.log('已保存');
});
});
// 加载已保存的颜色
chrome.storage.sync.get('bgColor', (data) => {
if (data.bgColor) document.getElementById('bgColor').value = data.bgColor;
});
清单中需包含 options_ui。
5.5 右键菜单 (Context Menus)
插件可以添加自定义右键菜单项。需要在后台脚本中调用 chrome.contextMenus.create 创建菜单,并监听 chrome.contextMenus.onClicked 事件。
权限:需要 contextMenus 权限。
示例:添加右键菜单“查看链接文本”,点击后弹出提示。
// background.js
chrome.runtime.onInstalled.addListener(() => {
chrome.contextMenus.create({
id: "show-link-text",
title: "查看链接文本",
contexts: ["link"] // 仅在链接上显示
});
});
chrome.contextMenus.onClicked.addListener((info, tab) => {
if (info.menuItemId === "show-link-text") {
const linkText = info.linkText;
chrome.scripting.executeScript({
target: { tabId: tab.id },
func: (text) => alert(`链接文本:${text}`),
args: [linkText]
});
}
});
注意:右键菜单在 V3 中需要 host_permissions 来执行脚本,或者使用 activeTab 权限(用户点击插件图标时授权)。
5.6 桌面通知 (Notifications)
插件可以发送系统通知,需要使用 notifications 权限。
示例:
chrome.notifications.create({
type: "basic",
iconUrl: "icon.png",
title: "提醒",
message: "这是一条通知"
}, (notificationId) => {
console.log("通知已创建,ID:" + notificationId);
});
5.7 页面操作 (Page Action) vs 浏览器操作 (Browser Action)
在 Manifest V3 中,两者统一为 action。但概念上:
- 浏览器操作:插件对所有页面都有效,工具栏图标始终显示。
- 页面操作:插件仅对特定页面有效,图标在不需要时变灰(或隐藏)。V3 中可通过
action动态设置图标或禁用状态来实现类似效果。
6. 消息传递机制
由于各组件(背景、内容脚本、弹出页面、选项页面)运行在不同环境,需要通过消息传递进行通信。
6.1 单向消息传递
使用 chrome.runtime.sendMessage 发送消息,chrome.runtime.onMessage 接收。
示例:内容脚本向后台发送消息,后台处理后返回结果。
content.js
chrome.runtime.sendMessage({ greeting: "hello" }, (response) => {
console.log("后台回复:" + response.reply);
});
background.js
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.greeting === "hello") {
sendResponse({ reply: "world" });
}
return true; // 异步响应时需要返回 true
});
6.2 带回调的消息传递
同上,sendMessage 的第二个参数是回调函数,接收 sendResponse 的结果。注意若回调是异步的,需要在监听器中返回 true,否则 sendResponse 会失效。
6.3 长时间连接
使用 chrome.runtime.connect 建立长连接,通过 port.postMessage 和 port.onMessage 通信。
示例:后台与内容脚本建立长连接。
background.js
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (changeInfo.status === 'complete') {
const port = chrome.tabs.connect(tabId, { name: "my-connection" });
port.postMessage({ data: "页面加载完成" });
port.onMessage.addListener((msg) => {
console.log("收到来自页面的消息:", msg);
});
}
});
content.js
chrome.runtime.onConnect.addListener((port) => {
if (port.name === "my-connection") {
port.onMessage.addListener((msg) => {
console.log("收到来自后台的消息:", msg);
port.postMessage({ reply: "收到" });
});
}
});
7. 数据存储
7.1 chrome.storage
推荐使用 chrome.storage API 存储数据,它是异步的,且与浏览器同步(如果使用 sync 存储,会在登录 Chrome 的用户间同步)。数据大小限制:sync 约 100KB,local 约 5MB(可申请更多)。
7.2 chrome.storage.local 与 chrome.storage.sync
local:仅存储在本地,数据量大,不跨设备同步。sync:跨设备同步,但容量小,适合存储用户偏好。
7.3 使用示例
// 存储数据
chrome.storage.sync.set({ key: "value" }, () => {
console.log("已保存");
});
// 读取数据
chrome.storage.sync.get(["key"], (result) => {
console.log("读取到的值:" + result.key);
});
// 移除数据
chrome.storage.sync.remove("key", () => {
console.log("已移除");
});
// 监听存储变化
chrome.storage.onChanged.addListener((changes, areaName) => {
console.log("存储变化:", changes, areaName);
});
8. 权限与 API
8.1 常用权限
activeTab:临时获取当前活动标签页的访问权限,用户点击插件按钮时自动授予,适合无需复杂权限的场景。tabs:访问标签页的完整信息(URL、标题等),并可操作标签页(创建、更新、关闭)。storage:使用chrome.storage。cookies:操作 cookies。webRequest:拦截和修改网络请求(V3 中需使用declarativeNetRequest)。notifications:显示桌面通知。contextMenus:添加右键菜单。bookmarks、history等。
8.2 动态权限请求
V3 中,部分权限可在运行时通过 chrome.permissions.request 请求。例如:
chrome.permissions.request({
permissions: ["cookies"],
origins: ["*://*.example.com/*"]
}, (granted) => {
if (granted) console.log("权限已授予");
});
同时可以检查权限、移除权限等。
9. 调试与测试
- 插件整体调试:在
chrome://extensions/中点击插件卡片下的“背景页”链接,可以打开 DevTools 调试 Service Worker。 - 内容脚本调试:打开目标网页,按 F12 打开 DevTools,在“Sources”面板的“内容脚本”分类下找到你的插件内容脚本,可设置断点。
- 弹出页面调试:右键点击插件图标,选择“检查弹出内容”,即可调试弹出页面的 DevTools。
- 选项页面调试:在选项页面上右键选择“检查”。
- 查看错误:在
chrome://extensions/页面,如果插件有错误,卡片上会有“错误”按钮,点击查看详情。
10. 打包与发布
-
准备图标:必须提供至少 128x128 的图标,建议提供 16、48、128 三种尺寸。
-
添加商店描述:准备详细说明、截图(至少 1 张)、宣传图(可选)。
-
创建开发者账户:登录 Chrome Web Store 开发者控制台,支付一次性注册费(约 5 美元)。
-
打包插件:
- 在
chrome://extensions/中,点击“打包扩展程序”,选择项目根目录,会生成.crx文件和私钥(.pem)。私钥务必保存好,用于后续更新。
- 在
-
上传:在开发者控制台点击“新增项目”,上传
.crx或直接上传项目 zip。填写表单,提交审核。审核通常需要几小时到几天。 -
更新:修改
manifest.json中的version号,重新打包(使用原来的私钥),在控制台上传更新。
11. 高级主题
11.1 DevTools 面板
插件可以添加自己的面板到 Chrome DevTools 中。需要声明 devtools_page 字段,并编写对应的 HTML 和 JS。
"devtools_page": "devtools.html"
devtools.html 中引入 JS,调用 chrome.devtools.panels.create 创建面板。
11.2 覆盖页面 (Override Pages)
可以替换 Chrome 的某些内置页面,如新标签页、书签页、历史页。需要在 chrome_url_overrides 字段中声明。
"chrome_url_overrides": {
"newtab": "my-newtab.html"
}
11.3 使用 WebAssembly
Manifest V3 允许在扩展中使用 WebAssembly,可以提高某些计算密集型任务的性能。只需将 .wasm 文件包含在插件包中,并在 JavaScript 中加载即可。
11.4 国际化 (i18n)
支持多语言:创建 _locales 文件夹,下设语言子文件夹(如 en、zh_CN),内含 messages.json。在 manifest.json 中可使用 __MSG_xxx__ 引用本地化字符串。
messages.json 示例:
{
"extensionName": {
"message": "我的插件",
"description": "插件名称"
},
"extensionDescription": {
"message": "一个示例插件",
"description": "插件描述"
}
}
在 manifest 中:"name": "__MSG_extensionName__"。
12. 最佳实践与注意事项
- 安全第一:不要在内容脚本中直接使用
eval或innerHTML插入未经验证的外部数据,防止 XSS 攻击。尽量使用textContent或createElement。 - 性能优化:Service Worker 和内容脚本应尽量轻量,避免阻塞页面渲染。使用异步 API,避免长时间运行的任务。
- 权限最小化:只申请必要的权限,提高用户信任度。
- 跨设备同步:对于用户设置,尽量使用
chrome.storage.sync让设置随账号同步。 - 错误处理:所有异步 API 调用都应添加错误回调(
onError或检查chrome.runtime.lastError)。 - 代码分离:保持后台脚本、内容脚本、弹出页面的代码独立,通过消息通信,降低耦合。
- 测试兼容性:在不同版本的 Chrome 上测试,确保 API 可用。使用
chrome.runtime.getManifest()检查清单版本,有条件地使用 API。 - 遵循 Chrome 商店政策:内容不可含有恶意代码、收集隐私信息需明确告知、不干扰其他扩展等。
13. 结语
Chrome 插件开发是一个门槛低但可以非常深入的技术。通过本教程,你已经掌握了从清单配置到各个组件、从消息传递到存储、从调试到发布的完整流程。现在,你可以开始构思自己的插件创意,并将它实现出来。
继续探索 Chrome 官方文档(developer.chrome.com/docs/extensions/),那里有更详细的 API 参考和大量示例。祝你开发顺利,创造出有用的插件!