最近做了一个浏览器插件的项目,私以为还是比较有意思的,在此记录一下经历。

这个浏览器插件的主要功能是,提供一个拨号盘界面,可以进行呼入、呼出的功能。再额外添加一些围绕着呼叫的辅助功能,比如:联络记录,通讯录,弹屏等等。

WXT 介绍

为了提高开发效率,我直接查找了可以用的插件开发框架,经过一番搜索最终选择了 WXT

它可以使用流行的前端框架进行开发,它是建立在 Nuxt之上的,而我对 Vue 还算比较熟悉,也就选择了 Vue 这条技术路线一路到底。

即使现在看来,整个开发过程的体验还是很轻松加愉快的。不足之处是,说明文档不是很全,有很多待补充内容,如果找不到想要的内容,只能到 issues 中寻找。

打开 WXT 的官方网站,找到 Get Stared,初始化项目,

1
pnpm dlx wxt@latest init <project-name>

命令执行完成之后,会生成一些模板代码,具体有什么用可以到官网查看 Link

WXT 遵循的是 约定优于配置,每个目录内的文件在最终编译时会转换为对应的文件。

例如:components 内的文件会转换为组件,background 内的文件会转为 ServiceWorker*.content.ts 会转为 content scripts

如果熟悉 Nuxt 的话,composables, hooks, utils 内的文件可以自动导入。像是在使用全局的函数,用起来很方便。

插件内的概念

在开始动手之前,需要先了解一下浏览器插件的概念,有助于开发。

popup 是用户点击插件图标时,弹出的窗口。这个窗口有大小限制,为 800x600。

这个窗口内的内容,可以理解为就是html。框架内编写的vue组件是在这里渲染的。对应 WXTentrypoints 目录中的 vue 文件。

每次打开 popup 时,vue代码都会重新加载。如果想实现一些状态共享的功能,在 popup 关闭时,状态都会清空,所以需要存到 storage (后面讲)中在打开时再次读取。

background scripts

background scripts 是在浏览器后台运行的脚本。在 manifest v3 中,backgound scripts 就是 service worker.

对应 WXTentrypoints/background 目录中的文件。

background scripts 不受跨域影响,可以监听来自 popupcontent scripts 的消息。

content scripts

content scripts 是在浏览器页面中运行的脚本。在页面加载后会注入到页面中。可以操作 DOM 元素。

storage

storage 用来存储数据。类似 localStorage,使用时必须加上前缀,local:session:sync:managed:

localStorage 不同,storage 可以监听值的变化,也可以存储对象值。

storage 的数据可以在 popupbackground scriptscontent scripts 之间共享。

我把它当作 Redis 来用,暂时没发现姿势有什么不对劲。

message

message 用来在 popupbackground scriptscontent scripts 之间传递消息。

主要用法为

1
2
3
4
5
6
7
8
9
// 接受消息
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
// do something
sendResponse();
// 如果发送端需要回复 要返回return true 表明是一个异步消息
return true;
});
// 发送消息
browser.runtime.sendMessage({message: 'hello'});

插件功能介绍

插件通话功能是由 jssip 实现的。页面上实现了登录注册,指定好后端地址,就可以使用通话功能了。

插件的页面组件使用了 vant.

拨号盘和话务功能

这部分我使用 vue 画了一个拨号盘的界面用于用户交互。话务功能 jssip 中有现成的函数,可以拨号,挂断,静音等,直接调用相关函数就可以了。

拨号盘界面需要注意的是,要根据不同的话机状态,显示不同的样式。

因为 jssip 要获取用户媒体和创建 Audio 用于播放铃声,这部分代码只能放到 content scripts 脚本中。

个人暂时觉得还是不太完善,在网上查资料可以有 offscreen.htmlbackground.html 的其他方法,暂未成功。

popup 中的状态,在用户关闭后就会丢失,而且这个窗口很容易被关闭。每次打开时都需要从 content scripts 中同步状态,这也就用到了 storagemessage

来电通知使用了 notifications,如下代码。这一部分倒是没遇到什么问题,jssip 收到来电后,使用 message 发到 background scripts 就可以了。

1
2
3
4
5
6
browser.notifications.create({
type: '',
title: '',
iconUrl: '',
message: '',
});

为了加强插件状态的直观性,在通话和来电时改变图标,可以使用

1
browser.action.setIcon({});

除了 jssipwebsocket 外,插件还需要一个新的 websocket 获取后台系统的消息,以实现弹屏功能。这一部分也放到了 content scripts 脚本中,暂时没遇到什么坑,轻松加愉快。

通讯录

通讯录可以直接使用 vant 内的组件和 storage 来实现。

在使用 storage 存储的时候需要注意,数据是插件内全部可见的。也就是即使我这个插件需要不同的用户先登录后再使用,如果用户A保存了通讯录,用户B登录后也能访问到。

所以在保存这些数据时,需要给数据打上标记,让用户只能访问自己建立的数据。

弹屏功能

弹屏功能是收到来电后,可以打开指定的网页内容。网页可以由用户自行填写,支持内容替换。这样在和其他CRM系统集成的时候,可以方便的调用第三方系统内的功能。

这一部分也比较简单,使用 message 然后在 background scripts 脚本中处理。

1
2
3
chrome.tabs.create({ url });
// or
chrome.tabs.update({ url });

国际化

这一部分使用了 vueI18n

可以参照 WXT示例

没有遇到什么坑点,唯一要注意的是,在 background scripts 中,要这么用

1
i18n.global.t('', {}, { locale: 'en' });

界面截图

screenshot-1 screenshot-2 screenshot-3 screenshot-4

总结

经过这个项目,我熟悉了浏览器插件的开发流程和概念。

幸好用了框架,没有让代码乱成一锅粥。

vue 生态中的资源也能很好的利用上。我想如果后续迭代的话,也很方便快捷。

——————
本文为个人原创,转载请署名且注明出处。