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