让我们编写一个 Web 扩展

您可能听说过 Mozilla 的 WebExtensions,这是我们为编写多进程兼容的附加组件实现的新浏览器扩展 API。也许您一直在好奇它是什么,以及如何使用它。好吧,我来帮忙!我认为 MDN 的 WebExtensions 文档 是一个非常好的起点

WebExtensions 是一种编写 Firefox 扩展的新方法。

该技术是为了跨浏览器兼容性而开发的:在很大程度上,该 API 与 扩展 API 兼容,后者受 Google Chrome 和 Opera 支持。为这些浏览器编写的扩展程序在大多数情况下只需稍作修改即可在 Firefox 中运行。该 API 还完全兼容 多进程 Firefox

我唯一想补充的是,虽然 Mozilla 正在实现 Chrome 和 Opera 支持的大部分 API,但我们并不局限于仅使用该 API。在有意义的地方,我们将添加新功能并与其他浏览器制造商讨论也实施这些功能。最后,由于 WebExtension API 仍在开发中,因此最好在此教程中使用 Firefox Nightly,以便获得最新、符合标准的行为。但请记住,这仍然是实验性技术——可能会出现故障!

开始

好的,让我们从一个相当简单的附加组件开始。我们将添加一个按钮,当您单击它时,它将在新标签页中打开 我最喜欢的网站之一

我们需要的第一文件是 manifest.json,以告诉 Firefox 有关我们的附加组件的信息。

{
  "manifest_version": 2,
  "name": "Cat Gifs!",
  "version": "1.0",
  "applications": {
    "gecko": {
      "id": "catgifs@mozilla.org"
    }
  },

  "browser_action": {
    "default_title": "Cat Gifs!"
  }
}

太好了!我们完成了!希望您的代码看起来有点像 这样。当然,我们还不知道它是否有效,所以让我们在 Firefox 中安装它(我们正在使用 Firefox Nightly 获取最新的实现)。您可以尝试将 manifest.json 或整个目录拖放到 Firefox 上,但这真的不会达到您想要的效果。

The directory listing

安装

要使 Firefox 将您的扩展程序识别为附加组件,您需要提供一个以 .xpi 结尾的 zip 文件,所以让我们首先安装 7-Zip,然后键入 7z a catgifs.xpi manifest.json。(如果您使用的是 Mac 或 Linux,则 zip 命令应该内置,因此只需键入 zip catgifs.xpi manifest.json。)然后,您可以将 catgifs.xpi 拖放到 Firefox 上,它将显示错误,因为我们的扩展程序未签名。

The first error

我们可以通过转到 about:config,在搜索框中键入 xpinstall.signatures.required,双击该条目将其设置为 false,然后关闭该选项卡来解决此问题。之后,当我们将 catgifs.xpi 放到 Firefox 上时,我们将获得安装新附加组件的选项!

需要注意的是,从 Firefox 44 开始(今年晚些时候),附加组件将 需要签名才能安装在 Firefox Beta 或浏览器发行版上,因此即使您设置了下面显示的偏好设置,您也很快仍需要运行 Firefox Nightly 或 Developer Edition 才能遵循本教程。

Success!!!

当然,我们的附加组件目前还没有做太多事情。

I click and click, but nothing happens.

所以让我们修复它!

添加功能

首先,我们将以下几行添加到 manifest.json 中,位于包含 browser_action 的行的上方

  "background": {
    "scripts": ["background.js"],
    "persistent": false
  },

现在,当然,它指向一个尚不存在的 background.js 文件,所以我们也应该创建它。让我们将以下 javascript 粘贴到其中

'use strict';

/*global chrome:false */

chrome.browserAction.setBadgeText({text: '(ツ)'});
chrome.browserAction.setBadgeBackgroundColor({color: '#eae'});

chrome.browserAction.onClicked.addListener(function(aTab) {
  chrome.tabs.create({'url': 'http://chilloutandwatchsomecatgifs.com/', 'active': true});
});

您应该会看到类似于 这样 的内容。通过键入 7z a catgifs.xpi manifest.json background.js(或 zip catgifs.xpi manifest.json background.js)重新创建附加组件,并将 catgifs.xpi 再次拖放到 Firefox 上,现在,当我们单击该按钮时,我们应该会得到一个新标签页!😄

Cat Gifs!

自动化构建

