每个浏览器都有其自己的支持者、批评者、优势和劣势。它们的共同点是人们将越来越多的时间花费于其中。本系列文章将介绍如何为 Chrome、Firefox 和 Safari 构建相同的基础扩展。您将了解到扩展每个浏览器是什么样子,执行这些常见任务是困难还是简单,以及如何发布您的扩展。在本文中,您将构建一个 Firefox 扩展。
Gawkblocker 扩展
回忆一下,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. 弹出/选项页面
您也可以使用 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
构建 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 弹出页面中的选项
当您在 清单 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. 重定向登录页面
在 Add-on Builder 中进行测试
当使用 Add-on Builder 时,Firefox 会使得测试扩展变得较为容易。您会得到一个错误控制台、一个测试按钮和一个 Add-on Builder 帮助程序,每次保存时这个帮助程序就会重新加载扩展。图 5 展示了正在运行的 Add-on Builder 帮助程序:
图 5. 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
遵照这里的上传指令。
寻找答案
您的 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 浏览器中。
注:本文转自伯乐在线。
- 本文固定链接: https://zxbcw.cn/post/1731/
- 转载请注明:必须在正文中标注并保留原文链接
- QQ群: PHP高手阵营官方总群(344148542)
- QQ群: Yii2.0开发(304864863)