Chrome开发者工具面板扩展与后台页面通信

20
我有一个用于 Chrome 开发者工具面板的扩展程序。我可以使用 chrome.devtools.inspectedWindow.eval 发送消息到页面上......但是,如何在开发面板中接收消息呢?具体而言,我需要让我的开发面板连接到页面上发生的事件。我无法使其监听内容脚本或后台页面上的事件。
我尝试在内容脚本中使用 chrome.extension.sendMessage,并在开发面板脚本中使用 chrome.extension.onMessage.addListener。但是sendMessage会报错:Port error: Could not establish connection. Receiving end does not exist. 长期连接时问题仍然存在:
在内容脚本或后台页面中:
var port = chrome.extension.connect({name: "test"});
port.postMessage({msg: "testing"});
在开发工具面板中的 JavaScript:
chrome.extension.onConnect.addListener(function(port) {
    port.onMessage.addListener(function(msg) {
         // never gets here
    });
 });
我该如何监听在我的内容脚本中触发的事件 - 在我的开发工具面板中呢?如果有像Firefox的Add-On SDK中这样的图表,那就太好了:https://addons.mozilla.org/en-US/developers/docs/sdk/latest/static-files/media/content-scripting-overview.png

文档提供了一个在后台脚本和开发工具脚本之间通信的示例。请参见"Broken links" demo。(background.jsdevtools.js - Rob W
@RobW 尽管在那个例子中背景脚本和开发工具之间进行了通信,但这种通信方式对我来说行不通。在那个例子中,devtools.js 发送一条消息并获取一个回调。当事件发生时,我需要背景脚本向开发工具页面发送一条消息,除非我不断地轮询,否则这种回调方法是行不通的 -- 这是一种不好的做法。 - Salami
我想要展示的概念是连接是由 devtools 脚本初始化,而不是后台脚本。现在我已经将这个概念转化为一个完整的答案,包括一个示例,展示如何在两个方向上传递消息,并根据消息修改面板内容。 - Rob W
1个回答

57

目标是创建一个通信的渠道(“端口”)。无论如何创建端口,只要连接正确维护即可。

devtools脚本必须启动端口,因为后台脚本不知道何时创建了devtools面板。

下面是一个基本示例,展示了双向通信方法:

devtools.js

chrome.devtools.panels.create('Test', '/icon.png', '/panel.html', function(extensionPanel) {
    var _window; // Going to hold the reference to panel.html's `window`

    var data = [];
    var port = chrome.runtime.connect({name: 'devtools'});
    port.onMessage.addListener(function(msg) {
        // Write information to the panel, if exists.
        // If we don't have a panel reference (yet), queue the data.
        if (_window) {
            _window.do_something(msg);
        } else {
            data.push(msg);
        }
    });
    
    extensionPanel.onShown.addListener(function tmp(panelWindow) {
        extensionPanel.onShown.removeListener(tmp); // Run once only
        _window = panelWindow;

        // Release queued data
        var msg;
        while (msg = data.shift()) 
            _window.do_something(msg);
        // Just to show that it's easy to talk to pass a message back:
        _window.respond = function(msg) {
            port.postMessage(msg);
        };
    });
});

现在,该面板可以通过端口发送/接收消息。面板的脚本(外部脚本文件,因为CSP)可能如下所示:

panel.js

function do_something(msg) {
    document.body.textContent += '\n' + msg; // Stupid example, PoC
}
document.documentElement.onclick = function() {
    // No need to check for the existence of `respond`, because
    // the panel can only be clicked when it's visible...
    respond('Another stupid example!');
};

现在,是后台页面的脚本:

background.js

var ports = [];
chrome.runtime.onConnect.addListener(function(port) {
    if (port.name !== "devtools") return;
    ports.push(port);
    // Remove port when destroyed (eg when devtools instance is closed)
    port.onDisconnect.addListener(function() {
        var i = ports.indexOf(port);
        if (i !== -1) ports.splice(i, 1);
    });
    port.onMessage.addListener(function(msg) {
        // Received message from devtools. Do something:
        console.log('Received message from devtools page', msg);
    });
});
// Function to send a message to all devtools.html views:
function notifyDevtools(msg) {
    ports.forEach(function(port) {
        port.postMessage(msg);
    });
}

要进行测试,只需在后台页面上运行notifyDevtools('Foo');(例如通过控制台)。在此演示中,消息将发送到所有开发工具。收到后,开发工具面板将包含接收到的消息。

使用以下内容组装扩展程序:

manifest.json

{
  "name": "Test",
  "manifest_version": 2,
  "version": "1",
  "devtools_page": "devtools.html",
  "background":{"scripts":["background.js"]}
}

panel.html

<script src="panel.js"></script> <!-- Doctype etc not added for conciseness-->

devtools.html

<script src="devtools.js"></script>

参见


很棒的答案,通过没有断开的端口发送消息解决了问题。 - Salami
我在尝试将这个与内容脚本一起使用时遇到了问题。我需要一个内容脚本能够与开发工具脚本进行通信。你有这方面的示例吗? - Raymond Camden
谢谢您的示例!我有一个后续问题:从文档中看来,只要清单中的“权限”字段允许,就应该可以向任何网站发出XMLHttpRequests请求,但是在多次尝试之后这并没有起作用。 - airportyh
@airportyh 创建一个新的问题或聊天室,以尽量减少离题评论。 - Rob W
1
@mindplay.dk 这个答案仍然有效。在Chrome 71和73.0.3666.0上测试通过。测试步骤:1)加载扩展程序 2)打开devtools 3)切换到“测试”面板 4)单击白色面板(即panel.html,以触发panel.js的onclick处理程序)5)切换回控制台选项卡并观察预期消息。请注意,在加载devtools之前必须加载背景页面(否则runtime.onConnect侦听器将无法响应)。 - Rob W
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接