创建您自己的浏览器扩展,第 2 部分: 将您的触角延伸至 Firefox

为 Firefox 编写一个基础浏览器扩展

每个浏览器都有其自己的支持者、批评者、优势和劣势。它们的共同点是人们将越来越多的时间花费于其中。本 系列 文章将介绍如何为 Chrome、Firefox 和 Safari 构建相同的基础扩展。您将了解到扩展每个浏览器是什么样子,执行这些常见任务是困难还是简单,以及如何发布您的扩展。在本文中,您将构建一个 Firefox 扩展。

Duane O'Brien, 软件开发人员, Freelance

Duane O'Brien 的照片Duane O'Brien 是一名硕果累累的计算机科学家。他撰写了许多关于开发 Web 应用程序和各种 PHP 框架的文章。要想了解 Duane 的更多信息,请访问 他的博客 或阅读他的 微博



2013 年 8 月 01 日

Gawkblocker 扩展

关于本系列

在这个四部分 系列 中,分别为 Chrome、Firefox 和 Safari 这三个浏览器构建 Gawkblocker 扩展。

  • 第 1 部分 中,介绍您的 Google Chrome 扩展,从开始直到进入应用程序商店。
  • 在本文中,为 Mozilla Firefox 构建一个附件(或扩展)。
  • 在即将发布的第 3 部分中,为 Safari 浏览器量身定制扩展。
  • 在即将发布的第 4 部分中,调整与浏览器无关的扩展代码。

回忆一下,Gawkblocker 支持您(以及其他用户)屏蔽某些您不喜欢访问的域,比如耗时的博客。Gawkblocker 有以下组件:

  • 一个弹出窗口(显示您将要屏蔽的域)
  • 一个可见的浏览器图标(扩展的入口点)
  • 一个选项页面(配置您想要屏蔽以及想要访问的域)

在 Chrome 中,Gawkblocker 扩展将向每个选项卡或窗口添加一个监听程序,并与黑名单进行匹配,这会将屏蔽的 URL 重定向到一个本地页面。现在,您将学习 Gawkblocker 扩展在 Firefox 中如何变化。

Gawkblocker 以特定的方式扩展至浏览器,进行一些将在其他扩展中进行的特定工作。正如 第 1 部分 所述,您需要回答以下这些问题:

  • 在浏览器 UI 中拥有一席之地有多难?
  • 持久化浏览器会话间的数据涉及到什么?
  • 不同扩展部分彼此如何通信?
  • 您对用户数据的研究有多深入?

完成 Firefox 的 Gawkblocker 构建流程后就可以回答这些问题。


开始之前

附件就是扩展

Firefox 扩展被称为附件。Chrome、Safari 和 Internet Explorer 都使用扩展 这一术语。本系列在提及 Firefox 附件时将交替使用这两个术语。

对于本文,您需要下载和安装 Firefox V12 或更高版本(参阅 参考资料)。(本文示例也是基于 Firefox V12)您也需要一些可以编辑 HTML、CSS 和 JavaScript 的工具。如果您有使用 Firefox 或者 Firefox 附件的经验将会很有帮助。如果没有这方面的经验,那么请浏览 Mozilla Add-ons 页面上提供的扩展(参阅 参考资料)。试用一下本文提供的几个上下文扩展。

您的参考文档是 Mozilla Add-on SDK 开发人员指南(参阅 参考资料)。您可使用 Add-on Builder( 一个基于 Web 的工具,用于构建 Firefox 扩展)完成大多数工作。Add-on Builder 是 Jetpack(一个 Firefox 项目)的一部分。Jetpack 的目的是使仅使用 HTML、CSS 和 JavaScript 编写扩展变得更为容易(正如您为 Chrome 扩展所做的一样)。也可使用 其他方法 来构建 Firefox 扩展。

下载 部分获取完整源代码。


Firefox 扩展剖析

其他方法

除了本文展示的流程之外,也可以选择其他方法来为 Firefox 构建扩展。您可以下载 SDK 文件,Add-on Builder 可直接从 Developer Hub(参阅 参考资料)获取该文件。下载 SDK 文件,以便您可以在构建附件时选择使用 IDE。

您也可以构建一个传统的(或经典的 或 XUL)扩展。以这种方法构建扩展存在缺陷:安装扩展需要重启,编写扩展的过程较为复杂。但好处是您可以修改浏览器,这是使用 Add-on Builder 或 SDK 所不能实现的功能。例如,除了 Add-on 栏之外,也可以使用 XUL 将扩展图标放置到位。您可以在 Mozilla Development Network 上阅读有关 XUL 扩展的更多信息(参阅 参考资料)。