我不知道您怎么样,但我最终键入了 7z a catgifs.xpi manifest.json 令人沮丧的次数,并想知道为什么我的 background.js 文件没有运行。因为我知道这篇文章的最终去向,我知道我们将要添加更多文件,所以我认为现在是时候添加构建脚本了。我听说如今首选的构建工具是 gulp,所以我会在这里等您 去安装它,并在您完成时回来。(我需要安装 Node,然后两次安装 gulp。我不确定为什么。)

因此,现在我们已经安装了 gulp,我们应该创建一个名为 gulpfile.js 的文件来告诉它如何构建我们的附加组件。

'use strict';

var gulp = require('gulp');

var files = ['manifest.json', 'background.js'];
var xpiName = 'catgifs.xpi';

gulp.task('default', function () {
  console.log(files, xpiName)
});

一旦您使该文件看起来 像这样,您可以键入 gulp,并看到如下输出

Just some command line stuff, nbd.

现在,您可能会注意到我们实际上并没有构建附加组件。为此,我们需要安装另一个软件包来压缩文件。因此,键入 npm install gulp-zip,然后更改 gulpfile.js 以包含以下内容

'use strict';

var gulp = require('gulp');
var zip = require('gulp-zip');

var files = ['manifest.json', 'background.js'];
var xpiName = 'catgifs.xpi';

gulp.task('default', function () {
  gulp.src(files)
    .pipe(zip(xpiName))
    .pipe(gulp.dest('.'));
});

一旦您的 gulpfile.js 看起来 像这样,当我们运行它时,它将创建 catgifs.xpi(正如我们可以通过查看时间戳或删除它并查看它是否重新创建来判断)。

修复错误

现在,如果您像我一样,您会多次单击该按钮以对其进行测试并确保它正常工作,并且您可能最终会得到很多标签页。虽然这将确保您保持格外冷静,但如果我们在单击按钮时创建它或切换到它(如果它存在),则可能只保留一个标签页会更好。所以让我们继续添加它。

Lots and lots of cats.

我们要做的第一件事是查看标签页是否存在,所以让我们编辑 background.js 中的 browserAction.onClicked 侦听器以包含以下内容

chrome.browserAction.onClicked.addListener(function(aTab) {
  chrome.tabs.query({'url': 'http://chilloutandwatchsomecatgifs.com/'}, (tabs) => {
    if (tabs.length === 0) {
      // There is no catgif tab!
      chrome.tabs.create({'url': 'http://chilloutandwatchsomecatgifs.com/', 'active': true});
    } else {
      // Do something here…
    }
  });
});

嗯,这很奇怪,无论已经有多少个猫 GIF 标签页,它总是会创建一个新标签页……事实证明,我们的附加组件还没有权限查看现有标签页的 URL,这就是它找不到它们的原因,所以让我们继续通过在 browser_action 上方插入以下代码来添加它

  "permissions": [
    "tabs"
  ],

一旦您的代码看起来 类似于这样,重新运行 gulp 以重新构建附加组件,并拖放以安装它,然后当我们对其进行测试时,瞧!只有一个猫 GIF 标签页!当然,如果我们在另一个标签页上,它不会执行任何操作,所以让我们修复它。我们可以更改 else 块以包含以下内容

      // Do something here…
      chrome.tabs.query({'url': 'http://chilloutandwatchsomecatgifs.com/', 'active': true}, (active) => {
        if (active.length === 0) {
          chrome.tabs.update(tabs[0].id, {'active': true});
        }
      });

确保它看起来 像这样,重新构建,重新安装,然后瞧,它起作用了!

使其看起来漂亮

好吧,它可以工作了,但它并不漂亮。让我们做几件事来稍微修复它。

首先,我们可以添加一个自定义图标,以便我们的附加组件看起来不像所有其他没有设置其图标的附加组件……为此,我们在 manifest_version 行之后将以下内容添加到 manifest.json

  "icons": {
    "48": "icon.png",
    "128": "icon128.png"
  },

当然,我们需要下载一张漂亮的图片作为我们的图标,所以让我们将 这张图片 的副本保存为 icon.png,并将 这张图片 保存为 icon128.png

我们还应该为按钮提供一个更漂亮的图标,所以回到 manifest.json,让我们在 browser_action 块中的 default_title 之前添加以下几行

    "default_icon": {
      "19": "button.png",
      "38": "button38.png"
    },

并将 此图像 保存为 button.png,并将 此图像 保存为 button38.png

最后,我们需要告诉我们的构建脚本有关新文件的信息,因此将 gulpfile.jsfiles 行更改为

var files = ['manifest.json', 'background.js', '*.png'];

