一、什么是插件(Plug-in),什么是扩展(Extension)。

插件指的是在页面HTML源代码里通过<object> 或者 <embed> 标签声明的部分,工作在内核层面的一种扩展技术,与浏览器无关,理论上可以用任何一种生成本地可执行文件的语言开发,比如C/C++、Delphi、VB、VS.Net等等,目前主流的浏览器插件技术主要有以下几种:

  1. ActiveX,由Microsoft提出,仅Internet Explorer(IE)浏览器支持,微软最新的Edge浏览器不再支持ActiveX技术。
  2. NPAPI(Netscape Plugin API),由Netscape提出,FireFox、Chrome等非IE浏览器基本都支持该项技术,不过后来因为安全性问题,Chrome从45版本之后放弃了对NPAPI的支持另搞了一套PPAPI技术,FireFox从53版本开始也放弃了对NPAPI的支持,据说Chrome的开源版本Chromium还可以用,不管怎么样这种技术的淘汰只是时间的问题。
  3. PPAPI(Pepper Plugin API),是 Google 在原有网景 NPAPI基础上搞的,它将插件放到沙盒里运行,所以具有更高的安全性。 目前只有 Chrome 浏览器及基于 Chromium 内核的浏览器支持。

扩展指的是利用浏览器提供的API来扩展浏览器功能的一种组件,工作在浏览器层面,通常使用HTML + Javascript 语言开发,与浏览器相关,与页面的HTML源代码无关。因此插件与扩展实质是两种不同的东西。

好了,废话不多说,下面进入FireFox浏览器扩展开发的详细介绍。

二、manifest.json

首先使用记事本一类的文本编辑器新建一个文本文件,然后在文件中输入以下内容后另存为manifest.json。

{"description":"Firefox extension demo description","name": "Firefox extension demo",    "manifest_version":2,  "version":"1.0","icons":{"48": "ICONS/ICON_48.png","64": "ICONS/ICON_64.png"},"applications":{"gecko":{"id": "demo@demo.com","strict_min_version": "50.0"}},"background":{"scripts":["background.js"]},"browser_action":{"default_icon":{"48": "ICONS/ICON_48.png"}}, "permissions":["nativeMessaging"]
}

manifest.json是扩展的配置文件,主要作用是向FireFox浏览器说明扩展的名称、介绍、图标路径、版本、浏览器版本、后台脚本等基本信息。其中:

"name":扩展的名称,必须项。

"manifest_version" :manifest版本,必须项,且目前值必须为2。

"version":当前扩展的版本,必须项。

"icons":图标列表,可选项,它由图像大小(以px为单位)的键值对以及相对于manifest.json文件所在目录的图像路径组成,最好是至少提供一个48*48像素大小的图标,如果没有的话浏览器会使用标准扩展名图标,如果有多个图标的话浏览器会根据实际情况自动选择最合适的大小。

"applications":在Firefox 48版本之前为必须项。目前只包含了一个键:gecko,其中包含了4个属性:

  • id即扩展名ID。从Firefox 48起为可选项,在此之前为必须项,如果没有指定的话浏览器会随机分配一个,如果要实现与原生应用之间的消息传递则必须指定。
  • strict_min_version:Gecko所能支持的最小版本号。可以使用“ *”来定义版本号。替换为“ 42a1”。
  • strict_max_version:Gecko所能支持的最大版本号。如果安装或运行附加组件的Firefox版本号高于这个最大版本号,附加组件将不能运行或替换被安装。替代“ *”,意味着为不对最大版本号做检查。
  • update_url: 更新地址链接。注意链接必须以“ https”开头。这是为了使你自己就能够管理附加组件的更新。

"background":后台页面及脚本列表,可选项,通过background可以引入一个或者多个后台脚本文件,以及一个可选的后台页面文件。当扩展被加载的时候就会自动加载background中的内容并一直运行,直到扩展被禁止或卸载。

"browser_action":扩展在浏览器工具栏上的按钮,可选项,该按钮有个图标,并可拥有一个使用 HTML,CSS,和 JavaScript 指定内容的弹出窗口(popup)。如果使用弹窗,则该弹窗将在用户点击该按钮时打开,并且由弹窗中所提供 JavaScript脚本来处理用户与弹窗的交互。如果不使用弹窗,则会在用户点击该按钮时将点击事件传递给background中定义的JavaScript脚本。