使用 Add-on Builder 构建的 Firefox 扩展可使用 CommonJS 约定导入所需的库。扩展中可以包括 HTML、CSS 和 JavaScript 文件的任意组合,但都是以 main.js 文件开始。

main.js 文件是 Firefox 扩展的核心。该文件告诉 Firefox 导入哪个模块,以及在何处执行扩展的初始化任务。回顾 第 1 部分 中的 Chrome 扩展。main.js 类似于 background.html 页面。main.js 在后台运行,与 Firefox 没有直接交互,而且在启动过程中仅运行一次。

也可以将大量页面显示在 Firefox 扩展的 panel 中。可以将这类页面作为一个弹出和选项窗口的组合页面,如图 1 所示:

图 1. 弹出/选项页面
Gawkblocker 弹出/选项页面屏幕截图

您也可以使用 Firefox 中的内容脚本,与在 Chrome 中使用的方法基本相同。内容脚本是可以添加到 Web 页面进行交互的 JavaScript 文件。在 Firefox 中,内容脚本可在页面上下文中有效地运行。但是访问 DOM 或从 DOM 中获取都可以进行代理以防止出现安全问题。内容脚本可使用 port 与其他扩展进行通信。

对于 Gawkblocker,您可以使用:

  • 一个 main.js 文件
  • 一个包含核心功能(大多数都是从 Chorme 扩展中移植过来)的 JavaScript 文件
  • 一个弹出/选项窗口的组合页面
  • 一个或两个图标

Firefox 实现比 Chrome 略微简单点,但是用户体验效果实际上是一样的。您可以从我的 Add-on Builder 配置文件(参阅 参考资料)中下载一个正在运行的 Gawkblocker 文件来查看活动的扩展,和我在此处介绍的其他部分一样。


使用 Add-on Builder

要使用 Add-on Builder,根据图 2 所示以及在 https://builder.addons.mozilla.org/ 中提供的信息,必须完成注册过程。然后,可以登录到 Add-on Builder 创建自己的附件。

图 2. Add-on Builder
Mozilla Add-on Builder 屏幕截图

构建 Add-on Builder 界面的完整过程不在本文的讨论范围之内,但是在文件结构中有两点需要注意。Lib 目录是使用 require 导入库时 Firefox 所要查找的目录。您可以将 Gawkblocker 的核心 JavaScript 类放在该目录下。Data 目录是存放图像、HTML、CSS 和扩展可能提供的其他资产的位置。

当构建一个附件并对其进行测试时,可能会提示您安装 Add-on Builder 帮助程序。该帮助程序可在开发过程中卸载和安装附件。


更新 Gawkblocker 核心类

第 1 部分 中,已经为 Gawkblocker 编写了一个看上去合理的可移植核心类文件。现在,如果在 Firefox 扩展中使用,您就会发现这个类文件实际上非常方便。

事实证明,您必须进行一些重要改变:

  • 使用 Firefox simple-storage 扩展 API 代替 localStorage
  • GB 对象添加到 exports

第 1 部分 的类文件中,定义了一个 Storage Manager 对象(名为 SM)— 一个 localStorage 包装程序 — 来处理会话间的数据持久化。该代码在 Firefox 扩展内不能运行。相反,Firefox 提供一个名为 simple-storage 的 API,为您实现数据持久化。您可以轻松地更新 第 1 部分 中的 Storage Manager 对象,如清单 1 所示:

清单 1. 更新 SM 对象
var SM = (function () {
    var SS = require("simple-storage");
    var my = {};
 
    my.get = function (key) {
        return SS.storage[key];
    }
    ...

    return my;

}());

GB 对象不需要改变,但是您必须依照 CommonJS 约定将其添加到 exports 。清单 2 的最后一行处理该任务:

清单 2. 将 GB 对象添加到 exports
var GB = (function (SM) {
   var my = {};

   my.blockTheseSites = {
       "gawker.com"        : "Gawker Media",
       "io9.com"           : "SciFi Blog",
       "gizmodo.com"       : "Gadget Blog",
       ...
   }

   ...

}(SM));

exports.GB = GB;

