扩展开发者工具

概览

DevTools 扩展程序会向 Chrome DevTools 添加功能。它可以添加新的界面面板 与所检查的页面交互、获取有关网络请求的信息等。视图 精选开发者工具扩展程序。开发者工具扩展程序还可以访问另外一组 开发者工具专用扩展程序 API:

开发者工具扩展程序在结构上与任何其他扩展程序一样:可以有后台页面、内容 脚本和其他项。此外,每个开发者工具扩展程序都有一个开发者工具页面,该页面可以访问 向开发者工具 API 集成。

显示开发者工具页面与
       和后台页面显示了背景页面
       与内容脚本通信以及访问扩展程序 API。
       “开发者工具”页面可以访问 DevTools API,例如创建面板。

开发者工具页面

每次打开开发者工具窗口时,系统都会创建扩展程序的开发者工具页面实例。通过 开发者工具页面在开发者工具窗口的生命周期内会一直存在。通过“开发者工具”页面,您可以访问 开发者工具 API 和一组有限的扩展程序 API。具体来说,DevTools 页面可以:

开发者工具页面无法直接使用大多数扩展程序 API。它有权访问 内容脚本有权访问的 extensionruntime API 的两种版本。点赞内容 脚本中,开发者工具页面可以使用消息传递功能与后台页面进行通信。对于 示例,请参阅注入内容脚本

创建开发者工具扩展程序

如需为您的扩展程序创建开发者工具页面,请在扩展程序中添加 devtools_page 字段 清单:

{
  "name": ...
  "version": "1.0",
  "minimum_chrome_version": "10.0",
  "devtools_page": "devtools.html",
  ...
}

对于每个 devtools_page 已打开开发者工具窗口。该页面可能会将其他扩展页面作为面板和边栏添加到 使用 devtools.panels API 的开发者工具窗口。

chrome.devtools.* API 模块仅适用于在开发者工具中加载的页面 窗口。内容脚本和其他扩展程序页面没有这些 API。因此,API 仅在开发者工具窗口的生命周期内可用。

此外,还有一些开发者工具 API 仍处于实验阶段。请参阅 chrome.experimental.* API,了解实验性 API 列表以及有关如何使用它们的指南。

开发者工具界面元素:面板和边栏窗格

除了常见的扩展程序界面元素(如浏览器操作、上下文菜单和弹出式窗口)外, DevTools 扩展程序可以将界面元素添加到开发者工具窗口:

  • 面板是顶级标签页,例如“元素”面板、“来源”面板和“网络”面板。
  • 边栏窗格提供与面板相关的补充界面。样式、计算样式和 “元素”面板上的“事件监听器”窗格就是边栏窗格的示例。(请注意, 边栏窗格的外观可能与图片不符,具体取决于您使用的 Chrome 版本 以及开发者工具窗口停靠的位置)。

显示“Elements”面板和“Styles”边栏窗格的开发者工具窗口。

每个面板都是其自己的 HTML 文件,其中可包含其他资源(JavaScript、CSS、图片等) on)。基本面板的创建过程如下所示:

chrome.devtools.panels.create("My Panel",
    "MyPanelIcon.png",
    "Panel.html",
    function(panel) {
      // code invoked on panel creation
    }
);

在面板或边栏窗格中执行的 JavaScript 可以访问与开发者工具页面相同的 API。

为 Elements 面板创建基本的边栏窗格如下所示:

chrome.devtools.panels.elements.createSidebarPane("My Sidebar",
    function(sidebar) {
        // sidebar initialization code here
        sidebar.setObject({ some_data: "Some data to show" });
});

您可以通过以下几种方式在边栏窗格中显示内容:

  • HTML 内容。调用 setPage 可指定要在窗格中显示的 HTML 页面。
  • JSON 数据。将 JSON 对象传递给 setObject
  • JavaScript 表达式。将表达式传递给 setExpression。开发者工具会评估 表达式,并显示返回值。

对于 setObjectsetExpression,窗格会显示其值,就像在 开发者工具控制台。不过,setExpression 可让您显示 DOM 元素和任意 JavaScript 对象,而 setObject 仅支持 JSON 对象。

在扩展程序组件之间通信

以下部分介绍了在 Google Cloud 不同 的组件。

注入内容脚本