"permissions":授权列表,可选项,因为需要与原生应用之间进行消息传递,所以必须具备“nativeMessaging”授权。

详情可参考官网:https://developer.mozilla.org/zh-CN/docs/Mozilla/Add-ons/WebExtensions/manifest.json

三、后台处理程序(background.js)

由于上文的manifest.json示例中"browser_action"项没有定义弹出窗口,所以用户点击浏览器工具栏中扩展对应的快捷按钮时,点击事件会传递给background中定义的background.js脚本,以下是background.js脚本的示例:

function onResponse(response) {console.log("background Received " + JSON.stringify(response));
}function onError(error) {console.log(`background Error: ${error}`);
}/*
On a click on the browser action, send the app a message.
*/
browser.browserAction.onClicked.addListener(() => {var JsonObj = {"name":"张三","sex":"男"};console.log("send:"+JSON.stringify(JsonObj));var sending = browser.runtime.sendNativeMessage("demo",JsonObj);sending.then(onResponse, onError);
});

这段代码的实际作用是给浏览器工具栏中扩展对应的按钮添加了一个侦听器来监控按钮的点击事件,当点击按钮时通过browser.runtime.sendNativeMessage方法将JsonObj对象作为参数传递给名为demo的原生应用,并通过回调函数onResponse和onError来处理demo反回的消息和错误。

详情可参考官网:https://developer.mozilla.org/zh-CN/docs/Mozilla/Add-ons/WebExtensions/API/runtime/sendNativeMessage

四、原生应用的配置文件(demo.json)

上面通过sendNativeMessage方法把JsonObj对象发送给了名为demo的原生应用,那么这个demo究竟是个什么东西呢,因此还需要一个配置文件(demo.json)来向浏览器进行说明,以下是demo.json的示例:

{"name": "demo","description": "demo native app","path": "/usr/bin/demo","type": "stdio","allowed_extensions": [ "demo@demo.com" ]
}

其中:

"name"必须和browser.runtime.sendNativeMessage("demo",JsonObj)中的第一个参数"demo"保持一致。在 OS X 和 Linux 中,它必须和配置文件的文件名保持一致(除.json文件扩展名外)。在 Windows 中,它必须和注册表项的名称一致。只能包含小写字母、数字、下划线和 . ,并且不允许开头或结束是 . ,并且 . 后面不能是 . 。

"type"必须是"stdio"。

"allowed-extensions"中列出了可以与该原生应用通信的ID,也就是说必须包含上面manifest.json中gecko项下id对应的值。

"path"指定了原生应用的具体路径和文件名,Windows下可以是相对路径,在 OS X 和 Linux 中,必须是绝对路径。

那么这个demo.json具体应该存放在什么位置呢?

  • 如果是Windows平台,那么需要在注册表项HKEY_LOCAL_MACHINE\SOFTWARE\Mozilla\NativeMessagingHosts\或者HKEY_CURRENT_USER\SOFTWARE\Mozilla\NativeMessagingHosts\下新建一个名为demo的项,其默认值为demo.json文件的路径。

  • 如果是Mac OS X平台需要把demo.json复制到/Library/Application Support/Mozilla/NativeMessagingHosts/或者~/Library/Application Support/Mozilla/NativeMessagingHosts/目录下

  • 如果是Linux平台需要把demo.json复制到/usr/lib/mozilla/native-messaging-hosts/或者/usr/lib64/mozilla/native-messaging-hosts/或者~/.mozilla/native-messaging-hosts/目录下

详情可参考官网:https://developer.mozilla.org/zh-CN/docs/Mozilla/Add-ons/WebExtensions/Native_manifests#%E6%B8%85%E5%8D%95%E8%B7%AF%E5%BE%84

五、原生应用的开发

原生应用也就是上面demo.json中path指向的可执行文件,该可执行文件必须采用stdin来接收消息,stdout来发送消息,每条消息必须序列化成UTF-8格式的JSON数据,在消息之前有4个字节长度的数据来表示消息的长度,浏览器发送给原生应用的单条消息最大是1MB,总消息不得超过4GB。

