首页 > 解决方案 > Chrome 扩展 UI 页面和内容脚本之间的通信问题

问题描述

这里的菜鸟问题:

上周我写了一个非常基本的 Chrome 扩展程序,其中一个 popup.js 向 content.js 脚本发送一条消息,方式如下(也许这不是最好的方式,但重要的是它有效。为什么这很重要吗?忍受我......)

在 popup.js

someButton.addEventListener('click', (event) => {
    chrome.tabs.executeScript(null, {
        file: 'src/content.js',
    }, () => {
        connect();
    });
});

然后:

function connect() {
    chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
        const port = chrome.tabs.connect(tabs[0].id);
        port.postMessage({ type: 'info', data: someValue });
    })
}

在 content.js

if (!chrome.runtime.onConnect.hasListeners()) {
    chrome.runtime.onConnect.addListener((port) => {
        port.onMessage.addListener((msg) => {
            if (msg && msg.type == "info") {
               // do some stuff
            }
        });
    });
}

这行得通,但我相信这不是最好的方法。自上周以来,我一直在阅读更多内容,并且知道我相信正确的方法应该是这样的:

在 popup.js 上

chrome.tabs.query({ active: true, currentWindow: true },  (tabs) => {
      chrome.tabs.sendMessage(tabs[0].id, {
        type: "info",
        someValue: value
      });
    });

在 content.js 中

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
        if (request.type == "info"){
           sendResponse({ message: "some answer" }) 
        }
        return true;
    })

但是在我的新版本中,这不起作用,即使每个教程和文档都说应该这样做。我没有收到任何错误,只是添加到侦听器的函数永远不会执行。

我怀疑这可能与我现在使用 React 和 Webpack 有关,也许 Webpack 正在做一些奇怪的事情?

我的 manifest.json 的一个片段

 "background": {
        "persistent": false,
        "scripts": ["background.bundle.js"]
    },
    "content_scripts": [{
        "matches": ["<all_urls>"],
        "js": ["content.bundle.js"]
    }],

也许问题是我正在使用捆绑包指定内容和背景?不确定,我唯一知道的是,根据我的理解,这应该有效,但事实并非如此。

我错过了什么?

PS:我要补充一点,我一直在调试,我发现内容文件正在执行,并且发送消息的那段代码也已执行。就像 addListener 没有正确添加,或者由于某种原因从未收到消息。

标签: reactjswebpackgoogle-chrome-extension

解决方案


当您content_scripts在 manifest.json 中声明时,它默认在DOMContentLoadedload事件之间运行,因此如果您在仍在加载的复杂页面上打开弹出窗口,则不会有内容脚本来接收消息。

您可以指定"run_at": "document_start"document.documentElement使内容脚本在页面仍然为空时在 "start" 处运行,DOM 将只有<html>节点,不会有<head>or <body>

请注意,在 manifest.json 中声明的内容脚本始终在每个匹配页面中运行,因此如果您的扩展程序仅在单击弹出窗口后才需要内容脚本,这将非常非常糟糕,因为您浪费了 99.999% 的时间和实际上需要广泛的主机权限。在这种情况下,您应该 1)content_scripts从 manifest.json 中删除,2) 添加activeTab“权限”并删除任何广泛的主机权限,例如<all_urls>or*://*/*http://*/*3) 像以前一样使用 executeScript 和 hasListeners。


推荐阅读