内容


创建您自己的浏览器扩展,第 2 部分

将您的触角延伸至 Firefox

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

Comments

系列内容:

此内容是该系列 # 部分中的第 # 部分: 创建您自己的浏览器扩展,第 2 部分

敬请期待该系列的后续内容。

此内容是该系列的一部分:创建您自己的浏览器扩展,第 2 部分

敬请期待该系列的后续内容。

Gawkblocker 扩展

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

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

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

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

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

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

开始之前

对于本文,您需要下载和安装 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 扩展剖析

使用 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 弹出/选项页面屏幕截图
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 屏幕截图
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 弹出页面中的选项
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 中的屏幕截图
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 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 链接
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 浏览器中。


下载资源


相关主题


评论

添加或订阅评论,请先登录注册

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