Please note, this is a STATIC archive of website developer.mozilla.org from 03 Nov 2016, cach3.com does not collect or store any user information, there is no "phishing" involved.

Embedded WebExtensions

嵌入一个 WebExtension 需要使用 Firefox 51 或更高版本。在 SDK 附加组件中嵌入一个 WebExtension 还需要 jpm 1.2.0

从 Firefox 51 开始,你可以在传统附加组件类型中嵌入一个 WebExtension。

传统附加组件可以是经典的自举扩展或者Add-on SDK 附加组件。嵌入式 WebExtension 的文件打包在传统附加组件中。嵌入式 WebExtension 并不直接与嵌入的附加组件共享范围,但可以使用 runtime API 中定义的消息函数交换消息。

这意味着您可以一次性迁移传统附加组件到 WebExtensions,并且在此期间附加组件的功能完全保留。尤其是它可以让您从旧版附加组件迁移存储数据到 WebExtension,通过撰写一个中间的混合式附加组件,使用旧版 API 读取数据(例如 simple-prefs 或 preferences 服务)并使用 WebExtension API 写入它(例如 storage)。

连同本指南,我们撰写了两个例子展示如何使用嵌入式 WebExtensions 来帮助从传统附加组件迁移。如何从自举式附加组件迁移以及如何从 SDK 附加组件迁移

嵌入 WebExtension

如果传统附加组件是一个带有install.rdf 的自举式扩展,在该 RDF 中加入 "hasEmbeddedWebExtension" 并设为 "true":

<em:hasEmbeddedWebExtension>true</em:hasEmbeddedWebExtension>
如果旧式附加组件是一个 SDK 附加组件,在 package.json 中包含 "hasEmbeddedWebExtension" 并设为 true
 
"hasEmbeddedWebExtension": true
WebExtension 本身放在附加组件中的 "webextension" 顶层目录。例如:
 
my-boostrapped-addon/
    chrome/
    webextension/
        manifest.json
        background.js
        ...
    bootstrap.js
    chrome.manifest
    install.rdf
 
my-sdk-addon/
    index.js
    package.json
    webextension/
        manifest.json
        background.js
        ...

Firefox 不将嵌入式 WebExtension 视为一个独立的附加组件。因此,您不应该为它指定一个附加组件 ID。如果你这样做,那只会被忽略。

但是,在您完成附加组件的迁移并移除旧式嵌入代码后,您必须添加一个 applications 键,设置 ID 为旧式附加组件的 ID。通过此方式,addons.mozilla.org 可以识别 WebExtension 是旧式附加组件的一个更新。

启动 WebExtension

嵌入式 WebExtension 必须由被嵌入的附加组件明确启动。

如果被嵌入的附加组件是一个自举式附加组件,那么传递到自举式扩展的 startup() 函数的 data 将获得一个明确的 webExtension

// bootstrapped add-on

