0

I'm writing a google chrome extension which could click links and buttons. I have to revoke the extension using the background script once the redirect button/link is clicked and the page is changed. The issue is the message indicates only one sent in the background script, but the onMessage listener in the content script receives two messages. How could this be fixed?

background.js

chrome.webNavigation.onCompleted.addListener((details) => {
  chrome.tabs &&
    chrome.tabs.query({ active: true, currentWindow: true }, () => {
      setTimeout(() => {
        const storage = chrome.storage.local;
        storage.get("activeProcess", (result) => {
          let activeProcess = Object.values(result)[0];
          if (activeProcess && details.frameType === "outermost_frame") {
            const tabId = details.tabId;
            storage.get("message", (result) => {
              result.message.url = details.url;
              result.message.source = "background";
              console.log("message sent");
              chrome.tabs.sendMessage(tabId, result.message, (res) => {
                console.log(res);
              });
            });
          }
        });
      }, 100);
    });
  return true;
});

message sent

content.js



chrome.runtime.onMessage.addListener(messagesListener);

async function messagesListener(message, sender, response) {
  await processMessage(message, sender, response);
}

export const processMessage = async (message, sender, response) => {
  console.log("message received")
}

message received message received

1 Answers1

0
  1. Prerendered tab is also reported, then it goes active and gets reported again.

    Solution: check documentLifecycle in the details parameter.

  2. chrome.tabs.sendMessage sends to all frames of the tab, so if your content script is injected in all frames every instance will receive a copy of the message.

    Solution: use the event's frameId in sendMessage options parameter explicitly.

  3. If you injected using chrome.scripting.executeScript it may have run twice.

    Solution: send a message first to verify the content script runs or check a global variable inside the content script (example).

chrome.webNavigation.onCompleted.addListener(d => {
  if (d.frameType !== 'outermost_frame' || d.documentLifecycle !== 'active')
    return;
  setTimeout(async () => {
    const {activeProcess, message} = await chrome.storage.local.get(
      ['activeProcess', 'message']);
    if (!activeProcess) return;
    message.url = d.url;
    message.source = 'background';
    const res = await chrome.tabs.sendMessage(d.tabId, message, {frameId: d.frameId});
    console.log(res);
  }, 100);
});
wOxxOm
  • 65,848
  • 11
  • 132
  • 136
  • I replaced the code in the background script with the code you provided but the issue remains. Are there any changes that need to be made in the content script as well? Also, I didn't find any "chrome.scripting.executeScript" in my code, so probably it isn't causing an issue. Thanks in advance for the reply! – Pavel Smith Mar 28 '23 at 04:25
  • If your content script is declared with all_frames and the page has an iframe then the behavior is correct. – wOxxOm Mar 28 '23 at 07:15
  • No my parameter is: "all_frames": false – Pavel Smith Mar 28 '23 at 15:59
  • Well then without debugging the extension myself I can only guess it's a bug in Chrome. Are you sure sendMessage runs only once? Console collapses identical messages by default and doesn't print anything if its sole parameter is undefined. – wOxxOm Mar 28 '23 at 17:49
  • I put math.random() instead of the message send and in logs only once even though the message received logs twice. So it looks like the message is being sent once but received twice. Let me know if we could connect anyhow to continue investigating the issue, if you have such opportunity of course :) – Pavel Smith Mar 28 '23 at 20:34
  • After setting up a debugger I find out that there are actually two messages that are being sent one of which ignores the debugger and send it right away into the content script, do you have any ideas about what can cause this? – Pavel Smith Mar 29 '23 at 21:16
  • Open `chrome://serviceworker-internals` and see if your extension has two service workers. – wOxxOm Mar 29 '23 at 21:54
  • It shows only one, and so is my manifest. Also, this duplicating only happens when the redirect is happening. If I would like to run a background script on button click or something like this it will run single time and will follow breakpoints – Pavel Smith Mar 29 '23 at 22:13
  • Ah, apparently the redirected URL is reported in onCompleted too. I guess you can add a listener for onCommitted and check [transitionQualifiers](https://developer.chrome.com/docs/extensions/reference/webNavigation/#transition-types-and-qualifiers), and ignore onCompleted for this tabId+url combination. – wOxxOm Mar 29 '23 at 22:48