Chrome插件开发

最近一直在开发插件,踩了些坑,这里总结下。

popup程序化弹出?

popup不支持程序化弹出,曲线解决的方案是,开启新window,打开popup.html即可。

1
2
3
4
5
6
7
8
9
 chrome.windows.create({
url: `popup.html`,
type: 'popup',
height: 640,
width: 357,
left: 100,
top: 100,
focused: true,
})

window resize禁用

1
2
3
4
5
6
7
8
9
10
const size = [document.body.clientWidth, document.body.clientHeight];  

/**
* 禁止修改 popup弹窗大小,new window时无法直接设置禁用resize,因此通过该方法解决
*/
function resizeThrottler() {
window.resizeTo(size[0], size[1]);
}

window.addEventListener('resize', resizeThrottler, false);

消息通讯

chrome extension中资源分三种,popup/content/background,能够与网页直接通讯的是content,因此如果是popup向网页发消息。可以发给content,然后content转发消息给网页即可。

content.js中接收消息使用chrome.runtime.onMessage,而发送消息给网页使用window.postMessage

1
2
3
4
5
6
chrome.runtime.onMessage.addListener(
(message, sender, sendResponse) => {
window.postMessage(message, '*');
return true;
},
);

popup向content.js发送消息使用chrome.tabs.sendMessage

1
chrome.tabs.sendMessage(tabId, message);

同时,Chrome也可以接收网页发送过来的消息

网页发送消息给extension使用chrome.runtime.sendMessage

1
2
3
4
5
6
7
8
9
10
var hasExtension = false;
const extensionId = 'bmkmhpkgcbigmdepppdpdhlifcgoibph';
chrome.runtime.sendMessage(extensionId, {operation: "installCheck"},
function (reply) {
if (reply && reply.data.version) {
hasExtension = true;
} else {
hasExtension = false;
}
});

extension-background接收消息使用chrome.runtime.onMessageExternal.addListene

1
2
3
chrome.runtime.onMessageExternal.addListener((request, sender, sendResponse) => {

})

chrome.runtime返回undefined

网页向拓展发送消息,需要确保设置中externally_connectable能够命中网页,否则chrome.runtime返回undefined

举个配置例子

1
2
3
4
5
6
"externally_connectable": {
"matches": [
"https://*.19991421.cn",
"http://127.0.0.1/*"
]
}
  1. http://*/*https://*/*无法命中IP地址及localhost域名,因此内网网址这些,需要单独配置,
  2. 端口号不需要考虑,默认都是通配。
  3. 这里并不建议配置http://*/*https://*/*,虽然它可行,但浏览器插件中会提示errorWildcard domain patterns such as "http://*/*" are not allowed

popup最大宽高

宽度最大800px,高度最大600px。HTML标签层面会强制给予该大小,如果子标签宽高大于该值,会滚动显示。

推荐尺寸600px高,357px宽

DevTools failed to load source map: Could not load content

Chrome插件只支持inlinemap,因此需要修改构建工具配置,不要使用分离的source map配置,使用比如inline-source-map

hot reload

插件不同于普通的WEB开发,所以热更配置不同,这里推荐使用ExtensionReloader插件,配置如下

1
2
3
4
5
6
7
new ExtensionReloader({
port: 9090, // Which port use to create the server
reloadPage: true, // Force the reload of the page also
entries: {
popup: "popup", background: "eventPage", contentScript: "contentScript"
}
})

注意entries中属性值即webpack中entry下配置的入口名,非物理文件路径名。

插件模版-实践

以上这些配置都可以在模版中查看

https://github.com/alanhg/chrome-extension-react-typescript-boilerplate

插件更新

  1. 官方商店分发
    该方式下,插件会自动更新,关于自动更新频率,可能是5小时
  2. 自行托管分发包
    • update_url字段,但方式下,托管的是crx已经签名分发的包,如果是未签名的不行。
    • 更新包必须是CRX文件
1
2
3
4
5
6
{
"name": "My extension",
...
"update_url": "http://myhost.com/mytestextension/updates.xml",
...
}
1
2
3
4
5
6
<?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
<app appid='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'>
<updatecheck codebase='http://myhost.com/mytestextension/mte_v2.crx' version='2.0' />
</app>
</gupdate>
  1. 开发包
    自定义逻辑实现check,比如popup弹出时提示或者定时器check,有更新推送notification。用户下载新包进行覆盖即可。覆盖后重启浏览器或插件页面手动点击更新

manifest.json配置修改

修改后,浏览器需要重启生效

修改页面window

写在最后

先写到这儿,持续更新

相关文档