- 简介
- Chrome 插件基础结构
- 入门到实践的核心
- 消息通讯【关键点】
- 小结
- manifest.json的配置解析
- 有机会再做逆向插件的分享以及可玩性~
一、简介
Chrome 插件是扩展浏览器功能的重要工具,为用户带来更加个性化和增强的浏览体验。通过利用 JavaScript、HTML 和 CSS 等 Web 技术,开发者可以创建功能丰富的应用程序,这些插件可以与浏览器深度集成,实现网页内容的修改、功能的扩展以及任务的自动化等多种用途。本文将详细介绍 Chrome 插件的开发流程、架构原理,并提供一些实用的开发技巧。
二、Chrome 插件基础结构
mainfest.json:插件配置文件,定义了插件的名称、版本、权限、入口点等关键信息
background script:背景脚本
生命周期:插件加载 -> 插件关闭
权限:拥有最全的chrome Api权限,如tabs、storage、cookies、contextMenus等
content script:内容脚本
生命周期:页面加载 -> 页面卸载
权限:拥有页面window的所有权
注意⚠️⚠️⚠️ contentScript中的window与页面中的window是完全独立的;
如果要操作页面中的window相关动作;则需要使用注入脚本
inject script:注入脚本,通过内容脚本注入页面
生命周期:页面加载 -> 页面卸载
权限:拥有页面window的所有权
popup: 用户交互页面,浏览器右上角插件icon点击后弹出的ui弹窗
生命周期:弹出 -> 关闭,每次打开popup的window环境都会重置
权限:chrome.runtime,可以通过chrome.runtime.sendMessage与背景脚本交流
sidePanel:侧边栏页面
支持版本:chrome内核115以上 + 插件使用V3版本
生命周期:打开 -> 关闭
权限:与背景脚本权限雷同,如:storage、tabs、runtime等,主要差别在于生命周期
optionsPage:插件的配置页面,允许用户修改插件的设置和配置
三、入门到实践的核心
1、 🚩 熟知各个环境的生命周期以及能力
2、🌟 学习相对环境之间的消息通讯,下方会详细介绍
四、消息通讯
🚩 介绍几种常用的通讯方式
1、第一种
// 发送的一方,发消息
chrome.runtime.sendMessage({ msg: '发送消息' }, res => {
console.log('收到的回调: ', res) // '发送消息'
})
/**
* 监听的一方,监听消息
* @param {any} request 收到的信息
* @param {any} sender 发送者
* @param {Function} sendResponse 回调函数
*/
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
console.log('收到消息: ', request) // { msg: '发送消息' }
sendResponse(request.msg)
// 这里需要return true;sendResponse才可以在异步中调用,及发送着才可以正确接收到回调
return true
})
3、第二种【除“注入脚本”外的环境 -----发送-----> 内容脚本】
/**
* 发送给内容脚本
* @param {number} tabId 标签页id
*/
chrome.tabs.sendMessage(tabId, { msg: '发送消息' }, res => {
console.log('收到的回调: ', res) // '发送消息'
})
/**
* 内容脚本监听消息
* @param {any} request 收到的信息
* @param {any} sender 发送者
* @param {Function} sendResponse 回调函数
*/
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
console.log('收到消息: ', request) // { msg: '发送消息' }
sendResponse(request.msg)
// 这里需要return true;sendResponse才可以在异步中调用,及发送着才可以正确接收到回调
return true
})
3、第三种【注入脚本 <----> 内容脚本】
// 发送的一方,发送消息
self.postMessage({ msg: '发送消息'})
// 监听的一方,监听消息
self.addEventListener('message', event => {
const request = event.data
console.log('收到消息: ', request) // { msg: '发送消息' }
}, false)
4、第四种 chrome.runtime.connect【不推荐,可以忽略】
场景:内容脚本与背景脚本之间的通讯
port.postMessage // 发消息chrome.runtime.onMessage.addListener // 监听消息
缺点;发送消息之前,需要创建连接,给代码增加负担;并且没有回调函数,需要单独监听
// 内容脚本 ----发送----> 背景脚本
// 内容脚本代码
const connectConfig = null // 可以指定长连接名称: { name: 'backConsole' }
const port = chrome.runtime.connect(connectConfig)
port.postMessage({ msg: '发送消息' })
port.onMessage.addListener(res => {
console.log('收到的回调: ', res) // '发送消息'
})
// 背景脚本监听消息
chrome.runtime.onConnect.addListener((port) => {
port.onMessage.addListener((request, { sender }) => {
console.log('收到消息: ', request) // { msg: '发送消息' }
port.postMessage(request.msg) // 回调函数
return true
})
})
🚩 各个环境之间的消息通讯:
【注入脚本与其他环境的通讯】:
1、注入脚本 <----发送----> 内容脚本【第三种】
2、(backgroundScript、popup、sidePanel、options Html)-----发送-----> 注入脚本
⚠️ ⚠️ ⚠️ 无法直接通讯;需要通过内容脚本做中转
【内容脚本与其他环境的通讯】:
1、内容脚本 -----发送----->(backgroundScript、popup、sidePanel、options Html)【第一种】
2、(backgroundScript、popup、sidePanel、options Html)-----发送-----> 内容脚本【第二种】
【其他脚本间的通讯】:
1、popup、sidePanel、options Html、背景脚本;它们之间的通讯【第一种】
⚠️ 需要与 注入脚本 通讯的环境,都需要经过内容脚本
五、manifest.json的配置解析
{
"name": "插件名称", // 插件名称
"description": "插件描述", // 插件描述
"version": "1.0.0", // 插件版本号
"manifest_version": 3, // Manifest 文件版本,V3 表示使用最新的扩展标准
"permissions": [ // 插件的api权限列表
"tabs", // 访问和修改浏览器标签页
"background", // 使用后台脚本
],
"host_permissions": [
"<all_urls>" // 允许插件访问所有网站的 URL
],
"background": { // 背景脚本配置
"service_worker": "src/background/index.js", // 指定后台脚本的路径
"type": "module", // 使用 ES 模块
"persistent": true // 后台脚本是否持久化(V3 默认持久化)
},
"content_scripts": [ // 内容脚本配置
{
"matches": ["http://*/*", "https://*/*"], // 匹配所有 HTTP 和 HTTPS 页面
"js": ["src/content/index.js"], // 内容脚本的路径
"all_frames": true, // 在所有框架中运行内容脚本
"run_at": "document_start" // 内容脚本在文档加载开始时运行
}
],
"web_accessible_resources": [ // 配置可公开访问的资源,通过chrome://...访问
{
"resources": ["inject/index.js"], // 注入脚本
"matches": ["http://*/*", "https://*/*"] // 适用的 URL 匹配规则
}
],
"side_panel": {
"default_path": "sidepanel.html" // 侧边栏页面的默认路径
},
"action": { // popup配置
"default_popup": "popup.html", // 插件图标点击时弹出的 UI 页面
"default_icon": "img/favicon-48.png" // 插件图标的默认路径
},
"options_page": "options.html", // 插件选项页面的路径
"key": "插件的公钥,可以固定插件Id" // 用于签名和验证
}
小结
Chrome 插件开发不仅充满挑战,还蕴含了无限的创新可能。借助 Chrome 浏览器提供的强大 API 和开放的生态系统,开发者能够打造出独特且有价值的用户体验。本文旨在帮助你快速入门,深入了解插件开发的各个环节,开启一段富有成就感的开发之旅。
有用的话麻烦关注收藏一下🌹🌹🌹~
逆向插件的文章后期有机会再做分享!!!
同时欢迎私信交流