Mobile 如何在Fennec扩展中驯服多个事件侦听器?

Mobile 如何在Fennec扩展中驯服多个事件侦听器?,mobile,firefox-addon,fennec,Mobile,Firefox Addon,Fennec,我正在尝试为Firefox Mobile编写一个无重启插件,它将把内容插入特定的网页。在我尝试禁用然后重新启用加载项之前,一切似乎都正常。在这一点上,我得到了对页面加载事件的多个响应,我无法找到一种方法来对它们进行排序 由于Fennec使用电解多进程平台,我知道我需要将代码拆分为chrome和内容脚本。我的bootstrap.js看起来像这样(为了清晰起见进行了修剪): 基本上,bootstrap.js只是启动一个内容脚本,并发送一条消息,告诉它在关机时进行清理。content.js设置了一个e

我正在尝试为Firefox Mobile编写一个无重启插件,它将把内容插入特定的网页。在我尝试禁用然后重新启用加载项之前,一切似乎都正常。在这一点上,我得到了对页面加载事件的多个响应,我无法找到一种方法来对它们进行排序

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

基本上,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,我无法区分哪个应该处理事件。更糟糕的是,一些EventListener处于活动状态,但不通过我的日志函数提供调试信息,并且如果我再次禁用扩展,它们不会全部被删除

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

  • 调用e.stopPropagation()以停止将事件传递给其他侦听器。没有效果
  • 调用e.preventDefault()并测试e.defaultPrevented以查看事件是否已被处理。从来没有
  • 测试if(this===content.document)以查看eventListener是否由其自己的页面内容触发。不起作用,因为我得到了多个“真实”的回答
  • 使事件侦听器捕获。没有效果
  • 使用load事件而不是DOMContentLoaded
我不能设置一个共享变量来表示事件已经按照电解处理,不同的EventListener将在不同的上下文中执行。此外,我无法区分加载同一页面的多个选项卡和多次检测到的一个页面加载。我可以通过IPC消息传递回chrome引导脚本来实现这一点,但我不知道如何将响应返回到正确的浏览器选项卡


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

经过更多的修改,看起来这可能与
messageManager.loadFrameScript()
有关。我想我必须等待修复,忍受多个脚本堆积,并在即将插入内容时添加额外的检查。这难道不是你向“旧”内容脚本发送
GeoMapEnh:Disable
的原因吗?以确保即使你无法卸载它,它也会死掉?我也是这么想的!发送
GeoMapEnh:Disable
消息确实会终止内容脚本,但是只要打开另一个选项卡,
loadFrameScript()
就会启动新的内容脚本,即使扩展应该被禁用。啊,对了-现有的内容脚本会死掉,但您无法阻止创建新的内容脚本。看起来Fennec 9(将于12月20日发布)中的错误将得到修复,因此您可以在关机时调用
mm.removeDelayedFrameScript(getResourceURISpec('content.js'))
(发送
GeoMapEnh:Disable
仍有必要)。我的临时解决方法是让内容脚本在启动其消息侦听器之前发送一条同步消息,询问扩展是否已启用。这主要解决了问题,但意味着当扩展被禁用时,我必须将匹配的
MessageListener
留在
bootscript.js
中。
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);
}