function startup({webExtension}) {

...

如果被嵌入的附加组件是一个 SDK 附加组件,它可以使用 sdk/webextension 模块访问一个 WebExtension 对象:

// SDK add-on

const webExtension = require("sdk/webextension");

无论哪种方式,此对象都有一个 startup() 函数,它返回一个 Promise。该 promise 使用一个 browser 属性解决一个对象:这包括 runtime API,被嵌入的附加组件可以用它来与嵌入式 WebExtension 交换消息:

例如:

// bootstrapped add-on

function startup({webExtension}) {
  webExtension.startup().then(api => {
    const {browser} = api;
    browser.runtime.onMessage.addListener(handleMessage);
  });
}
// SDK add-on

const webExtension = require("sdk/webextension");

webExtension.startup().then(api => {
  const {browser} = api;
  browser.runtime.onMessage.addListener(handleMessage);
});

应注意的是,嵌入的附加组件不能启动通信,它可以使用 onMessage 接收(并可选响应)一次性消息,并可以使用 onConnect 接受连接请求。

如果嵌入式 WebExtension 缺少一个 manifest,或者如果 manifest 无效,该 promise 会被拒绝。这种情况下,您可以在浏览器工具箱的控制台中看到更多细节。

交换消息

一旦嵌入式 WebExtension 处在运行,它可以使用 runtime API 的子集与旧式附加组件交换消息:

无需连接的消息

要发送一条消息,WebExtension 可以使用 runtime.sendMessage()。您可以省略 extensionId 参数,因为浏览器认为嵌入式 WebExtension 是被嵌入附加组件的一部分:

browser.runtime.sendMessage("message-from-webextension").then(reply => {
  if (reply) {
    console.log("response from legacy add-on: " + reply.content);
  }
});

被嵌入的附加组件可以使用 runtime.onMessage 对象接收消息(并可选响应):

// bootstrapped add-on

function startup({webExtension}) {
  // Start the embedded webextension.
  webExtension.startup().then(api => {
    const {browser} = api;
    browser.runtime.onMessage.addListener((msg, sender, sendReply) => {
      if (msg == "message-from-webextension") {
        sendReply({
          content: "reply from legacy add-on"
        });
      }
    });
  });
}

基于连接的消息

要在 WebExtension 与传统附加组件间设置一个长寿命连接,WebExtension 可以使用 runtime.connect()

var port = browser.runtime.connect({name: "connection-to-legacy"});

port.onMessage.addListener(function(message) {
  console.log("Message from legacy add-on: " + message.content);
});

旧式附加组件可以使用 runtime.onConnect 监听连接尝试,双方可以使用得到的 runtime.Port 来交换消息:

function startup({webExtension}) {
  // Start the embedded webextension.
  webExtension.startup().then(api => {
    const {browser} = api;
    browser.runtime.onConnect.addListener((port) => {
      port.postMessage({
        content: "content from legacy add-on"
      });
    });
  });
}

从传统附加组件迁移数据

嵌入式 WebExtensions 的一项主要用途是迁移附加组件的存储数据。

人们从旧式附加组件类型迁移的一个主要问题是存储数据,因为旧式附加组件不能使用 WebExtension 存储 API,WebExtensions 也不能使用旧式存储 API。例如,如果一个 SDK 附加组件使用了 SDK 的 simple-prefs API 来存储首选项,WebExtension 版本不可能访问这项数据。

使用嵌入式 WebExtensions,您可以创建一个嵌入了 WebExtension 的附加组件中间版本来迁移数据。中间版本使用旧式 API 读取存储的数据,然后使用 WebExtension API 写入数据。

  • 在初始版本中,基于 SDK 的附加组件使用 simple-prefs API 读取和写入附加组件首选项。
  • 在中间版本中,SDK 附加组件启动嵌入式 WebExtension。WebExtension 要求 SDK 附加组件用 simple-prefs 检索存储的数据。WebExtension 然后使用 storage API 存储数据。

    在某些情况下,中间版本必须在初始导入后保持数据同步。例如,附加组件的首选项界面仍然使用旧系统,所以如果用户在这里修改了设置,它修改的是旧数据。中间的附加组件必须监听这些更改并将新数据发送到嵌入式 WebExtension。

    有个 "embedded-webextension-sdk" 示例说明了这一点。

  • 在最终版本中,附加组件只是一个 WebExtension,并且只使用存储 API。

我们提供了两个例子说明此模式:"embedded-webextension-bootstrapped" 展示了从一个自举式附加组件迁移,而 "embedded-webextension-sdk" 展示了从一个 SDK 附加组件迁移。

限制

调试

如果您有一个嵌入了 WebExtension 的旧式附加组件,您不能使用新的附加组件调试器来调试它。您必须使用基于浏览器工具箱的旧版调试工具

文档标签和贡献者

 此页面的贡献者: yfdyh000
 最后编辑者: yfdyh000,