开发者工具页面无法直接调用 tabs.executeScript。如需从 Cloud Storage 中注入内容脚本, 在开发者工具页面中,您必须使用 inspectedWindow.tabId 属性,并向后台页面发送消息。在 后台页面中,调用 tabs.executeScript 来注入脚本。

以下代码段展示了如何使用 executeScript 注入内容脚本。

// DevTools page -- devtools.js
// Create a connection to the background page
var backgroundPageConnection = chrome.runtime.connect({
    name: "devtools-page"
});

backgroundPageConnection.onMessage.addListener(function (message) {
    // Handle responses from the background page, if any
});

// Relay the tab ID to the background page
chrome.runtime.sendMessage({
    tabId: chrome.devtools.inspectedWindow.tabId,
    scriptToInject: "content_script.js"
});

后台网页的代码:

// Background page -- background.js
chrome.runtime.onConnect.addListener(function(devToolsConnection) {
    // assign the listener function to a variable so we can remove it later
    var devToolsListener = function(message, sender, sendResponse) {
        // Inject a content script into the identified tab
        chrome.tabs.executeScript(message.tabId,
            { file: message.scriptToInject });
    }
    // add the listener
    devToolsConnection.onMessage.addListener(devToolsListener);

    devToolsConnection.onDisconnect.addListener(function() {
         devToolsConnection.onMessage.removeListener(devToolsListener);
    });
});

在检查的窗口中评估 JavaScript

您可以使用 inspectedWindow.eval 方法在 所检查的网页。您可以从开发者工具页面、面板或边栏窗格调用 eval 方法。

默认情况下,系统将在页面的主框架上下文中对表达式进行求值。现在,您可以 熟悉开发者工具 命令行 API 功能,例如元素检查 (inspect(elem))、破坏函数 (debug(fn))、复制到剪贴板 (copy()) 等。 inspectedWindow.eval() 使用与在 开发者工具控制台,允许在评估期间访问这些 API。例如,SOAK 将其用于 用于检查元素:

chrome.devtools.inspectedWindow.eval(
  "inspect($$('head script[data-soak=main]')[0])",
  function(result, isException) { }
);

或者,对 inspectedWindow.eval() 使用 useContentScriptContext: true 选项 在与内容脚本相同的上下文中对表达式求值。正在拨打 eval useContentScriptContext: true 不会创建内容脚本上下文,因此您必须加载 上下文脚本,然后再调用 eval(通过调用 executeScript 或通过指定内容 脚本(位于 manifest.json 文件中)。

一旦存在上下文脚本上下文,您就可以使用此选项注入其他内容 脚本。

eval 方法在合适的上下文中使用时功能强大,但使用时危险 不当。如果您不需要访问 tabs.executeScript 方法, 所检查网页的 JavaScript 上下文。如需详细的注意事项和比较这两种方法, 请参阅 inspectedWindow

将所选元素传递给内容脚本

内容脚本无法直接访问当前所选的元素。然而,您创建的任何代码 使用 inspectedWindow.eval 执行时,有权访问开发者工具控制台和命令行 API。 例如,在经过评估的代码中,您可以使用 $0 访问选定的元素。

如需将所选元素传递给内容脚本,请执行以下操作:

  • 在内容脚本中创建一个将所选元素作为参数的方法。
  • 使用 inspectedWindow.evaluseContentScriptContext: true选项。

内容脚本中的代码可能如下所示:

function setSelectedElement(el) {
    // do something with the selected element
}

从 DevTools 页面调用该方法,如下所示:

chrome.devtools.inspectedWindow.eval("setSelectedElement($0)",
    { useContentScriptContext: true });

useContentScriptContext: true 选项指定必须在 与内容脚本相同的上下文,以便它可以访问 setSelectedElement 方法。

获取参考面板的 window

如需从开发者工具面板执行 postMessage,您需要引用其 window 对象。 从 panel.onShown 事件处理脚本中获取面板的 iframe 窗口:

onShown.addListener(function callback)
extensionPanel.onShown.addListener(function (extPanelWindow) {
    extPanelWindow instanceof Window; // true
    extPanelWindow.postMessage( // …
});

从内容脚本到开发者工具页面的消息传递

在开发者工具页面与内容脚本之间传递消息,消息通过后台页面间接进行。

向内容脚本发送消息时,后台网页可以使用 tabs.sendMessage 方法,用于将消息定向到特定标签页中的内容脚本。 如注入内容脚本中所示。

从内容脚本发送消息时,没有现成的方法可用于发送消息 与当前标签页关联的正确开发者工具页面实例。解决方法是 DevTools 页面会与后台页面建立长期连接,并且 后台网页保存标签页 ID 到连接的映射,以便将每一条消息路由到正确的 连接。

// background.js
var connections = {};

chrome.runtime.onConnect.addListener(function (port) {

    var extensionListener = function (message, sender, sendResponse) {

        // The original connection event doesn't include the tab ID of the
        // DevTools page, so we need to send it explicitly.
        if (message.name == "init") {
          connections[message.tabId] = port;
          return;
        }

    // other message handling
    }

    // Listen to messages sent from the DevTools page
    port.onMessage.addListener(extensionListener);

    port.onDisconnect.addListener(function(port) {
        port.onMessage.removeListener(extensionListener);

        var tabs = Object.keys(connections);
        for (var i=0, len=tabs.length; i < len; i++) {
          if (connections[tabs[i]] == port) {
            delete connections[tabs[i]]
            break;
          }
        }
    });
});

// Receive message from content script and relay to the devTools page for the
// current tab
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
    // Messages from content scripts should have sender.tab set
    if (sender.tab) {
      var tabId = sender.tab.id;
      if (tabId in connections) {
        connections[tabId].postMessage(request);
      } else {
        console.log("Tab not found in connection list.");
      }
    } else {
      console.log("sender.tab not defined.");
    }
    return true;
});