重新运行构建,并重新安装附加组件,然后 我们完成了!😀

New, prettier, icons.

还有一件事……

好吧,我们还可以尝试做另一件事。我的意思是,我们有一个在 Firefox 中完美运行的附加组件,但新 WebExtension API 的优点之一是您可以在 Firefox 和 Chrome 上运行相同的附加组件(或具有最少更改的附加组件)。所以让我们看看在两个浏览器上运行它需要做些什么!

我们将首先启动 Chrome,并尝试加载附加组件,看看它会给我们什么错误。要加载我们的扩展程序,我们需要转到 chrome://extensions/,并选中“开发者模式”复选框,如下所示

Now we’re hackers!

然后,我们可以单击“加载解压的扩展程序...”按钮,并选择我们的目录以加载我们的附加组件!哦,看来我们遇到了错误。

Close, but not quite.

由于 applications 密钥是 Firefox 所必需的,所以我认为我们可以安全地忽略此错误。无论如何,该按钮出现了!当我们点击它时……

Cats!

所以,我想我们完成了!(我过去曾在此处有一个关于如何加载 babel.js 的部分,因为我使用的 Chrome 版本不支持 ES6 的 箭头函数,但显然他们已经升级了他们的 JavaScript 引擎,现在一切正常。😉)

最后,如果您有任何疑问或在遵循本教程时遇到任何问题,请随时在此处发表评论,或通过 电子邮件 或在 twitter 上与我联系!如果您在开发 WebExtensions 时遇到问题或有建设性反馈,团队将在 Discourse 论坛 上倾听。

关于 Blake Winton

Blake Winton 的更多文章……