以下是C的代码,使用了cJSON库来处理JSON数据。

#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cJSON.h"void my_handler(int);
void setCatchSignal();
unsigned int message_in(unsigned int,char *);
unsigned int message_out(char *);
unsigned int message_in_len(void);volatile bool bCommunicationEnds=false;             //结束通讯标志int main(int argc, char* argv[])
{    setCatchSignal();                              //拦截信号          char *inbuff;do {       unsigned int len=message_in_len();          //取输入内容长度inbuff=(char *)malloc(len);                    //申请空间      message_in(len,inbuff);                     //接收数据      cJSON *inmessage=cJSON_Parse(inbuff);       //转json对象       message_out(cJSON_Print(inmessage));        //输出cJSON_Delete(inmessage);                    //删除json对象free(inbuff);                             //释放空间              }while(!bCommunicationEnds);return 0;
}void my_handler(int s){ bCommunicationEnds=true;
}void setCatchSignal(){struct sigaction sigHandler;  sigHandler.sa_handler = my_handler;  sigemptyset(&sigHandler.sa_mask);  sigHandler.sa_flags = 0;  sigaction(SIGTERM, &sigHandler, NULL);
}//接收消息函数
//inbuff : 接收到收到的数据
unsigned int message_in(unsigned int len,char *inbuff){ for(int i=0;i<len;i++){                         //读入传递的参数内容         inbuff[i]=getchar();            } return len;
}//取消息长度
//return : 消息长度
unsigned int message_in_len(void){unsigned int len=0;   for(int i=0;i<=3;i++){len +=getchar();}return len;
}//返回消息函数
//outbuff : 需要输出的内容
unsigned int message_out(char *outbuff){unsigned int len=strlen(outbuff);               //计算需要输出的内容长度   putchar(char(((len>>0) & 0xFF)));             //输出长度,4字节putchar(char(((len>>8) & 0xFF)));putchar(char(((len>>16) & 0xFF)));putchar(char(((len>>24) & 0xFF)));for(int i=0;i<len;i++)                       //输出内容putchar(outbuff[i]);fclose(stdout);                               //关闭输出流结束输出return 0;
}

按照FireFox官网的说法,浏览器与原生应用之间的消息传递有两种模式,基于连接的消息传递和无连接消息传递。

  • 基于连接的传递方式,通过runtime.connectNative()方法返回一个Port对象,再通过Port对象的postMessage()方法发送消息,最后通过Port对象的disconnect()方法或关闭与其连接的页面来关闭原生应用。
  • 基于无连接的传递方式,直接通过runtime.sendNativeMessage()来发送消息,原生应用在收到消息并发送响应后关闭。然而实际上在C里面不使用fclose(stdout)去主动关闭stdout的话原生应用并不会自动退出,c++里面用cout进行输出的话却没有这个问题不知道是为什么,对于一个C/C++的菜鸡来说确实困扰了我好久。

详情可参考官网:https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_messaging

六、测试

打开FireFox浏览器,地址栏中输入about:addons回车后打开扩展管理界面,如下图所示:

点击"调试附加组件"如下图所示:

点击"临时载入附加组件",然后选择manifest.json文件,打开后载入浏览器扩展,再点击"检查"进入控制台,如下图所示:

最后点击FireFox工具栏中扩展对应的按钮看到结果,如下图所示:

七、打包和发布

将manifest.json及其中引用到的各类图标、js脚本、html、css等文件制作成一个.zip包,登录addons.mozilla.org提交获取签名,签名之后就可以安装使用了。

详情可参考官网:https://extensionworkshop.com/documentation/publish/

开发FireFox浏览器扩展(Extension)并实现与原生应用之间的消息传递相关推荐

  1. Firefox常用扩展(extension)推荐

    [color=blue]Fasterfox[/color] » Firefox 性能和网络优化. [url]http://addons.mozine.cn/firefox/88/[/url] [col ...

  2. 浏览器扩展开发系列教程(一)

    以谷歌内核的浏览器扩展,包括 edge chrome ,还有我们常用的国产浏览器都能使用 浏览器扩展是一种软件,以增强Chrome内核浏览器的功能.浏览器扩展使用HTML.JavaScript.CSS ...

  3. 【论文阅读】浏览器扩展危害-Helping or Hindering? How Browser Extensions Undermine Security

    本文来源于ACM CCS 2022: https://dl.acm.org/doi/10.1145/3548606.3560685 摘要 "浏览器扩展"是轻量级的浏览器附加组件,使 ...

  4. css 好困难字体样式_帮助阅读困难者的字体和浏览器扩展

    css 好困难字体样式 G-Stock Studio/Shutterstock G-Stock Studio / Shutterstock Dyslexia is a learning conditi ...

  5. firefox浏览器邮件通知插件

    firefox浏览器扩展真的很丰富,这里给大家介绍的是一个邮件通知插件.虽然一些客户端软件都可以实现实时邮件通知,但是我还是不习惯在自己电脑开机运行很多程序.如果你和我有一样的想法,那么就可以试试这个 ...

  6. Firefox 浏览器

    文章目录 Firefox 浏览器 扩展 Firefox 浏览器 扩展 划词翻译 https://addons.mozilla.org/zh-CN/firefox/addon/hcfy/ AdBlock ...

  7. Firefox浏览器代理插件——FoxyProxy

    问题描述 前期使用BurpSuite工具进行抓包时,配置了Firefox浏览器代理:导致 不运行BurpSuite工具且不关闭拦截时,Firefox浏览器无法使用. 因此!于是!   我找到了Foxy ...

  8. 常见浏览器扩展开发笔记(chrome firefox 360 baidu qq sougou liebao uc opera)

    浏览器扩展开发貌似时下很冷门啊,但是不少企业还是有类似的应用,360的抢票插件啊,笔者最近在做的网页翻译扩展之类的.笔者在开发的过程中,遇到了不少坑,说是坑,说白了就是各个厂商支持的API不统一导致的 ...

  9. Firefox(火狐)浏览器扩展开发初探

    最近开发一个FF的扩展,自动完成公司的订餐操作,主要完成的功能很简单:登陆网站,执行一个特定操作,并在ff的状态栏内显示执行的成功或者失败的状态.以前没有写过FF扩展,需要从头学习,在完成这个扩展过程 ...

最新文章

  1. 3G网络关闭,4G还会远吗?
  2. 极简版 卸载 home 扩充 根分区--centos7 xfs 文件格式
  3. EventBus in SAP UI5 and Kyma
  4. java requestbody map_@RequestBody 的正确使用办法
  5. 【2018.3.17】模拟赛之一-ssl2574jzoj1368 无限序列【斐波那契数列】
  6. servlet中实现页面跳转return “r:”和return “f:
  7. 听到表扬的飞鸽传书2011
  8. 【JS基础】异步和单线程
  9. 物联网云平台有哪些优势
  10. react环境搭建(-)
  11. 2021年了,Transformer有可能替代CNN吗?未来有哪些研究方向?
  12. 使用CleanMyMac的空间透镜功快速决策清理垃圾
  13. tomcat处理连接的详细过程
  14. redis设计与实现 二
  15. CSS Sprite雪碧图应用
  16. linux嵌入式做智能家居,嵌入式系统在智能家居中的应用
  17. python股票策略_用Python编程彼得林奇PEG价值选股策略
  18. 铁甲雄心机器人冠军_《铁甲雄心》第二季首播 优必选科技引领中国AI机器人进击之路...
  19. WACV 2021 论文大盘点-目标检测篇
  20. 纤亿通带你去看空分复用光纤技术突破

热门文章

  1. 制作winpe ISO(x86/amd64/ARM)
  2. opencv 傅立叶变换及其逆变换实例及其理解1
  3. Python由来以及用途
  4. .NetCore WPF应用Nlog日志模块
  5. C语言基础知识:checksum += (0x000000FF) *a++;    以及 *( (unsigned int *)a ) = checksum;  的理解
  6. navicat连接出现ORA-01017: invalid username/password
  7. SpringBoot-quartz配置页面可视化任务调度
  8. selenium淘宝爬虫
  9. ssm班级管理系统的设计与实现
  10. scratch案例——双人赛跑