在Chrome扩展程序中,内容脚本在初始加载时不会从后台接收消息

avwztpqn  于 12个月前  发布在  Go
关注(0)|答案(1)|浏览(125)

在我的Chrome扩展中,内容脚本应该在页面加载时从后台脚本接收消息。但是当我打开一个新标签并输入URL https://example.com时,它没有收到消息。但是,它在页面重新加载时工作。是因为页面是从Chrome://newtab加载的吗?

// background script
chrome.runtime.onMessage.addListener(function (message, sender) {
  if (message.action === "NOTIFY_CONTENT_SCRIPT_LOADED") {
    console.log(`### ACK content script in page: ${message.pageURL} and tab: ${sender.tab.url}`);

    chrome.tabs.sendMessage(sender.tab.id, { action: "CHANGE_BG" }, () => {
      console.log("### ACK changed BG color of client page");
      // do more stuff
    });
  }
});
// content script
chrome.runtime.onMessage.addListener((message, _, sendResponse) => {
  if (message.action === "CHANGE_BG") {  // <---- This is not received on first page load
    document.body.style.background = "yellow";
    sendResponse();
  }
});

console.log("### Notifying background from page: " + location.href);
chrome.runtime.sendMessage({ action: "NOTIFY_CONTENT_SCRIPT_LOADED", pageURL: location.href });

来自后台脚本的控制台日志:

### ACK content script in page: https://example.com/ and tab: chrome://newtab/

请注意,sender.tab.urlchrome://newtab/而不是https://example.com/。这是间歇性发生的。也就是说,在某些情况下不会发生:

  • 当页面重新加载时
  • 当浏览器检查窗口已经打开时

我创建了一个具有相同问题的示例扩展:https://github.com/lazyvab/chrome-newtab-issue
编辑:尝试来自评论的建议-
如果有多个消息,不要使用sendMessage,而是切换到chrome. runtime. connect。

// content script
const bgPort = chrome.runtime.connect();
bgPort.onMessage.addListener((msg) => {
  console.log("### Received BG msg", msg);
});

// background script
chrome.runtime.onConnect.addListener((port) => {
  port.onDisconnect.addListener((...args) => {
    console.log("### disconnected port on tab", tabId, ...args);
  });

  console.log("### BG: sending ping to tab", tabId);
  port.postMessage({ action: "ping" });
});

我打开https://example.com在新的标签页,这里是结果。
后台页面控制台截图:

内容脚本(页面)控制台截图:

从屏幕截图中可以看出,端口在网站加载后立即断开,后台脚本无法再次使用端口发送消息。

bxjv4tth

bxjv4tth1#

我最终可以通过在内容脚本和后台脚本之间建立一个长期端口连接来解决这个问题,以防出现预先呈现的页面。

// background.js
let clientPort = null;
let clientLoadSubscribers = [];

chrome.runtime.onConnect.addListener((port) => {
    const tabId = port.sender.tab.id;

    if (port.sender.documentLifecycle === "active") {
      clientPort = port;
      clientLoadSubscribers.forEach((subscriber) => subscriber());
      clientLoadSubscribers = [];
    }

    port.onDisconnect.addListener(() => {
      clientPort = null;

      chrome.tabs.executeScript(
        tabId,
        {
          code: "chrome.runtime.connect()",
        },
        () => {
          if (chrome.runtime.lastError) {
            // ignore
          }
        }
      );
    });
});

const sendMessageToClient = (tabId, ...restArgs) => {
  const send = () => chrome.tabs.sendMessage(tabId, ...restArgs);

  if (clientPort) {
    send();
  } else {
    clientLoadSubscribers.push(send);
  }
};
// content script
chrome.runtime.connect();

这样,我就可以使用sendMessageToClient()可靠地将消息从后台发送到内容脚本。

相关问题