在 Firefox Add-on SDK 扩展中的 'onInstalled' 上执行脚本
Execute script on 'onInstalled' in Firefox Add-on SDK extension
我是Mozilla扩展开发的新手,即使我才知道扩展和附加开发是不同的
我对我在 MDN(Mozilla 开发者网络)上看到的内容非常执着。
我想在我的附加组件安装后立即执行脚本 'content_script.js',这样用户就不需要重新启动浏览器。
我只是拖放我的 xpi 文件并安装它,然后我单击网页上的一个按钮,该按钮向我的附加组件发送消息,但我的附加组件只有在我重新加载网页后才会收听此消息。
//main.js
var chrome = require("chrome");
chrome.runtime.onInstalled.addListener(function(){
executeScript (contentscript.js) in tabs});
//also I tried
browser.runtime.onInstalled.addListener
当我知道它是用于 Mozilla 扩展而不是附加组件时,我正在尝试这个,因为它给我错误 browser undefined 和 chrome.runtime
is undefined.
然后,我在AddonManager.addAddonListener()
里面找到了onInstalled()
。
但是,我仍然很困惑如何在我的附加组件中使用它。
无论我尝试哪种方式,它都会给我错误。
//main.js
const { AddonManager } = require("resource://gre/modules/AddonManager.jsm");
Cu.import("resource://gre/modules/AddonManager.jsm");
AddonManager.addAddonListener.onInstalled.addListener(function(){
console.log('installed');
tabs.executeScript(tabId, "../data/content_script.js", function(result) { console.log('result ='+result); });
});
下面的代码删除了错误但也不起作用:
const { AddonManager } = require("resource://gre/modules/AddonManager.jsm");
Cu.import("resource://gre/modules/AddonManager.jsm");
var listener = {
onInstalled: function(addon) {
console.log('installed');
console.log(addon);
tabs.executeScript(tabId, "../data/content_script.js", function(result) { console.log('result ='+result); });
}
};
AddonManager.addAddonListener(listener);
我的package.json看起来像这样
{
"title": "test",
"name": "test",
"version": "1.0.0",
"description": "test addon corp",
"main": "lib/main.js",
"author": "test",
"engines": {
"firefox": ">=38.0a1",
"fennec": ">=38.0a1"
},
"license": "MIT",
"keywords": [
"jetpack"
]
}
main
包括 main.js,但它仍然没有执行,因为当我重新加载页面时,我的附加组件才工作。
我认为我做的完全错了,我是在 Chrome 扩展中做的,这很容易,但我对 Mozilla 附加组件一无所知。我什至无法达到 "installed"。执行content_script还差得远
您似乎遇到了一些问题:
- 您仍在混合使用 WebExtensions 和 Add-on SDK
- Add-on SDK没有
tabs.executeScript()
you are looking for tab.attach()
. For the active tab it would be tabs.activeTab.attach()
这样的方法。
- 安装当前正在安装的附加组件的
AddonManager
onInstalled
事件发生 先于 附加组件的任何代码 运行。因此,您不会收到正在侦听的附加组件的此事件。
AddonManager
主要是为了让您的加载项能够监控涉及 其他 加载项的 activity。它在监控插件 activity 中的作用有限。
- 您可以获得
AddonManager
onDisabled
event if the user disables the add-on prior to removing it. If the user directly removes it, you just get an onUninstalling
活动。
- 您可能 运行 正在解决以下问题:内容脚本中的
console.log()
未显示在浏览器控制台中,当时加载的加载项附加了内容脚本作为使用 jpm run
进行测试的主要附加组件。输出在执行 jpm run
的控制台 window 中可用。虽然输出到控制台 window 是设计使然,但我认为输出不进入浏览器控制台(除了控制台 window 之外)是错误或功能失调。
- 将内容脚本加载到
about:*
页面会导致某些行为不同于将其加载到普通网页。此行为可以包括制作 console.log()
output only show up as if it was output using dump()
(即它不会显示在浏览器控制台中,但会显示在执行 Firefox/jpm run
的控制台中)。如果您正在尝试这样做,您将需要试验您能够做什么。
- 您已经声明,"I think my main.js is not running right after installation." 这种信念可能是由于没有在正确的地方寻找
console.log()
输出 Browser Console。因此,我让下面的附加组件自动打开浏览器控制台。
- 安装插件时在package.json key
"main"
运行中指定的JavaScript文件。在 Firefox 启动时也是 运行。
- 您可以有一个
exports.main
函数,它会在 "main"
JavaScript 文件中的代码被评估和执行后自动调用。此功能可用于查找您的附加组件被执行的原因。可能的原因是 install
、enable
、startup
、upgrade
和 downgrade
。下面的附加组件演示了何时执行此代码并将 reason
传递给它。
为了演示各种东西,我编写了一个 Firefox 附加 SDK 扩展,它加载了几个内容脚本并侦听 AddonManager
事件。我制作了这个插件的两个版本,它们仅在名称和 ID 上有所不同,这些名称和 ID 在各自的 package.json 文件中分配给每个版本。这两个附加组件是 installinfo@ex1
和 installinfo@ex2
。
第一个附加组件 installinfo@ex1
由 运行ning jpm run
在其目录中加载。第二个插件 installinfo@ex2
是通过拖放 jpm xpi
为它创建的 .xpi[=116=] 来安装的。使用 Firefox UI,我立即导航到 about:addons
(Ctrl-Shift-A, Cmd-Shift-A on OSX) 然后继续首先禁用installinfo@ex2
;然后 "remove" installinfo@ex2
;然后刷新 about:addons
页面以使其无法 "undo" 删除。然后我退出 Firefox 主浏览器 window.
附加组件向控制台输出大量信息,因此您可以查看事件发生的顺序以及哪个附加组件能够接收哪些 AddonManager
事件。控制台输出是[括号内是我在用户界面上所做的,以及一些评论]:
[User action: Start Firefox in installinfo@ex1 directory]
installinfo@ex1: In index.js
installinfo@ex1: In installAddonListener: Adding add-on listener
installinfo@ex1: Attaching content script A
installinfo@ex1: In exports.main: This add-on is being loaded for reason= install Object { loadReason: "install", staticArgs: undefined }
installinfo@ex1: Attaching content script B
installinfo@ex1: In exports.main: was passed callbacks= Object { print: print(), quit: function () }
[Note: no console.log output from within conentScriptA loading]
installinfo@ex1: received message from contentScriptA: Is Loaded
[Note: no console.log output from within conentScriptB loading]
installinfo@ex1: received message from contentScriptB: Is Loaded
[User action: Drag and drop .xpi for installinfo@ex2 onto Firefox]
installinfo@ex1: AddonManager Event: Installing addon ID: installinfo@ex2 ::needsRestart= false ::addon object: Object { }
installinfo@ex1: AddonManager Event: Installed addon ID: installinfo@ex2 ::addon object: Object { }
installinfo@ex2: In index.js
installinfo@ex2: In installAddonListener: Adding add-on listener
installinfo@ex2: Attaching content script A
installinfo@ex2: In exports.main: This add-on is being loaded for reason= install Object { loadReason: "install", staticArgs: undefined }
installinfo@ex2: Attaching content script B
installinfo@ex2: In exports.main: was passed callbacks= Object { print: print(_), quit: function () }
installinfo@ex2: In contentScriptA: Loaded
installinfo@ex2: received message from contentScriptA: Is Loaded
installinfo@ex2: In contentScriptB: Loaded
installinfo@ex2: received message from contentScriptB: Is Loaded
[User action: Navigate to about:addons]
[User action: Disable installinfo@ex2]
installinfo@ex1: AddonManager Event: Disabling addon ID: installinfo@ex2 ::needsRestart= false ::addon object: Object { }
installinfo@ex2: AddonManager Event: Disabling addon ID: installinfo@ex2 ::needsRestart= false ::addon object: Object { }
installinfo@ex2: In exports.onUnload: This add-on is being unloaded for reason= disable
installinfo@ex2: In removeAddonListener: Removing add-on listener
installinfo@ex1: AddonManager Event: Disabled addon ID: installinfo@ex2 ::addon object: Object { }
installinfo@ex2: AddonManager Event: Disabled addon ID: installinfo@ex2 ::addon object: Object { }
installinfo@ex1: AddonManager Event: Uninstalling addon ID: installinfo@ex2 ::needsRestart= true ::addon object: Object { }
[Get a warning in Browser Console because installinfo@ex2 did not remove its AddonManager listeners, and AddonManager is still trying to call them.]
1472563865661 addons.manager WARN AddonListener threw exception when calling onUninstalling: TypeError: can't access dead object (resource://gre/modules/AddonManager.jsm:1756:1) JS Stack trace: AddonManagerInternal.callAddonListeners@AddonManager.jsm:1756:1 < this.AddonManagerPrivate.callAddonListeners@AddonManager.jsm:3075:5 < this.XPIProvider.uninstallAddon@XPIProvider.jsm:5041:7 < AddonWrapper.prototype.uninstall@XPIProvider.jsm:7484:5 < uninstall@extensions.xml:1548:13 < oncommand@about:addons:1:1
[User action: Refresh about:addons page to remove "undo" posibility for installinfo@ex2]
installinfo@ex1: Uninstalled addon ID: installinfo@ex2 ::addon object: Object { }
[Get a warning in Browser Console because installinfo@ex2 did not remove its AddonManager listeners, and AddonManager is still trying to call them.]
1472563873408 addons.manager WARN AddonListener threw exception when calling onUninstalled: TypeError: can't access dead object (resource://gre/modules/AddonManager.jsm:1756:1) JS Stack trace: AddonManagerInternal.callAddonListeners@AddonManager.jsm:1756:1 < this.AddonManagerPrivate.callAddonListeners@AddonManager.jsm:3075:5 < this.XPIProvider.uninstallAddon@XPIProvider.jsm:5096:7 < AddonWrapper.prototype.uninstall@XPIProvider.jsm:7484:5 < doPendingUninstalls@extensions.js:1740:5 < gListView.hide@extensions.js:2733:5 < gViewController.shutdown@extensions.js:651:7 < shutdown@extensions.js:184:3 < EventListener.handleEvent*@extensions.js:84:1
[User action: Close main Firefox browser window]
[User action: Close Firefox Browser Console window]
(via dump):installinfo@ex1: In exports.onUnload: This add-on is being unloaded for reason= shutdown
我建议您试验下面的附加组件,以了解 AddonManager 事件的可能性以及代码何时在您的附加组件中执行。
附加文件:
index.js:
/* Firefox Add-on SDK test when code is executed upon install*/
//For testing:
var doNotRemoveAddonManagerListenersUponUninstall = true
var self = require("sdk/self");
var tabs = require("sdk/tabs");
var myId = self.id;
let myIdText = myId;
if(myId.indexOf('2') > -1){
//Indent console logs for version 2
myIdText = '\t\t' + myIdText ;
}
var utils = require('sdk/window/utils');
activeWin = utils.getMostRecentBrowserWindow();
//This will execute every time the add-on is loaded (e.g. install, startup, enable, etc).
myLog('In index.js');
//Open the Browser Console
activeWin.document.getElementById('menu_browserConsole').doCommand();
function myLog(){
// Using activeWin.console.log() is needed to have output to the
// Browser Console when installed as an .xpi file. In that case,
// console is mapped to dump(), which does not output to the console.
// This is done, I assume, to not polute the console from SDK add-ons
// that are logging information when they should not. Using jpm run,
// console.log outputs to the Browser Console.
let activeWin = require('sdk/window/utils').getMostRecentBrowserWindow();
// If Firefox is exiting (and some other conditions), there is
// no active window. At such times, we must use the version
// of console.log() aliases to dump().
let useConsole = console;
if(activeWin ){
//useConsole = activeWin.console;
}
useConsole.log(myIdText +':',...arguments);
}
function attachScript(script){
let tabWorker = tabs.activeTab.attach({
contentScriptFile: script,
contentScriptOptions: {
//extra \t because content script console.log (from .xpi) doesn't prefix with
// add-on name.
idText: '\t\t\t' + myIdText
}
});
tabWorker.port.on('consoleLog',logMessage);
return tabWorker;
}
function logMessage(message){
myLog(message);
}
exports.main = function (options,callbacks) {
myLog('In exports.main: This add-on is being loaded for reason=', options.loadReason
, options);
myLog('Attaching content script B');
attachScript('./contentScriptB.js');
if(typeof callbacks !== 'undefined'){
myLog('In exports.main: was passed callbacks=', callbacks);
}
switch (options.loadReason) {
case 'install':
//Do actions upon install
break;
case 'enable':
//Do actions upon enable
break;
case 'startup':
//Do actions upon startup
break;
case 'upgrade':
//Do actions upon upgrade
break;
case 'downgrade':
//Do actions upon downgrade
break;
default:
throw 'Unknown load reason:' + options.loadReason;
break; //Not needed, throw will exit
}
};
exports.onUnload = function (reason) {
myLog('In exports.onUnload: This add-on is being unloaded for reason=',reason);
//Your add-on listeners are NOT automatically removed when
// your add-on is disabled/uninstalled.
//You MUST remove them in exports.onUnload if the reason is
// not 'shutdown'. If you don't, errors will be shown in the
// console for all events for which you registered a listener.
if(reason !== 'shutdown') {
uninstallAddonListener();
}
};
const { AddonManager } = require("resource://gre/modules/AddonManager.jsm");
let addonListener = {
onEnabling: function(addon, needsRestart){
myLog('AddonManager Event: Enabliling addon ID: ' + addon.id
+ ' ::needsRestart= ' + needsRestart + ' ::addon object:', addon);
},
onEnabled: function(addon){
myLog('AddonManager Event: Enabled addon ID: ' + addon.id
+ ' ::addon object:', addon);
},
onDisabling: function(addon, needsRestart){
myLog('AddonManager Event: Disabling addon ID: ' + addon.id
+ ' ::needsRestart= ' + needsRestart + ' ::addon object:', addon);
},
onDisabled: function(addon){
myLog('AddonManager Event: Disabled addon ID: ' + addon.id
+ ' ::addon object:', addon);
},
onInstalling: function(addon, needsRestart){
myLog('AddonManager Event: Installing addon ID: ' + addon.id
+ ' ::needsRestart= ' + needsRestart + ' ::addon object:', addon);
},
onInstalled: function(addon){
myLog('AddonManager Event: Installed addon ID: ' + addon.id
+ ' ::addon object:', addon);
},
onUninstalling: function(addon, needsRestart){
myLog('AddonManager Event: Uninstalling addon ID: ' + addon.id
+ ' ::needsRestart= ' + needsRestart + ' ::addon object:', addon);
},
onUninstalled: function(addon){
myLog('AddonManager Event: Uninstalled addon ID: ' + addon.id
+ ' ::addon object:', addon);
},
onOperationCancelled: function(addon){
myLog('AddonManager Event: Add-on Operation Canceled addon ID: '
+ addon.id + ' ::addon object:', addon);
},
onPropertyChanged: function(addon, properties){
myLog('AddonManager Event: Add-on Property Changed addon ID: ' + addon.id
+ ' ::properties= ', properties, ' ::addon object:', addon);
}
}
function installAddonListener(){
//Using an AddonManager listener is not effective to listen for your own add-on's
// install event. The event happens prior to you adding the listener.
myLog('In installAddonListener: Adding add-on listener');
AddonManager.addAddonListener(addonListener);
}
function uninstallAddonListener(){
if(doNotRemoveAddonManagerListenersUponUninstall === true){
//Do the WRONG thing to demonstrate what happens when you don't
// remove AddonManager listeners upon your add-on being disabled.
return;
}
//Using an AddonManager listener is not effective to listen for your own add-on's
// install event. The event happens prior to you adding the listener.
myLog('In removeAddonListener: Removing add-on listener');
AddonManager.removeAddonListener(addonListener);
}
installAddonListener();
myLog('Attaching content script A');
attachScript('./contentScriptA.js');
data/contentScriptA:
//console.log is ailiased to dump() when running under jpm run. Thus,
// you will not see the output from this line in the Browser Console
// when run under jpm run. It will appear in the console window from
// which you executed 'jpm run'
// From an .xpi it outputs to the Browser Console, as expected.
console.log(self.options.idText + ': In contentScriptA: Loaded');
//Send a message to the background script that this content script is loaded.
self.port.emit('consoleLog', 'received message from contentScriptA: Is Loaded');
data/contentScriptB:
//console.log is ailiased to dump() when running under jpm run. Thus,
// you will not see the output from this line in the Browser Console
// when run under jpm run. It will appear in the console window from
// which you executed 'jpm run'
// From an .xpi it outputs to the Browser Console, as expected.
console.log(self.options.idText + ': In contentScriptB: Loaded');
//Send a message to the background script that this content script is loaded.
self.port.emit('consoleLog', 'received message from contentScriptB: Is Loaded');
package.json(对于 installinfo@ex1):
{
"title": "Demo when code executes re install 1",
"name": "installinfo1",
"id": "installinfo@ex1",
"version": "0.0.1",
"description": "Demo when execute various code with respect to install",
"main": "index.js",
"author": "Makyen",
"engines": {
"firefox": ">=38.0a1",
"fennec": ">=38.0a1"
},
"license": "MIT",
"keywords": [
"jetpack"
]
}
package.json(对于 installinfo@ex2):
{
"title": "Demo when code executes re install 2",
"name": "installinfo2",
"id": "installinfo@ex2",
"version": "0.0.1",
"description": "Demo when execute various code with respect to install",
"main": "index.js",
"author": "Makyen",
"engines": {
"firefox": ">=38.0a1",
"fennec": ">=38.0a1"
},
"license": "MIT",
"keywords": [
"jetpack"
]
}
我是Mozilla扩展开发的新手,即使我才知道扩展和附加开发是不同的 我对我在 MDN(Mozilla 开发者网络)上看到的内容非常执着。 我想在我的附加组件安装后立即执行脚本 'content_script.js',这样用户就不需要重新启动浏览器。
我只是拖放我的 xpi 文件并安装它,然后我单击网页上的一个按钮,该按钮向我的附加组件发送消息,但我的附加组件只有在我重新加载网页后才会收听此消息。
//main.js
var chrome = require("chrome");
chrome.runtime.onInstalled.addListener(function(){
executeScript (contentscript.js) in tabs});
//also I tried
browser.runtime.onInstalled.addListener
当我知道它是用于 Mozilla 扩展而不是附加组件时,我正在尝试这个,因为它给我错误 browser undefined 和 chrome.runtime
is undefined.
然后,我在AddonManager.addAddonListener()
里面找到了onInstalled()
。
但是,我仍然很困惑如何在我的附加组件中使用它。
无论我尝试哪种方式,它都会给我错误。
//main.js
const { AddonManager } = require("resource://gre/modules/AddonManager.jsm");
Cu.import("resource://gre/modules/AddonManager.jsm");
AddonManager.addAddonListener.onInstalled.addListener(function(){
console.log('installed');
tabs.executeScript(tabId, "../data/content_script.js", function(result) { console.log('result ='+result); });
});
下面的代码删除了错误但也不起作用:
const { AddonManager } = require("resource://gre/modules/AddonManager.jsm");
Cu.import("resource://gre/modules/AddonManager.jsm");
var listener = {
onInstalled: function(addon) {
console.log('installed');
console.log(addon);
tabs.executeScript(tabId, "../data/content_script.js", function(result) { console.log('result ='+result); });
}
};
AddonManager.addAddonListener(listener);
我的package.json看起来像这样
{
"title": "test",
"name": "test",
"version": "1.0.0",
"description": "test addon corp",
"main": "lib/main.js",
"author": "test",
"engines": {
"firefox": ">=38.0a1",
"fennec": ">=38.0a1"
},
"license": "MIT",
"keywords": [
"jetpack"
]
}
main
包括 main.js,但它仍然没有执行,因为当我重新加载页面时,我的附加组件才工作。
我认为我做的完全错了,我是在 Chrome 扩展中做的,这很容易,但我对 Mozilla 附加组件一无所知。我什至无法达到 "installed"。执行content_script还差得远
您似乎遇到了一些问题:
- 您仍在混合使用 WebExtensions 和 Add-on SDK
- Add-on SDK没有
tabs.executeScript()
you are looking fortab.attach()
. For the active tab it would betabs.activeTab.attach()
这样的方法。
- Add-on SDK没有
- 安装当前正在安装的附加组件的
AddonManager
onInstalled
事件发生 先于 附加组件的任何代码 运行。因此,您不会收到正在侦听的附加组件的此事件。AddonManager
主要是为了让您的加载项能够监控涉及 其他 加载项的 activity。它在监控插件 activity 中的作用有限。- 您可以获得
AddonManager
onDisabled
event if the user disables the add-on prior to removing it. If the user directly removes it, you just get anonUninstalling
活动。
- 您可能 运行 正在解决以下问题:内容脚本中的
console.log()
未显示在浏览器控制台中,当时加载的加载项附加了内容脚本作为使用jpm run
进行测试的主要附加组件。输出在执行jpm run
的控制台 window 中可用。虽然输出到控制台 window 是设计使然,但我认为输出不进入浏览器控制台(除了控制台 window 之外)是错误或功能失调。 - 将内容脚本加载到
about:*
页面会导致某些行为不同于将其加载到普通网页。此行为可以包括制作console.log()
output only show up as if it was output usingdump()
(即它不会显示在浏览器控制台中,但会显示在执行 Firefox/jpm run
的控制台中)。如果您正在尝试这样做,您将需要试验您能够做什么。 - 您已经声明,"I think my main.js is not running right after installation." 这种信念可能是由于没有在正确的地方寻找
console.log()
输出 Browser Console。因此,我让下面的附加组件自动打开浏览器控制台。- 安装插件时在package.json key
"main"
运行中指定的JavaScript文件。在 Firefox 启动时也是 运行。 - 您可以有一个
exports.main
函数,它会在"main"
JavaScript 文件中的代码被评估和执行后自动调用。此功能可用于查找您的附加组件被执行的原因。可能的原因是install
、enable
、startup
、upgrade
和downgrade
。下面的附加组件演示了何时执行此代码并将reason
传递给它。
- 安装插件时在package.json key
为了演示各种东西,我编写了一个 Firefox 附加 SDK 扩展,它加载了几个内容脚本并侦听 AddonManager
事件。我制作了这个插件的两个版本,它们仅在名称和 ID 上有所不同,这些名称和 ID 在各自的 package.json 文件中分配给每个版本。这两个附加组件是 installinfo@ex1
和 installinfo@ex2
。
第一个附加组件 installinfo@ex1
由 运行ning jpm run
在其目录中加载。第二个插件 installinfo@ex2
是通过拖放 jpm xpi
为它创建的 .xpi[=116=] 来安装的。使用 Firefox UI,我立即导航到 about:addons
(Ctrl-Shift-A, Cmd-Shift-A on OSX) 然后继续首先禁用installinfo@ex2
;然后 "remove" installinfo@ex2
;然后刷新 about:addons
页面以使其无法 "undo" 删除。然后我退出 Firefox 主浏览器 window.
附加组件向控制台输出大量信息,因此您可以查看事件发生的顺序以及哪个附加组件能够接收哪些 AddonManager
事件。控制台输出是[括号内是我在用户界面上所做的,以及一些评论]:
[User action: Start Firefox in installinfo@ex1 directory]
installinfo@ex1: In index.js
installinfo@ex1: In installAddonListener: Adding add-on listener
installinfo@ex1: Attaching content script A
installinfo@ex1: In exports.main: This add-on is being loaded for reason= install Object { loadReason: "install", staticArgs: undefined }
installinfo@ex1: Attaching content script B
installinfo@ex1: In exports.main: was passed callbacks= Object { print: print(), quit: function () }
[Note: no console.log output from within conentScriptA loading]
installinfo@ex1: received message from contentScriptA: Is Loaded
[Note: no console.log output from within conentScriptB loading]
installinfo@ex1: received message from contentScriptB: Is Loaded
[User action: Drag and drop .xpi for installinfo@ex2 onto Firefox]
installinfo@ex1: AddonManager Event: Installing addon ID: installinfo@ex2 ::needsRestart= false ::addon object: Object { }
installinfo@ex1: AddonManager Event: Installed addon ID: installinfo@ex2 ::addon object: Object { }
installinfo@ex2: In index.js
installinfo@ex2: In installAddonListener: Adding add-on listener
installinfo@ex2: Attaching content script A
installinfo@ex2: In exports.main: This add-on is being loaded for reason= install Object { loadReason: "install", staticArgs: undefined }
installinfo@ex2: Attaching content script B
installinfo@ex2: In exports.main: was passed callbacks= Object { print: print(_), quit: function () }
installinfo@ex2: In contentScriptA: Loaded
installinfo@ex2: received message from contentScriptA: Is Loaded
installinfo@ex2: In contentScriptB: Loaded
installinfo@ex2: received message from contentScriptB: Is Loaded
[User action: Navigate to about:addons]
[User action: Disable installinfo@ex2]
installinfo@ex1: AddonManager Event: Disabling addon ID: installinfo@ex2 ::needsRestart= false ::addon object: Object { }
installinfo@ex2: AddonManager Event: Disabling addon ID: installinfo@ex2 ::needsRestart= false ::addon object: Object { }
installinfo@ex2: In exports.onUnload: This add-on is being unloaded for reason= disable
installinfo@ex2: In removeAddonListener: Removing add-on listener
installinfo@ex1: AddonManager Event: Disabled addon ID: installinfo@ex2 ::addon object: Object { }
installinfo@ex2: AddonManager Event: Disabled addon ID: installinfo@ex2 ::addon object: Object { }
installinfo@ex1: AddonManager Event: Uninstalling addon ID: installinfo@ex2 ::needsRestart= true ::addon object: Object { }
[Get a warning in Browser Console because installinfo@ex2 did not remove its AddonManager listeners, and AddonManager is still trying to call them.]
1472563865661 addons.manager WARN AddonListener threw exception when calling onUninstalling: TypeError: can't access dead object (resource://gre/modules/AddonManager.jsm:1756:1) JS Stack trace: AddonManagerInternal.callAddonListeners@AddonManager.jsm:1756:1 < this.AddonManagerPrivate.callAddonListeners@AddonManager.jsm:3075:5 < this.XPIProvider.uninstallAddon@XPIProvider.jsm:5041:7 < AddonWrapper.prototype.uninstall@XPIProvider.jsm:7484:5 < uninstall@extensions.xml:1548:13 < oncommand@about:addons:1:1
[User action: Refresh about:addons page to remove "undo" posibility for installinfo@ex2]
installinfo@ex1: Uninstalled addon ID: installinfo@ex2 ::addon object: Object { }
[Get a warning in Browser Console because installinfo@ex2 did not remove its AddonManager listeners, and AddonManager is still trying to call them.]
1472563873408 addons.manager WARN AddonListener threw exception when calling onUninstalled: TypeError: can't access dead object (resource://gre/modules/AddonManager.jsm:1756:1) JS Stack trace: AddonManagerInternal.callAddonListeners@AddonManager.jsm:1756:1 < this.AddonManagerPrivate.callAddonListeners@AddonManager.jsm:3075:5 < this.XPIProvider.uninstallAddon@XPIProvider.jsm:5096:7 < AddonWrapper.prototype.uninstall@XPIProvider.jsm:7484:5 < doPendingUninstalls@extensions.js:1740:5 < gListView.hide@extensions.js:2733:5 < gViewController.shutdown@extensions.js:651:7 < shutdown@extensions.js:184:3 < EventListener.handleEvent*@extensions.js:84:1
[User action: Close main Firefox browser window]
[User action: Close Firefox Browser Console window]
(via dump):installinfo@ex1: In exports.onUnload: This add-on is being unloaded for reason= shutdown
我建议您试验下面的附加组件,以了解 AddonManager 事件的可能性以及代码何时在您的附加组件中执行。
附加文件:
index.js:
/* Firefox Add-on SDK test when code is executed upon install*/
//For testing:
var doNotRemoveAddonManagerListenersUponUninstall = true
var self = require("sdk/self");
var tabs = require("sdk/tabs");
var myId = self.id;
let myIdText = myId;
if(myId.indexOf('2') > -1){
//Indent console logs for version 2
myIdText = '\t\t' + myIdText ;
}
var utils = require('sdk/window/utils');
activeWin = utils.getMostRecentBrowserWindow();
//This will execute every time the add-on is loaded (e.g. install, startup, enable, etc).
myLog('In index.js');
//Open the Browser Console
activeWin.document.getElementById('menu_browserConsole').doCommand();
function myLog(){
// Using activeWin.console.log() is needed to have output to the
// Browser Console when installed as an .xpi file. In that case,
// console is mapped to dump(), which does not output to the console.
// This is done, I assume, to not polute the console from SDK add-ons
// that are logging information when they should not. Using jpm run,
// console.log outputs to the Browser Console.
let activeWin = require('sdk/window/utils').getMostRecentBrowserWindow();
// If Firefox is exiting (and some other conditions), there is
// no active window. At such times, we must use the version
// of console.log() aliases to dump().
let useConsole = console;
if(activeWin ){
//useConsole = activeWin.console;
}
useConsole.log(myIdText +':',...arguments);
}
function attachScript(script){
let tabWorker = tabs.activeTab.attach({
contentScriptFile: script,
contentScriptOptions: {
//extra \t because content script console.log (from .xpi) doesn't prefix with
// add-on name.
idText: '\t\t\t' + myIdText
}
});
tabWorker.port.on('consoleLog',logMessage);
return tabWorker;
}
function logMessage(message){
myLog(message);
}
exports.main = function (options,callbacks) {
myLog('In exports.main: This add-on is being loaded for reason=', options.loadReason
, options);
myLog('Attaching content script B');
attachScript('./contentScriptB.js');
if(typeof callbacks !== 'undefined'){
myLog('In exports.main: was passed callbacks=', callbacks);
}
switch (options.loadReason) {
case 'install':
//Do actions upon install
break;
case 'enable':
//Do actions upon enable
break;
case 'startup':
//Do actions upon startup
break;
case 'upgrade':
//Do actions upon upgrade
break;
case 'downgrade':
//Do actions upon downgrade
break;
default:
throw 'Unknown load reason:' + options.loadReason;
break; //Not needed, throw will exit
}
};
exports.onUnload = function (reason) {
myLog('In exports.onUnload: This add-on is being unloaded for reason=',reason);
//Your add-on listeners are NOT automatically removed when
// your add-on is disabled/uninstalled.
//You MUST remove them in exports.onUnload if the reason is
// not 'shutdown'. If you don't, errors will be shown in the
// console for all events for which you registered a listener.
if(reason !== 'shutdown') {
uninstallAddonListener();
}
};
const { AddonManager } = require("resource://gre/modules/AddonManager.jsm");
let addonListener = {
onEnabling: function(addon, needsRestart){
myLog('AddonManager Event: Enabliling addon ID: ' + addon.id
+ ' ::needsRestart= ' + needsRestart + ' ::addon object:', addon);
},
onEnabled: function(addon){
myLog('AddonManager Event: Enabled addon ID: ' + addon.id
+ ' ::addon object:', addon);
},
onDisabling: function(addon, needsRestart){
myLog('AddonManager Event: Disabling addon ID: ' + addon.id
+ ' ::needsRestart= ' + needsRestart + ' ::addon object:', addon);
},
onDisabled: function(addon){
myLog('AddonManager Event: Disabled addon ID: ' + addon.id
+ ' ::addon object:', addon);
},
onInstalling: function(addon, needsRestart){
myLog('AddonManager Event: Installing addon ID: ' + addon.id
+ ' ::needsRestart= ' + needsRestart + ' ::addon object:', addon);
},
onInstalled: function(addon){
myLog('AddonManager Event: Installed addon ID: ' + addon.id
+ ' ::addon object:', addon);
},
onUninstalling: function(addon, needsRestart){
myLog('AddonManager Event: Uninstalling addon ID: ' + addon.id
+ ' ::needsRestart= ' + needsRestart + ' ::addon object:', addon);
},
onUninstalled: function(addon){
myLog('AddonManager Event: Uninstalled addon ID: ' + addon.id
+ ' ::addon object:', addon);
},
onOperationCancelled: function(addon){
myLog('AddonManager Event: Add-on Operation Canceled addon ID: '
+ addon.id + ' ::addon object:', addon);
},
onPropertyChanged: function(addon, properties){
myLog('AddonManager Event: Add-on Property Changed addon ID: ' + addon.id
+ ' ::properties= ', properties, ' ::addon object:', addon);
}
}
function installAddonListener(){
//Using an AddonManager listener is not effective to listen for your own add-on's
// install event. The event happens prior to you adding the listener.
myLog('In installAddonListener: Adding add-on listener');
AddonManager.addAddonListener(addonListener);
}
function uninstallAddonListener(){
if(doNotRemoveAddonManagerListenersUponUninstall === true){
//Do the WRONG thing to demonstrate what happens when you don't
// remove AddonManager listeners upon your add-on being disabled.
return;
}
//Using an AddonManager listener is not effective to listen for your own add-on's
// install event. The event happens prior to you adding the listener.
myLog('In removeAddonListener: Removing add-on listener');
AddonManager.removeAddonListener(addonListener);
}
installAddonListener();
myLog('Attaching content script A');
attachScript('./contentScriptA.js');
data/contentScriptA:
//console.log is ailiased to dump() when running under jpm run. Thus,
// you will not see the output from this line in the Browser Console
// when run under jpm run. It will appear in the console window from
// which you executed 'jpm run'
// From an .xpi it outputs to the Browser Console, as expected.
console.log(self.options.idText + ': In contentScriptA: Loaded');
//Send a message to the background script that this content script is loaded.
self.port.emit('consoleLog', 'received message from contentScriptA: Is Loaded');
data/contentScriptB:
//console.log is ailiased to dump() when running under jpm run. Thus,
// you will not see the output from this line in the Browser Console
// when run under jpm run. It will appear in the console window from
// which you executed 'jpm run'
// From an .xpi it outputs to the Browser Console, as expected.
console.log(self.options.idText + ': In contentScriptB: Loaded');
//Send a message to the background script that this content script is loaded.
self.port.emit('consoleLog', 'received message from contentScriptB: Is Loaded');
package.json(对于 installinfo@ex1):
{
"title": "Demo when code executes re install 1",
"name": "installinfo1",
"id": "installinfo@ex1",
"version": "0.0.1",
"description": "Demo when execute various code with respect to install",
"main": "index.js",
"author": "Makyen",
"engines": {
"firefox": ">=38.0a1",
"fennec": ">=38.0a1"
},
"license": "MIT",
"keywords": [
"jetpack"
]
}
package.json(对于 installinfo@ex2):
{
"title": "Demo when code executes re install 2",
"name": "installinfo2",
"id": "installinfo@ex2",
"version": "0.0.1",
"description": "Demo when execute various code with respect to install",
"main": "index.js",
"author": "Makyen",
"engines": {
"firefox": ">=38.0a1",
"fennec": ">=38.0a1"
},
"license": "MIT",
"keywords": [
"jetpack"
]
}