24 条评论

  1. 太棒了

    跨浏览器扩展太棒了!

    2015 年 9 月 21 日 下午 5:25

  2. J. McNair

    感谢您提供清晰有趣的教程。但是,我认为“符合标准”有点误导。另一方面,“与 Chrome、Opera 和可能还有 MS Edge 的良好定义的子集兼容”是一个很长的句子。第三方面,如果多个浏览器制造商确实在协作制定一个用 JS 编写的扩展程序的官方标准,那将非常棒。

    尽管如此,还是要感谢您!

    2015 年 9 月 21 日 下午 5:37

  3. Gabe

    您能否也展示如何调试扩展程序?在 Chrome 中,您可以通过 background.js 使用开发者工具。Firefox 中的对应项是什么?

    2015 年 9 月 21 日 下午 8:07

    1. Blake Winton

      这是一个很好的问题!但我认为我可能会把它留到后续文章中……(我会说,如果您仔细查看第 8 张图片,您会看到一个“调试”按钮,它应该可以帮助您找到答案。)

      2015 年 9 月 21 日 下午 8:10

  4. Shiv

    感谢您提供非常有趣的教程。您能否解释一下您在 else 块中添加的代码?我下载了源代码,但仍然无法理解。

    2015 年 9 月 21 日 下午 10:22

    1. Blake Winton

      当然!

      “chrome.tabs.query({‘url’: ‘http://chilloutandwatchsomecatgifs.com/’, ‘active’: true},” 部分查找具有猫 GIF URL 的活动标签页。它将使用这些标签页的可能为空的数组调用我们传入的函数。

      该函数检查是否存在具有该 URL 的活动标签页(“if (active.length === 0) {“),如果没有,则将具有该 URL 的第一个标签页设置为活动状态(“chrome.tabs.update(tabs[0].id, {‘active’: true});”)。

      这是否有助于使代码更容易理解一些?

      2015 年 9 月 22 日 上午 6:31

  5. kketch

    是否计划在不久的将来包含对 chromium 的 devtools 扩展 API 的支持?

    2015 年 9 月 22 日 上午 9:09

    1. Blake Winton

      肯定有计划支持它们(https://wiki.mozilla.org/WebExtensions#List_of_APIs_we_will_likely_support_in_the_future),但我还不知道时间表。如果您发现自己等不及了,我相信团队会非常感谢您的帮助。;)

      2015 年 9 月 22 日 上午 9:13

  6. lv7777

    我翻译了 webextension 的 MdN 文章。
    我期待着 WebExtension。

    2015 年 9 月 22 日 上午 9:25

  7. Daniel Lo Nigro

    每次进行任何更改后都需要将扩展程序打包成 .xpi 文件,这很烦人。有没有办法将解压的扩展程序加载到 Firefox 中?

    2015 年 9 月 23 日 下午 11:49

    1. Blake Winton

      是的!我们一直在讨论这个问题,我认为我们甚至正在处理它,但我似乎找不到错误……您觉得当文件夹中的内容发生变化时自动重新加载未打包的扩展程序怎么样?这会太烦人,还是一个惊人的省时方法?

      2015年9月24日 04:51

      1. Blake Winton

        找到了!看起来它甚至有一个补丁……

        2015年9月24日 06:44

  8. Scott O’Malley

    是否可以在新的 Web 扩展程序中使用旧的 Firefox API 调用?例如,Firefox 尚未支持 Chrome/Opera 中的 cookie 权限,那么是否可以在 background.js 中使用此处列出的函数 - https://mdn.org.cn/en-US/Add-ons/Code_snippets/Cookies

    2015年9月27日 02:54

    1. Blake Winton

      不可以,因为那样做会使新的 API 不比旧的 API 好。

      我们正在努力实施新的 API,所以最好的办法是等待。实际上,_最好的_办法是帮助实施您正在等待的 API ;),但第二好的办法是等待。第三好的办法是编写一个 Jetpack 扩展程序,它使用您需要的所有旧 API,直到我们将其实施到新的 API 中。;D

      2015年9月27日 09:50

      1. Scott O’Malley

        不用担心,我目前正在使用 Jetpack 扩展程序,但我一直遇到一些问题,导致事情变得很困难。具体来说,由于某种原因,我的应用程序拒绝在除了我的开发笔记本电脑之外的任何其他机器上工作……

        您能告诉我哪里可以帮助实施缺少的 API 吗? :)

        2015年9月28日 04:32

        1. Blake Winton

          此链接 将列出我们正在跟踪的所有错误,而 此链接 应为大多数需要查看的代码列表。如果您能加入 irc.mozilla.org,#webextensions 频道应该能够帮助您解决遇到的任何与 WebExtension 相关的问题。 :)

          2015年9月28日 07:26

  9. A.J.

    也许我疯了,但我找不到 xpinstall.signatures.required。按照了所有其他步骤。

    2015年9月29日 10:34

    1. Blake Winton

      您使用的是 Firefox Nightly 吗?如果您在 about:config 顶部的搜索框中输入“signatures”会发生什么?(此外,如果您想给我发送屏幕截图的电子邮件,我可能会写一个更长、更有帮助的回复……:)

      2015年9月29日 10:51

  10. Sylos

    您能否评论一下 Firefox 的 WebExtensions 实现的当前状态?现在尝试学习 Firefox 中的 API 是否可行,或者它仍然存在太多限制?
    如果可能,我想避免安装 Chrome 或其他基于 Chromium 的浏览器……

    2015年10月1日 09:23

    1. Blake Winton

      它正在逐步完善。有一个完整(并且持续更新)的列表,其中列出了不工作的功能 此处。我正在将 我的一个附加组件 移植到 WebExtensions,并且 我正在添加的功能(并在 Nightly 中测试)进展得相当顺利,我认为。

      2015年10月1日 10:11

  11. Brett Zamir

    听到你说“我们不局限于仅使用该 API”这真是令人非常放心。

    不过,为了和谐起见,我真的希望您考虑完全实施 Node.js API,因为它的大多数 API 不是特定于服务器的,而是特定于像服务器一样具有特权的桌面访问权限——即使实施特定于服务器的功能也可能有用——能够直接在 Web 应用程序中提供您当前的浏览器选项卡列表、浏览器中播放的音频或其他任何内容,这可能是一些有趣的用例。

    2015年10月4日 13:58

    1. Blake Winton

      您应该在 Discourse 论坛 上提出这个建议。我怀疑并非所有 Node API 在附加组件中都有意义,并且浏览器已经有了不同的方法来处理诸如子进程之类的事情,因此实施完整的 API 似乎不太可能,但如果您陈述您的理由,谁知道呢?:D

      感谢您的建议!

      2015年10月4日 17:16

  12. Paul Dunderdale

    当我将 catgifs.xpi 拖到 Firefox (41.0.1) 上时,我收到“此附加组件无法安装,因为它似乎已损坏。”的消息。

    甚至尝试了 GitHub 上的 catgif-extension-step-1

    2015年10月6日 00:42

    1. Blake Winton

      是的。您需要使用 Firefox Nightly 或 Developer Edition(版本 43 或更高版本),因为加载 WebExtensions 的代码尚未完全发布到 Firefox 的正式版本中。

      2015年10月6日 07:06

本文的评论已关闭。