4

我正在尝试为 Firefox Mobile 编写一个无需重启的插件,它将内容插入特定的网页。在我尝试禁用然后重新启用加载项之前,这一切似乎都可以正常工作,此时我得到了对页面加载事件的多个响应,我无法找到一种方法来解决它们。

由于 Fennec 使用 Electrolysis 多进程平台,我知道我需要将我的代码拆分为 chrome 和 content 脚本。我的 bootstrap.js 看起来像这样(为清楚起见进行了修剪):

function startup(data, reason) {
  mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIChromeFrameMessageManager);
  mm.loadFrameScript(getResourceURISpec('content.js'), true);
}

function shutdown(data, reason) {
  let mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIChromeFrameMessageManager);
  mm.sendAsyncMessage("GeoMapEnh:Disable", {reason: reason});
}

function install(data, reason) {}
function uninstall(data, reason) {}

基本上,bootstrap.js 只是启动一个内容脚本,并发送一条消息告诉它在关机时进行清理。content.js 设置了一个 eventListener 来监视页面加载,看起来有点像这样:

addMessageListener("GeoMapEnh:Disable", disableScript);
addEventListener("DOMContentLoaded", loadHandler, false );

function loadHandler(e) {
  LOG("Page loaded");
  // Do something cool with the web page.
}

function disableScript(aMessage) {
  if (aMessage.name != "GeoMapEnh:Disable") {
    return;
  }
  LOG("Disabling content script: " + aMessage.json.reason);
  try {
    removeEventListener("DOMContentLoaded", loadHandler, false );
    removeMessageListener("GeoMapEnh:Disable", disableScript);
  } catch(e) {
    LOG("Remove failed: " + e);
  }
}

function LOG(msg) {
  dump(msg + "\n");
  var consoleService = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
  consoleService.logStringMessage(msg);
}

当我第一次运行扩展程序时,一切正常。为每个浏览器选项卡(以及我打开的任何新选项卡)执行一个 content.js 实例,并且我的 eventListener 检测到它应该通过 DOMContentLoaded 事件加载的页面。当我禁用扩展时,一切似乎仍然正常:页面加载停止被检测到。

当我重新启用扩展程序时,一切都出错了。我仍然会为每个打开的选项卡执行一个 content.js 实例,但是现在,如果我打开新选项卡,DOMContentLoaded 会触发多个 eventListeners,我无法区分哪个应该处理该事件。更糟糕的是,一些 eventListeners 是活动的,但不要通过我的 LOG 函数提供调试信息,如果我第二次禁用扩展,它们也不会全部被删除。

我确实想查看所有浏览器选项卡,包括任何新选项卡,但我只希望我的扩展程序在触发它的页面上插入内容,并且每个页面加载一次。我尝试了以下但没有成功:

  • 调用 e.stopPropagation() 以停止将事件传递给其他侦听器。没有效果。
  • 调用 e.preventDefault() 并测试 e.defaultPrevented 以查看事件是否已被处理。它从来没有。
  • 测试 if (this === content.document) 以查看 eventListener 是否已被其自己的页面内容触发。不起作用,因为我得到了多个“真实”响应。
  • 使 eventListener 捕获。没有效果。
  • 使用 load 事件而不是 DOMContentLoaded。

我无法设置共享变量来说明事件已在电解下处理,不同的 eventListener 将在不同的上下文中执行。此外,我无法区分加载同一页面的多个选项卡和多次检测到一个页面加载。我可以通过 IPC 消息传递回 chrome 引导脚本来做到这一点,但是我不知道如何将响应返回到正确的浏览器选项卡。

有任何想法吗?这是一个 Firefox 错误,还是我在我的代码中做了一些愚蠢的事情?我正在使用 Fennec Desktop v4 进行开发,并将针对 Fennec Android v6 进行生产。

4

0 回答 0