DevTools 页面(或面板或边栏窗格)会建立如下连接:

// Create a connection to the background page
var backgroundPageConnection = chrome.runtime.connect({
    name: "panel"
});

backgroundPageConnection.postMessage({
    name: 'init',
    tabId: chrome.devtools.inspectedWindow.tabId
});

从注入的脚本向开发者工具页面发送消息

虽然上述解决方案适用于内容脚本,但代码会直接注入到网页中 (例如,通过附加 <script> 标记或通过 inspectedWindow.eval)需要 不同的策略在这种情况下,runtime.sendMessage 不会将消息传递给 按预期运行后台脚本

一种权宜解决方法是,将注入的脚本与充当 中介。如需将消息传递给内容脚本,您可以使用 window.postMessage API。下例假设为上一部分中的后台脚本:

// injected-script.js

window.postMessage({
  greeting: 'hello there!',
  source: 'my-devtools-extension'
}, '*');
// content-script.js

window.addEventListener('message', function(event) {
  // Only accept messages from the same frame
  if (event.source !== window) {
    return;
  }

  var message = event.data;

  // Only accept messages that we know are ours
  if (typeof message !== 'object' || message === null ||
      !message.source === 'my-devtools-extension') {
    return;
  }

  chrome.runtime.sendMessage(message);
});

您的消息现在将从注入的脚本流向内容脚本,再流到后台 脚本,最后是“开发者工具”页面。

您还可以考虑在此处使用两种不同的消息传递技术

检测开发者工具何时打开和关闭

如果您的扩展程序需要跟踪开发者工具窗口是否已打开,您可以添加 onConnect 监听器,并从开发者工具页面中调用 connect。由于每个标签页 自己的开发者工具窗口打开,您可能会收到多个连接事件。为了跟踪 DevTools 窗口已打开,您需要对连接和断开连接事件进行计数,如下所示:

// background.js
var openCount = 0;
chrome.runtime.onConnect.addListener(function (port) {
    if (port.name == "devtools-page") {
      if (openCount == 0) {
        alert("DevTools window opening.");
      }
      openCount++;

      port.onDisconnect.addListener(function(port) {
          openCount--;
          if (openCount == 0) {
            alert("Last DevTools window closing.");
          }
      });
    }
});

开发者工具页面会创建如下连接:

// devtools.js

// Create a connection to the background page
var backgroundPageConnection = chrome.runtime.connect({
    name: "devtools-page"
});

开发者工具扩展程序示例

浏览这些开发者工具扩展程序示例的源代码:

更多信息

要了解扩展程序可以使用的标准 API,请参阅 chrome.*API网站 API

向我们提供反馈!您的意见和建议有助于我们改进 API。

示例

您可以在示例中找到使用开发者工具 API 的示例。