1. 开发人员模式
以Edge(Chromium)为例, 可在管理扩展页, 在左侧开发人员模式 打开, 只有此项开启后才能加载未压缩的扩展, 虽然也可以打包扩展, 但是浏览器会检测, 未上线的crx包是无法被安装的. 所以不打算上架的crx只能使用 加载解压缩的扩展 安装
2. 创建扩展
2.1 建立文件夹mycrx
2.2 创建manifest.json
json
{
"manifest_version": 3, // 扩展版本, 现在只能用3
"name": "MyCrx", // 扩展名称
"description": "这是我的扩展描述", // 扩展描述
"version": "1.0.0", // 版本号
"action": { // popup配置
"default_title": "TkImPlus",
"default_icon": "img/logo.png",
"default_popup": "popup.html", // 指定popup页面
},
"author": "AriFe.Liu", // 作者信息, 俗称免费广告位
"background":{ // background.js配置
"type":"module", // 该配置用于使其支持使用import动态导入文件
"service_worker":"service.js" // 指定background.js文件
},
"permissions":[ // 扩展权限, 具体需要使用哪些需要根据自身需求查阅文档
"tabs",
"storage",
"webRequest",
"declarativeNetRequest",
"cookies",
"notifications"
],
"host_permissions":[ // 这个忘了是做什么用的了
"*://*/*"
],
"content_scripts": [ // content.js配置
{
"matches":["*://affiliate-us.tiktok.com/seller/im?*"], // 这里指仅在匹配到该网址时才生效
"js": ["content.js"], // 指定content.js文件
"run_at": "document_idle", // 执行时机
"css": ["content.css"] // 附加的css文件
}
]
}
3. 核心文件说明
3.1 content.js
这个文件是在匹配到指定url时, 会被插入到对应页面中, 在该文件内, 可操作被插入页面的DOM, 也就是说, 如果需要修改页面的样式, 删除某些元素, 插入新的元素, 都可在本文件中实现, 但是它并不能操作页面的JS. 但是可以调用扩展的chrome.runtime, chrome.extension等API.
也就是说, 页面1原生加载的JS1, 这里的content.js就是JS2, 虽然JS都可以操作页面1, 但是JS2和JS1不互通, 也就意味着, 你在content.js里面写的方法等, 通过给页面中的元素附加事件等是无法触发的.
###3.2 background.js
这个文件是在浏览器启动后直接运行在后台的, 它不可操作页面dom, 但是它可以发起跨域请求, 可以调用chrome的更多的api, 可以理解为content是前端, 而background是后端, 比如前端需要跨域调用接口等, 可以直接告知background来进行处理获取后返回.
3.3 popup
这个是点击扩展图标时弹出的页面, 焦点移开就会关闭, 一般用来做些临时的交互, 这个页面大小会自适应, 但是最大好像宽度只有750px, 高度应该只有550px, 所以最大只有这么大的话, 可以自己考虑自己的扩展有什么是需要放在这里用的
3.4 inject.js
这个文件是为了弥补content.js无法操作页面JS而衍生出来的, 这个就和页面中的普通JS一样, 页面原本附带的JS能做什么它也能做什么. 而且也不能调用扩展的API
3.5 other
除了这些还有一些其它的, 但我做过的几个实际上并没有用到过, 一般来说仅靠content和background就可以完成绝大部分操作. content不能执行的操作,例如跨域等, 就发消息给background来操作, 然后监听后台发来的消息再进行下一步处理
4. 通信说明
短链接
在content中, chrome.runtime.sendMessage即可发送消息给background
在background中, chrome.runtime.onMessage.addListener((data,sender,sendResponse)=>{})即可接收并发送响应. 但在实际开发中, 我发现在接受消息时如果处理事件耗时过长(比如此时执行了fetch等), 则content就会收不到消息, 报错提示大意是说,在发送消息给指定端口时, 这个端口已经被关闭了. 也有可能是因为异步操作等原因, 我处理的有问题, 但实际测试了很多次没找到什么办法解决.所以引出了我使用长连接的案例
长链接
在content中, chrome.runtime.connect即可发起长连接请求, 返回port, 再使用port.postMessage可发送消息, 使用port.onMessage.addListener监听消息
在background中, chrome.runtime.onConnect.addListener用来监听连接请求, 使用方法也挺简单, 具体可以看下方参考资料
在实际使用中我发现, 长连接好像是会自动断开的, 查询官方文档, 意思大概是说30秒没有交互后, 这个连接就会被休眠. 官方建议是自行处理这些异常的发生, 同时建议使用chrome.stroge来存储信息而不是使用全局变量
在很多业务中, 使用content和background,搭配上通信即可实现绝大部分需求
5. 相关资料
【干货】Chrome插件(扩展)开发全攻略 - 我是小茗同学 - 博客园
API 参考 | Chrome for Developers
扩展程序 | Extensions | Chrome for Developers