Chrome 插件开发完全指南

6 阅读12分钟

Chrome 插件(扩展程序)可以为浏览器增加新功能,修改网页行为,与用户交互。本教程将带你从零开始,掌握 Chrome 插件开发的全部核心知识,最终能够开发、调试并发布自己的插件。


目录

  1. Chrome 插件概述

  2. 开发环境准备

  3. Manifest V3 配置文件

  4. 第一个插件:Hello World

  5. 插件核心组件详解

    • 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. 消息传递机制

    • 6.1 单向消息传递
    • 6.2 带回调的消息传递
    • 6.3 长时间连接
  7. 数据存储

    • 7.1 chrome.storage
    • 7.2 chrome.storage.local 与 chrome.storage.sync
    • 7.3 使用示例
  8. 权限与 API

    • 8.1 常用权限
    • 8.2 动态权限请求
  9. 调试与测试

  10. 打包与发布

  11. 高级主题

    • 11.1 DevTools 面板
    • 11.2 覆盖页面 (Override Pages)
    • 11.3 使用 WebAssembly
    • 11.4 国际化 (i18n)
  12. 最佳实践与注意事项

  13. 结语


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 知识

推荐步骤

  1. 在本地创建一个文件夹,作为插件项目根目录。

  2. 编写代码。

  3. 在 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。
  • nameversiondescription:插件基本信息。
  • 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.json
  • popup.html
  • popup.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:加载插件

  1. 打开 chrome://extensions/
  2. 开启“开发者模式”
  3. 点击“加载已解压的扩展程序”,选择 hello-extension 文件夹
  4. 插件加载后,工具栏会出现图标,点击即弹出 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:添加右键菜单。
  • bookmarkshistory 等。

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. 打包与发布

  1. 准备图标:必须提供至少 128x128 的图标,建议提供 16、48、128 三种尺寸。

  2. 添加商店描述:准备详细说明、截图(至少 1 张)、宣传图(可选)。

  3. 创建开发者账户:登录 Chrome Web Store 开发者控制台,支付一次性注册费(约 5 美元)。

  4. 打包插件

    • 在 chrome://extensions/ 中,点击“打包扩展程序”,选择项目根目录,会生成 .crx 文件和私钥(.pem)。私钥务必保存好,用于后续更新。
  5. 上传:在开发者控制台点击“新增项目”,上传 .crx 或直接上传项目 zip。填写表单,提交审核。审核通常需要几小时到几天。

  6. 更新:修改 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 文件夹,下设语言子文件夹(如 enzh_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 参考和大量示例。祝你开发顺利,创造出有用的插件!