由于变化微乎其微,所以您可以轻松地将它们合并到 GB 对象,使其在 Firefox 或 Chrome 中均可运行(我将其留给您,可根据自己项目的需要进行实现。)

将文件重名为 GB.js,然后上传到 Lib 目录。这样您就可以看到在 main.js 中如何使用该对象了。


Gawkblocker 中的 main.js 文件

在 Chrome 中,使用后台页面文件检查 URL,查看是否屏蔽。在 Firefox 中,在 main.js 文件中进行这一项检查。在 main.js 进行任何操作之前,必须使用一系列 require 语句导入计划使用的模块和 API,如清单 3 所示:

清单 3. require 语句
var data = require("self").data,
    tabs = require("tabs"),
    GB = require("GB").GB,
    popupPanel = require("panel").Panel({
        height: 500,
        contentURL: data.url("popup.html")
    });

清单 3 中的语句依次告诉 main.js 为您提供:

  • 一个可用于访问 Data 目录的对象
  • 一个处理选项卡的对象
  • 从主类导出的 GB 对象
  • 一个保存弹出窗口的 popupPanel 对象,该代码也可创建弹出窗口。

此外,由于创建的弹出窗口也可作为选项页面,因而必须构建一些监听程序。在 Chrome 中,您可以利用后台页面并告诉它您想要做什么。在 Firefox 中,可以将消息发送到 main.js 文件来实现同样的目的。例如,清单 4 展示了一个将默认登录页面设置为用户选择屏蔽网站的监听程序:

清单 4. 将默认登录页面设置为用户选择屏蔽网站的监听程序
popupPanel.port.on("watchthis", function () {
    GB.setWatchThisInstead(http://www.youtube.com/watch?v=N-uyWAe0NhQ);
    console.log("watchthis");
});

在我们讨论弹出页面时,也可以过一会将消息传递到该端口。

在 main.js 文件中,Gawkblocker 也可以访问选项卡以查看用户想要屏蔽哪个 URL(如果有的话)。清单 5 显示侦听选项卡以进行更新的代码:

清单 5. 侦听选项卡进行更新
tabs.on("ready", function checkForBlock(tab) {
    for (site in GB.getBlockedSites()) {

        if (tab.url.match(site)) {
            tab.url = GB.getWatchThisInstead();
        }
    }
});

功能和性能类似于您在 Chrome 中所进行的操作,API 的使用也类似于 Chrome(调用一个方法,传递一个回调函数)

最后,将这个小徽章添加到浏览器右下角,创建一个 Widget,如清单 6 所示:

清单 6. 创建一个 Widget
require("widget").Widget({
    id: "GBBrowserAction",
    label: "Gawkblocker",
    contentURL: data.url("images/GB-19.png"),
    panel: popupPanel
});

当 main.js 文件一切就绪后,就可以深入研究弹出页面的变化。


弹出页面

在 Chrome 扩展中,弹出页面仅仅是一个屏蔽域列表。现在正是对该设计进行迭代的良好时机。对于 Firefox 扩展,将功能从选项页面迁移到弹出页面。然后将一个单击处理程序添加到弹出页面中显示的标题上,该页面将选项 div 和域列表互换。该选项允许用户站点访问屏蔽列表,并为屏蔽站点提供重定向地址。图 3 显示了 Gawkblocker 弹出页面中的选项:

图 3. Gawkblocker 弹出页面中的选项
Add-on Builder 屏幕截图显示了 Gawkblocker 弹出页面中的选项

当您在 清单 4 中建立一个端口时,记得侦听 main.js 中的 watchthis。在清单 7 中,您可以使用 addon.port.emit 从弹出页面发送消息:

清单 7. 使用 addon.port.emit 从弹出页面发送消息
$("#watchthis").click(function () {
    addon.port.emit("watchthis");
    $("#status").text("YOU'RE GOOD MATE.  ");
});

您也可以通过使用 port 侦听该列表,以便从 main.js 中获取屏蔽站点列表。在 main.js 中,当弹出页面告诉您一切准备就绪时就发送该列表,如清单 8 所示:

清单 8. 当弹出页面告诉您一切准备就绪时就发送列表
popupPanel.port.on("pop", function () {
    popupPanel.port.emit("blocklist", GB.getBlockedSites());
    ...
});

在弹出对象中,可以侦听和修改页面,如清单 9 所示:

清单 9. 侦听和修改页面
addon.port.on("blocklist", function (blocklist) {
    $("#blockedlist").children().remove();
    $.each(blocklist, function (index, value) {
        $("#blockedlist").append("<div class='siterow' title='"+value+"'>
<div class='sitename'>"+index+"</div><span class='sitedesc'> : 
"+value+"</span></div>");
        showBlockList(blocklist);
    });
});

弹出页面请求 main.js 获取屏蔽站点列表。然后通过该列表进行迭代并附加屏蔽站点细节来在弹出窗口中显示 div


重定向登录页面

在 Chrome 中,可将重定向发送至部分扩展中的登录页面。Firefox 不会这样做,而是直接将它们发送到源页面(您在登录页面嵌入的 YouTube URL:“Hey You! Don't Watch That! Watch This!” ) 。

可以在 main.js 中设置重定向初始条件,如清单 10 所示:

清单 10. 设置初始条件
if (!GB.getWatchThisInstead()) {
   GB.setWatchThisInstead("http://www.youtube.com/watch?v=N-uyWAe0NhQ");
}

图 4 显示了重定向登录页面:

图 4. 重定向登录页面
YouTube 上的重定向登录页面在 Firefox 中的屏幕截图

在 Add-on Builder 中进行测试

当使用 Add-on Builder 时,Firefox 会使得测试扩展变得较为容易。您会得到一个错误控制台、一个测试按钮和一个 Add-on Builder 帮助程序,每次保存时这个帮助程序就会重新加载扩展。图 5 展示了正在运行的 Add-on Builder 帮助程序:

图 5. Add-on Builder 实用程序
Add-on Builder 帮助程序屏幕截图,显示一个错误消息

分发您的扩展

扩展准备就绪后,有几种方法可供选择来进行分发。如果您在配置文件中将 Add-on 标记为公开,就可以为潜在用户发送一个链接,这样他们就可以从链接安装 Add-on。您也可以通过下载的方式分发一个打包的扩展,或者将扩展上传到 addons.mozilla.org。

分发一个打包的扩展

要分发一个打包的扩展,从 Add-on Builder 下载。单击 Download 图标,获取任何人都可以安装的 XPI 文件。您也可以通过您希望的方式(邮件、托管、安装程序以及其他方法)分发。但是您需要负责处理更新和托管。

上传到 addons.mozilla.org

将一个扩展上传到 addons.mozilla.org 的过程与分发您自己的扩展相比涉及的技术较少,但是您需要经过一个审核流程和一些其他障碍。要完成这一过程,在配置文件中单击紧挨着扩展的 upload to AMO 链接,如图 6 所示:

图 6. 上传到 AMO
Add-on 仪表盘屏幕截图,带有 Upload to AMO 链接

遵照这里的上传指令。


寻找答案

您的 Firefox 附件已经完成了,现在应该看看如何给出问题的答案,与 Chrome 中的答案相比:

在浏览器 UI 中拥有一席之地有多难?
如果想要在浏览器底部的 Add-on Bar 中进行持久化,那么与 Chrome 中的难度相差无几。可以通过在 main.js 中创建 Widget 来实现。
持久化浏览器会话间的数据涉及到什么?
使用特定于 Firefox 的 simple-storage API。如果想要让一个 Storage Manager 类在 Chrome 和 Firefox 中运行,那么需要实施一些特性检测
不同的扩展部分彼此如何通信?
使用 port 创建这类通信并建立监听程序和发送程序。
您对用户数据的研究有多深入?
用户没有显式权限,所以您至少仍然可以访问用户访问的每个 URL。这非常重要。

结束语

扩展仅仅只是在 Firefox 附件中进行操作的开始。距离测试 Add-on Builder 可给予您的极限还很远。如果想要深入研究,这里可提供更多信息。在 Add-on Builder、Add-on SDK 和更为复杂的 XUL 扩展之间,您可通过多种方法将触角延伸至 Firefox 。

敬请期待本系列第 3 部分,其中您可以将 Gawkblocker 移植到 Safari 浏览器中。


下载

描述名字大小
文章源代码firefox-sourcecode.zip38KB

参考资料

学习

获得产品和技术

讨论

  • 加入 developerWorks 中文社区:查看开发人员推动的博客、论坛、组和维基,并与其他 developerWorks 用户交流。

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Open source, Web development
ArticleID=939623
ArticleTitle=创建您自己的浏览器扩展,第 2 部分: 将您的触角延伸至 Firefox
publish-date=08012013