深入探讨使用 Manifest V3 和 JavaScript API 进行浏览器扩展开发。学习为现代浏览器构建功能强大且安全的扩展程序。
浏览器扩展开发:Manifest V3 与 JavaScript API
浏览器扩展是定制浏览体验的小型软件程序。它们可以添加新功能、修改网站内容、拦截广告等等。随着 Manifest V3 的到来,扩展的构建和运行方式发生了重大变化。本综合指南将探讨使用 Manifest V3 和 JavaScript API 进行浏览器扩展开发,为您提供为现代浏览器创建功能强大且安全的扩展所需的知识。
什么是浏览器扩展?
浏览器扩展本质上是在网页浏览器中运行的迷你应用程序。它们扩展了浏览器的功能,并与网页无缝集成。扩展使用 HTML、CSS 和 JavaScript 等标准 Web 技术编写,这使得 Web 开发人员相对容易上手。
流行的浏览器扩展示例包括:
- 广告拦截器:拦截网页上的广告,提高浏览速度并减少干扰。
- 密码管理器:安全地存储和管理密码,在网站上自动填充。
- 笔记扩展:允许用户直接从网页上做笔记并保存。
- 生产力工具:通过提供任务管理、时间跟踪和专注模式等功能来提高生产力。
- 语言翻译工具:只需单击一下即可将网页翻译成不同语言。例如:谷歌翻译扩展。
- VPN 扩展:代理互联网流量以绕过地理限制并增强隐私。
Manifest V3 的重要性
Manifest V3 是清单文件(manifest file)的最新版本,这是一个向浏览器描述扩展的 JSON 文件。它概述了扩展的名称、版本、权限、后台脚本和其他必要的元数据。与前身 Manifest V2 相比,Manifest V3 引入了几个关键变化,主要侧重于安全性和性能。
Manifest V3 的主要变化:
- Service Workers:Manifest V3 用 Service Worker 替换了后台页面。Service Worker 是事件驱动的脚本,在后台运行而不需要持久页面。它们比后台页面更高效,资源消耗更少。
- Declarative Net Request API:此 API 允许扩展在不直接拦截网络请求的情况下修改它们。它通过将过滤逻辑卸载到浏览器来增强安全性和性能。
- 更严格的内容安全策略 (CSP):Manifest V3 强制执行更严格的 CSP 规则,以防止执行任意代码,从而进一步增强安全性。
- 基于 Promise 的 API:许多 API 现在都基于 Promise,使异步操作更易于管理。
为何转向 Manifest V3?
- 增强安全性:Manifest V3 旨在提高浏览器扩展的安全性,保护用户免受恶意代码的侵害。
- 提升性能:Service Worker 和 Declarative Net Request API 有助于提高性能并减少资源消耗。
- 更好的隐私保护:Manifest V3 旨在让用户更好地控制自己的数据和隐私。
设置您的开发环境
在开始开发浏览器扩展之前,您需要设置好开发环境。这包括安装代码编辑器、选择用于测试的浏览器以及了解扩展的基本文件结构。
1. 代码编辑器
选择一款您用得顺手的代码编辑器。热门选择包括:
- Visual Studio Code (VS Code):一款免费且功能强大的代码编辑器,对 JavaScript 和其他 Web 技术有出色的支持。
- Sublime Text:一款快速且可定制的代码编辑器,拥有丰富的插件。
- Atom:一款由 GitHub 开发的免费开源代码编辑器。
2. 测试用浏览器
选择一个浏览器来测试您的扩展。Chrome 和 Firefox 是最受欢迎的选择,因为它们提供强大的开发者工具并支持扩展开发。
3. 基本文件结构
一个浏览器扩展通常包含以下文件:
- manifest.json:此文件包含扩展的元数据,例如其名称、版本、权限和后台脚本。
- background.js (或 service worker 脚本):此脚本在后台运行,处理浏览器操作和上下文菜单点击等事件。
- content.js:此脚本在网页的上下文中运行,可以修改其内容。
- popup.html:此文件定义了扩展弹出窗口的用户界面。
- popup.js:此脚本处理扩展弹出窗口的逻辑。
- options.html:此文件定义了扩展选项页面的用户界面。
- options.js:此脚本处理扩展选项页面的逻辑。
- icons:这些是用于在浏览器工具栏和扩展管理页面中代表扩展的图标。
创建您的第一个扩展:“Hello, World!”
让我们创建一个简单的“Hello, World!”扩展来演示浏览器扩展开发的基本原理。
1. 创建清单文件 (manifest.json)
在新目录中创建一个名为 `manifest.json` 的文件,并添加以下代码:
{
"manifest_version": 3,
"name": "Hello, World!",
"version": "1.0",
"description": "A simple Hello, World! extension",
"permissions": [
"storage"
],
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "images/icon16.png",
"48": "images/icon48.png",
"128": "images/icon128.png"
}
},
"icons": {
"16": "images/icon16.png",
"48": "images/icon48.png",
"128": "images/icon128.png"
}
}
解释:
- `manifest_version`: 指定清单文件的版本(Manifest V3 为 3)。
- `name`: 扩展的名称。
- `version`: 扩展的版本号。
- `description`: 扩展的简短描述。
- `permissions`: 扩展所需的权限数组(例如,“storage”)。
- `action`: 定义扩展弹出窗口的属性,包括默认的弹出文件和图标。
- `icons`: 指定扩展图标的路径。
2. 创建弹出文件 (popup.html)
在同一目录中创建一个名为 `popup.html` 的文件,并添加以下代码:
<!DOCTYPE html>
<html>
<head>
<title>Hello, World!</title>
<style>
body {
width: 200px;
padding: 10px;
font-family: sans-serif;
}
</style>
</head>
<body>
<h1>Hello, World!</h1>
<p>This is a simple browser extension.</p>
</body>
</html>
此文件定义了扩展弹出窗口的用户界面,它将显示“Hello, World!”消息。
3. 创建图标图像
创建三个尺寸分别为 16x16、48x48 和 128x128 像素的图标图像。将它们作为 `icon16.png`、`icon48.png` 和 `icon128.png`保存在您的扩展目录下的 `images` 目录中。
4. 将扩展加载到您的浏览器中
Chrome:
- 打开 Chrome 并访问 `chrome://extensions`。
- 在右上角启用“开发者模式”。
- 点击“加载已解压的扩展程序”并选择包含您的扩展文件的目录。
Firefox:
- 打开 Firefox 并访问 `about:debugging#/runtime/this-firefox`。
- 点击“加载临时附加组件...”并选择 `manifest.json` 文件。
您的“Hello, World!”扩展现在应该已经安装并在浏览器工具栏中可见。点击扩展图标以打开弹出窗口并看到“Hello, World!”消息。
使用 JavaScript API
浏览器扩展可以使用 JavaScript API 与浏览器和网页进行交互。这些 API 提供了对各种功能的访问,例如:
- Tabs API:允许您管理浏览器标签页,包括创建、更新和查询标签页。
- Storage API:提供一种在扩展内持久存储和检索数据的方法。
- Alarms API:允许您安排在特定时间执行的任务。
- Notifications API:使您能够向用户显示通知。
- Context Menus API:允许您向浏览器的上下文菜单(右键菜单)添加自定义项目。
- Web Request API (在 Manifest V3 中为 Declarative Net Request):使您能够拦截和修改网络请求。
- Scripting API:允许将脚本注入网页。
示例:使用 Storage API
让我们创建一个使用 Storage API 存储和检索用户姓名的扩展。
1. 更新清单文件 (manifest.json)
确保您的 `manifest.json` 中的 `permissions` 数组包含 `"storage"`:
{
"manifest_version": 3,
"name": "Storage Example",
"version": "1.0",
"description": "An extension that uses the Storage API",
"permissions": [
"storage"
],
"action": {
"default_popup": "popup.html"
},
"icons": {
"16": "images/icon16.png",
"48": "images/icon48.png",
"128": "images/icon128.png"
}
}
2. 创建弹出文件 (popup.html)
创建或更新您的 `popup.html` 文件,内容如下:
<!DOCTYPE html>
<html>
<head>
<title>Storage Example</title>
<style>
body {
width: 250px;
padding: 10px;
font-family: sans-serif;
}
</style>
</head>
<body>
<h1>Storage Example</h1>
<label for="name">Enter your name:</label>
<input type="text" id="name">
<button id="save">Save</button>
<p id="greeting"></p>
<script src="popup.js"></script>
</body>
</html>
3. 创建弹出脚本 (popup.js)
创建一个名为 `popup.js` 的文件,并添加以下代码:
document.addEventListener('DOMContentLoaded', () => {
const nameInput = document.getElementById('name');
const saveButton = document.getElementById('save');
const greeting = document.getElementById('greeting');
// Load the saved name from storage
chrome.storage.sync.get('name', (data) => {
if (data.name) {
nameInput.value = data.name;
greeting.textContent = `Hello, ${data.name}!`;
}
});
// Save the name to storage when the button is clicked
saveButton.addEventListener('click', () => {
const name = nameInput.value;
chrome.storage.sync.set({ name: name }, () => {
greeting.textContent = `Hello, ${name}!`;
});
});
});
解释:
- 该脚本监听 `DOMContentLoaded` 事件,以确保在执行代码之前 DOM 已完全加载。
- 它获取对输入字段、保存按钮和问候段落的引用。
- 它使用 `chrome.storage.sync.get()` 从存储中加载已保存的名称。
- 当点击保存按钮时,它使用 `chrome.storage.sync.set()` 将名称保存到存储中。
- 它使用已保存或输入的名称更新问候段落。
在您的浏览器中重新加载扩展。现在,当您打开弹出窗口时,您可以输入您的名字,保存它,并看到问候消息。该名称将保存在扩展的存储中,并在您下次打开弹出窗口时加载。
示例:使用 Tabs API
让我们创建一个在弹出窗口中显示当前标签页 URL 的扩展。
1. 更新清单文件 (manifest.json)
将 `"tabs"` 权限添加到您的 `manifest.json` 的 `permissions` 数组中:
{
"manifest_version": 3,
"name": "Tabs Example",
"version": "1.0",
"description": "An extension that uses the Tabs API",
"permissions": [
"tabs"
],
"action": {
"default_popup": "popup.html"
},
"icons": {
"16": "images/icon16.png",
"48": "images/icon48.png",
"128": "images/icon128.png"
}
}
2. 创建弹出文件 (popup.html)
创建或更新您的 `popup.html` 文件,内容如下:
<!DOCTYPE html>
<html>
<head>
<title>Tabs Example</title>
<style>
body {
width: 300px;
padding: 10px;
font-family: sans-serif;
}
</style>
</head>
<body>
<h1>Tabs Example</h1>
<p>Current Tab URL:</p>
<p id="url"></p>
<script src="popup.js"></script>
</body>
</html>
3. 创建弹出脚本 (popup.js)
创建一个名为 `popup.js` 的文件,并添加以下代码:
document.addEventListener('DOMContentLoaded', () => {
const urlDisplay = document.getElementById('url');
// Get the current tab's URL
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
const tab = tabs[0];
urlDisplay.textContent = tab.url;
});
});
解释:
- 该脚本监听 `DOMContentLoaded` 事件。
- 它使用 `chrome.tabs.query()` 获取当前窗口中当前活动的标签页。
- 它检索标签页的 URL 并在 `url` 段落中显示它。
在您的浏览器中重新加载扩展。现在,当您打开弹出窗口时,它将显示当前标签页的 URL。
后台脚本和 Service Worker
在 Manifest V3 中,后台脚本被 Service Worker 取代。Service Worker 是事件驱动的脚本,在后台运行而不需要持久页面。它们比后台页面更高效,资源消耗更少。
Service Worker 的主要特点:
- 事件驱动:Service Worker 响应浏览器操作、警报和来自内容脚本的消息等事件。
- 异步:Service Worker 使用异步 API 来避免阻塞主线程。
- 空闲时终止:当 Service Worker 不在活动地处理事件时,它们会被终止,以节省资源。
示例:使用 Service Worker
让我们创建一个在浏览器启动时显示通知的扩展。
1. 更新清单文件 (manifest.json)
更新您的 `manifest.json` 文件,内容如下:
{
"manifest_version": 3,
"name": "Service Worker Example",
"version": "1.0",
"description": "An extension that uses a service worker",
"permissions": [
"notifications"
],
"background": {
"service_worker": "background.js"
},
"icons": {
"16": "images/icon16.png",
"48": "images/icon48.png",
"128": "images/icon128.png"
}
}
解释:
- `"background"` 属性指定了 Service Worker 脚本的路径 (`background.js`)。
- `"permissions"` 数组包含 `"notifications"`,这是显示通知所必需的。
2. 创建 Service Worker 脚本 (background.js)
创建一个名为 `background.js` 的文件,并添加以下代码:
chrome.runtime.onStartup.addListener(() => {
// Display a notification when the browser starts
chrome.notifications.create('startup-notification', {
type: 'basic',
iconUrl: 'images/icon48.png',
title: 'Browser Started',
message: 'The browser has started.',
});
});
解释:
- 该脚本监听 `chrome.runtime.onStartup` 事件,该事件在浏览器启动时触发。
- 它使用 `chrome.notifications.create()` 来显示具有指定属性的通知。
在您的浏览器中重新加载扩展。现在,当您重新启动浏览器时,您应该会看到来自扩展的通知。
内容脚本
内容脚本是在网页上下文中运行的 JavaScript 文件。它们可以访问和修改网页的 DOM,允许您自定义网站的行为和外观。
内容脚本的主要特点:
- 访问 DOM:内容脚本可以访问和操作网页的 DOM。
- 与网页脚本隔离:内容脚本在隔离的环境中运行,防止与网页脚本发生冲突。
- 与后台脚本通信:内容脚本可以使用消息传递与后台脚本通信。
示例:使用内容脚本
让我们创建一个将网页背景颜色更改为浅蓝色的扩展。
1. 更新清单文件 (manifest.json)
更新您的 `manifest.json` 文件,内容如下:
{
"manifest_version": 3,
"name": "Content Script Example",
"version": "1.0",
"description": "An extension that uses a content script",
"permissions": [
"activeTab",
"scripting"
],
"background": {
"service_worker": "background.js"
},
"content_scripts": [
{
"matches": [""],
"js": ["content.js"]
}
],
"icons": {
"16": "images/icon16.png",
"48": "images/icon48.png",
"128": "images/icon128.png"
}
}
解释:
- `"content_scripts"` 属性指定了要注入到网页中的内容脚本数组。
- `"matches"` 指定了内容脚本应该被注入的 URL (`
` 匹配所有 URL)。 - `"js"` 指定了内容脚本的路径 (`content.js`)。
- `"permissions"` 数组包含 `"activeTab"` 和 `"scripting"`,这是注入脚本所必需的。
2. 创建内容脚本 (content.js)
创建一个名为 `content.js` 的文件,并添加以下代码:
document.body.style.backgroundColor = 'lightblue';
3. 创建 Service Worker (background.js)
创建一个名为 `background.js` 的文件,并添加以下代码:
chrome.action.onClicked.addListener((tab) => {
chrome.scripting.executeScript({
target: { tabId: tab.id },
function: () => {
document.body.style.backgroundColor = 'lightblue';
}
});
});
解释:
- 内容脚本只是将 `body` 元素的背景颜色设置为浅蓝色。
- Service Worker 监听点击事件并在当前标签页中执行一个函数,该函数会更改背景颜色。
在您的浏览器中重新加载扩展。现在,当您打开任何网页时,背景颜色将是浅蓝色。
调试浏览器扩展
调试浏览器扩展是开发过程中必不可少的一部分。Chrome 和 Firefox 提供了出色的开发者工具用于调试扩展。
在 Chrome 中调试:
- 打开 Chrome 并访问 `chrome://extensions`。
- 在右上角启用“开发者模式”。
- 为您的扩展点击“检查视图 背景页”。这将为后台脚本打开 Chrome 开发者工具。
- 要调试内容脚本,请打开注入了内容脚本的网页,然后为该页面打开 Chrome 开发者工具。您应该在“源代码”面板中看到您的内容脚本。
在 Firefox 中调试:
- 打开 Firefox 并访问 `about:debugging#/runtime/this-firefox`。
- 在列表中找到您的扩展并点击“检查”。这将为该扩展打开 Firefox 开发者工具。
- 要调试内容脚本,请打开注入了内容脚本的网页,然后为该页面打开 Firefox 开发者工具。您应该在“调试器”面板中看到您的内容脚本。
常用调试技巧:
- 控制台日志:使用 `console.log()` 将消息打印到控制台。
- 断点:在您的代码中设置断点以暂停执行并检查变量。
- 源映射(Source maps):使用源映射以其原始形式调试您的代码,即使它已被压缩或转译。
- 错误处理:实施错误处理以捕获和记录错误。
发布您的扩展
在您开发和测试完您的扩展后,您可以将其发布到 Chrome 网上应用店或 Firefox 附加组件市场。
发布到 Chrome 网上应用店:
- 在 Chrome 网上应用店创建一个开发者帐户。
- 将您的扩展打包成一个 `.zip` 文件。
- 将 `.zip` 文件上传到 Chrome 网上应用店。
- 提供所需的元数据,例如扩展的名称、描述和截图。
- 提交您的扩展以供审核。
发布到 Firefox 附加组件市场:
- 在 Firefox 附加组件市场创建一个开发者帐户。
- 将您的扩展打包成一个 `.zip` 文件。
- 将 `.zip` 文件上传到 Firefox 附加组件市场。
- 提供所需的元数据,例如扩展的名称、描述和截图。
- 提交您的扩展以供审核。
发布最佳实践:
- 为您的扩展撰写清晰简洁的描述。
- 提供高质量的截图和视频以展示您的扩展功能。
- 在提交之前彻底测试您的扩展。
- 及时回应用户的评论和反馈。
- 使您的扩展与最新的浏览器版本和安全补丁保持同步。
安全注意事项
安全性是浏览器扩展开发的关键方面。扩展可能会访问敏感的用户数据并修改网页内容,因此遵循安全最佳实践以保护用户免受恶意代码的侵害至关重要。
主要安全注意事项:
- 最小化权限:只请求您的扩展实际需要的权限。
- 验证用户输入:清理和验证所有用户输入,以防止跨站脚本(XSS)攻击。
- 使用 HTTPS:始终使用 HTTPS 与远程服务器通信。
- 内容安全策略 (CSP):强制执行严格的 CSP,以防止执行任意代码。
- 定期更新您的扩展:保持您的扩展更新至最新的安全补丁。
通过遵循这些安全指南,您可以帮助确保您的浏览器扩展对用户是安全可靠的。
结论
使用 Manifest V3 和 JavaScript API 进行浏览器扩展开发,提供了一种强大的方式来定制浏览体验并为 Web 浏览器添加新功能。通过理解本指南中概述的关键概念、API 和最佳实践,您可以创建功能强大且安全的扩展,从而提高生产力、增强安全性,并为全球用户提供更好的浏览体验。随着 Web 的不断发展,浏览器扩展将在塑造未来在线互动方面发挥越来越重要的作用。拥抱 Manifest V3 和丰富的 JavaScript API 带来的机遇,构建创新且有价值的扩展。