javascriptfirefox-addonfirefox-addon-webextensions

Can't successfully run executeScript from the background script unless I load the popup page/script first


I've trying to run execute script from my background script using keyboard shortcuts, it doesn't work and returns:

Error: No window matching {"matchesHost":[]}

But if I just open the popup page, close it, and do the same, everything works.

I've recreated the problem in using the Beastify example with minimal changes. Here's the code:

manifest.json

{
    ... (not interesting part, same as in beastify)

    "permissions": [
    "activeTab"
    ],  

    "browser_action": {
        "default_icon": "icons/beasts-32.png",
        "default_title": "Beastify",
        "default_popup": "popup/choose_beast.html"
    },

    "web_accessible_resources": [
        "beasts/frog.jpg",
        "beasts/turtle.jpg",
        "beasts/snake.jpg"
    ],

My additions start here:

    "background": {
        "scripts": ["background_scripts/background_script.js"]
    },

    "commands": {
        "run_content_test": {
            "suggested_key": {
                "default": "Alt+Shift+W"
            }
        }
    }
}

popup/choose_beast.js (same as in original)

/*
Given the name of a beast, get the URL to the corresponding image.
*/
function beastNameToURL(beastName) {
  switch (beastName) {
    case "Frog":
      return browser.extension.getURL("beasts/frog.jpg");
    case "Snake":
      return browser.extension.getURL("beasts/snake.jpg");
    case "Turtle":
      return browser.extension.getURL("beasts/turtle.jpg");
  }
}

/*
Listen for clicks in the popup.

If the click is on one of the beasts:
  Inject the "beastify.js" content script in the active tab.

  Then get the active tab and send "beastify.js" a message
  containing the URL to the chosen beast's image.

If it's on a button which contains class "clear":
  Reload the page.
  Close the popup. This is needed, as the content script malfunctions after page reloads.
*/
document.addEventListener("click", (e) => {
  if (e.target.classList.contains("beast")) {
    var chosenBeast = e.target.textContent;
    var chosenBeastURL = beastNameToURL(chosenBeast);

    browser.tabs.executeScript(null, {
      file: "/content_scripts/beastify.js"
    });

    var gettingActiveTab = browser.tabs.query({active: true, currentWindow: true});
    gettingActiveTab.then((tabs) => {
      browser.tabs.sendMessage(tabs[0].id, {beastURL: chosenBeastURL});
    });
  }
  else if (e.target.classList.contains("clear")) {
    browser.tabs.reload();
    window.close();

    return;
  }
});

background_scripts/background_script.js (added by me)

browser.commands.onCommand.addListener(function(command) {
    var executing = browser.tabs.executeScript(
            null, 
            {file: "/content_scripts/content_test.js"});

    executing.then(
            function (res){
                console.log("started content_test.js: " + res);
            }, 
            function (err){
                console.log("haven't started, error: " + err);
            });
});

content_scripts/content_test.js (added by me)

alert("0");

I'm skipping the whole content_scripts/beastify.js cause it has nothing to do with it (IMO), but it can be found here.

Now, I know that the background script runs and receives the messages even when the popup page hasn't been opened before, because I see it failing executing the script. I have no idea what causes this behavior and if there's a way to fix it.

Note: I tried adding permissions such as "tabs" and even "all_urls", but it didn't change anything.

Note 2: I'm running the add-on as a temporary add-on from the about:debugging page, but I'm trying to execute the script on a normal non-restricted page (on this page for example I can recreate the problem).

Thanks a lot guys!


Solution

  • // in manifest.json
    
        "permissions": [
           "<all_urls>",
           "activeTab"
        ],
    

    DOES work for me (Firefox 50, Mac OS X 10.11.6).

    I had gotten the exact same error message you described when I had used the original

        "permissions": [
           "activeTab"
        ],
    

    So the addition of "<all_urls>" seems to fix the problem. However, you said that you were still experiencing the issue when you included "all_urls" in your permissions, so I am not sure whether the way I did it fixes the issue in your own setup.

    edit: Whether giving any webextension such broad permissions would be wise in terms of the security risks it might pose is a separate, important consideration, I would imagine.

    (I would have posted this as a comment, but I don't have enough reputation yet to be able to add comments.)