google-chrome-extensionchrome-extension-manifest-v3

Navigate tab to a URL and execute script inside


I am struggling to get this simple f-ty working... My scenario is:

  1. get current URL
  2. modify it
  3. navigate/redirect to it
  4. execute custom JS code there

The most problems I have is with 4)

manifest.json

{
  "name": "Hello, World!",
  "description": "Navigate and execute custom js script",
  "version": "1.0",
  "manifest_version": 3,
  "permissions": [
    "tabs",
    "activeTab",
    "scripting"
  ],
  "background": {
    "service_worker": "background.js"
  },
  "action": {}
}

background.js

function myCustomScript() {
    alert('myCustomScript test ok!');
    console.log('myCustomScript test ok!');
}

chrome.action.onClicked.addListener((tab) => {

    chrome.tabs.update({url: "https://example.com"}, myCustomScript);

});

The page got redirected but my js function is not executed! Do you know why and how to fix it?

P.S: this is my first time I am creating my chrome extension, maybe I am doing something wrong...


Solution

  • To execute custom code, use chrome.scripting API. For this scenario you'll need:

    1. "scripting" added to "permissions", which you already have,
    2. "https://example.com/" added to "host_permissions" in manifest.json.

    Note that activeTab permission won't apply to the tab after it's navigated to a URL with a different origin because this permission only applies to the currently shown origin.

    Due to a bug in Chrome, you need to wait for the URL to be set before executing the script.

    chrome.action.onClicked.addListener(async tab => {
      await chrome.tabs.update(tab.id, {url: "https://example.com"});
      // Creating a tab needs the same workaround
      // tab = await chrome.tabs.create({url: "https://example.com"});
      await onTabUrlUpdated(tab.id);
      const results = await chrome.scripting.executeScript({
        target: {tabId: tab.id},
        files: ['content.js'],
      });
      // do something with results
    });
    
    function onTabUrlUpdated(tabId) {
      return new Promise((resolve, reject) => {
        const onUpdated = (id, info) => id === tabId && info.url && done(true);
        const onRemoved = id => id === tabId && done(false);
        chrome.tabs.onUpdated.addListener(onUpdated);
        chrome.tabs.onRemoved.addListener(onRemoved);
        function done(ok) {
          chrome.tabs.onUpdated.removeListener(onUpdated);
          chrome.tabs.onRemoved.removeListener(onRemoved);
          (ok ? resolve : reject)();
        }
      });
    }
    

    P.S. alert can't be used in a service worker. Instead, you should look at devtools console of the background script or use chrome.notifications API.