Search code examples
google-chrome-extensionbackgroundcontent-script

Chrome extension background activating inactive tab


I am using manifest 2. I have an extension that requires opening a "inactive tab" to a specific url, gathering information and sending a message to the background to close this tab when we are done. When I send the message to the background, I try to close the tab by using one of the following.


      setTimeout( () => {
            chrome.tabs.highlight({ tabs: sender.tab.index }, function () {
                chrome.tabs.remove(sender.tab.id);
            });
        }, 500);

OR

       setTimeout(function () {
            chrome.tabs.update(sender.tab.id, { active: true }, function () {
                chrome.tabs.remove(sender.tab.id);
            });
        }, 500);

Both of these are unsucessful until I actually click on the tab to activate it, and then the tab will execute the remove call.

These are the permissions I have set in my extension.

   "permissions": [
        "activeTab",
        "tabs",
        "notifications",
        "contextMenus",
        "storage",
        "<all_urls>"
    ]

Does anybody have any suggestions?

Thanks in advance, Tom


Solution

  • I have prepared a minimal manifest v2 example to show how to achieve this behavior, using callback style.

    manifest.json

    Here "https://www.google.com/*" is an example url where to open the tab; it could be anything.

    {
      "name": "EXAMPLE",
      "version": "0.0.0",
      "manifest_version": 2, 
      "permissions": [
        "activeTab",
        "https://www.google.com/*"
      ],
      "background": {
        "scripts": ["background.js"]
      }
    }
    

    content.js

    The content script will instantly send a message over message passing to registered listeners.

    chrome.runtime.sendMessage({msg: document.body.innerText});
    

    background.js

    // step 1: create tab
    chrome.tabs.create({
    
        // tab properties
        active: false,
        url: 'https://www.google.com/'
    
    }, ({id: createdTabId}) => {
    
        // step 2: register listener to receive message from tab
        chrome.runtime.onMessage.addListener((request, sender) => {
    
                // step 4. using tab id to identify response from same tab
                if (createdTabId === sender.tab.id) {
    
                    // close the created tab
                    chrome.tabs.remove(createdTabId);
    
                    // do something with the received data
                    window.alert(`message from tab: ${request.msg}`);
                }
            }
        );
    
        // step 3: programmatically load content script after registering listener
        // in MV3 this is called: chrome.scripting.executeScript
        chrome.tabs.executeScript(createdTabId, {file: 'content.js'});
    });
    

    The background script does four things, in sequence:

    1. creates the inactive tab
    2. registers a listener to receive a response from the created tab
    3. loads the content script into the created tab
    4. after receiving message, displays the message value

    I am using the tab id to identify the message sender, which requires waiting for the tab creation to finish before registering the listener, and then loading the content script, since content script will immediately send a response. This is a choice. An alternative approach would be to specify, in manifest, content script to load on a specific match pattern, the registering the listener before opening a tab, and using something other than tab id as the condition for identifying response from tab.