Entwicklertools erweitern

Überblick

Mit einer DevTools-Erweiterung können die Chrome-Entwicklertools um zusätzliche Funktionen erweitert werden. Sie kann neue UI-Steuerfelder und Seitenleisten hinzufügen, mit der untersuchten Seite interagieren, Informationen zu Netzwerkanfragen abrufen und vieles mehr. Sehen Sie sich Angesagte Entwicklertools-Erweiterungen an. Entwicklertools-Erweiterungen haben Zugriff auf eine zusätzliche Reihe von Entwicklertools-spezifischen Erweiterungs-APIs:

Eine DevTools-Erweiterung ist wie jede andere Erweiterung strukturiert: Sie kann eine Hintergrundseite, Inhaltsskripte und andere Elemente enthalten. Außerdem gibt es für jede DevTools-Erweiterung eine Entwicklertools-Seite mit Zugriff auf die DevTools APIs.

Architekturdiagramm, das die Kommunikation der Entwicklertools-Seite mit dem geprüften Fenster und der Hintergrundseite zeigt. Die Hintergrundseite kommuniziert mit den Inhaltsskripten und greift auf Erweiterungs-APIs zu.
       Über die Seite „Entwicklertools“ hast du Zugriff auf die Entwicklertools-APIs und kannst z. B. Bereiche erstellen.

Seite „Entwicklertools“

Jedes Mal, wenn ein Entwicklertools-Fenster geöffnet wird, wird eine Instanz der Entwicklertools-Seite der Erweiterung erstellt. Die Seite „Entwicklertools“ ist für die gesamte Dauer des Fensters verfügbar. Über die Seite „Entwicklertools“ hast du Zugriff auf die Entwicklertools-APIs und eine begrenzte Anzahl von Erweiterungs-APIs. Konkret bietet die Seite „Entwicklertools“ folgende Möglichkeiten:

  • Mit den devtools.panels APIs können Sie Bereiche erstellen und mit ihnen interagieren.
  • Rufen Sie mit den devtools.inspectedWindow APIs Informationen zum geprüften Fenster ab und werten Sie den Code im geprüften Fenster aus.
  • Rufen Sie Informationen zu Netzwerkanfragen mit den devtools.network APIs ab.

Die meisten Erweiterungs-APIs können über die Entwicklertools-Seite nicht direkt genutzt werden. Es hat Zugriff auf die gleiche Teilmenge der extension und runtime APIs, auf die ein Inhaltsskript Zugriff hat. Wie ein Inhaltsskript kann eine Entwicklertools-Seite über die Nachrichtenweitergabe mit der Hintergrundseite kommunizieren. Ein Beispiel finden Sie unter Content-Skript einfügen.

Entwicklertools-Erweiterung erstellen

Fügen Sie dem Erweiterungsmanifest das Feld devtools_page hinzu, um eine Entwicklertools-Seite für Ihre Erweiterung zu erstellen:

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

Für jedes geöffnete Entwicklertools-Fenster wird eine Instanz von devtools_page erstellt, die im Manifest der Erweiterung angegeben ist. Die Seite kann dem Fenster der Entwicklertools mithilfe der devtools.panels API andere Erweiterungsseiten als Bereiche und Seitenleisten hinzufügen.

Die chrome.devtools.* API-Module sind nur für die Seiten verfügbar, die im Fenster der Entwicklertools geladen werden. Content-Skripts und andere Erweiterungsseiten haben diese APIs nicht. Daher sind die APIs nur während der gesamten Lebensdauer des Entwicklertools-Fensters verfügbar.

Es gibt auch einige Entwicklertools-APIs, die sich noch in der Testphase befinden. Weitere Informationen finden Sie unter chrome.experimental.* APIs finden Sie eine Liste der experimentellen APIs und Anleitungen zu ihrer Verwendung.

UI-Elemente der Entwicklertools: Steuerfelder und Seitenleistenbereiche

Zusätzlich zu den üblichen UI-Elementen der Erweiterung, wie Browseraktionen, Kontextmenüs und Pop-ups, kann eine DevTools-Erweiterung UI-Elemente zum DevTools-Fenster hinzufügen:

  • Ein Steuerfeld ist ein Tab auf oberster Ebene wie die Steuerfelder "Elemente", "Quellen" und "Netzwerk".
  • Ein Seitenleistenbereich enthält eine zusätzliche UI für einen Bereich. Die Bereiche „Stile“, „Berechnete Stile“ und „Ereignis-Listener“ im Steuerfeld „Elemente“ sind Beispiele für Seitenleistenbereiche. Beachte, dass die Darstellung der Seitenleistenbereiche möglicherweise nicht mit dem Bild übereinstimmt, je nachdem, welche Chrome-Version du verwendest und wo das Entwicklertools-Fenster angedockt ist.

Fenster „Entwicklertools“ mit dem Steuerfeld „Elemente“ und der Seitenleiste „Stile“.

Jeder Bereich ist eine eigene HTML-Datei, die andere Ressourcen (JavaScript, CSS, Bilder usw.) enthalten kann. Das Erstellen eines einfachen Steuerfelds sieht so aus:

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

JavaScript, das in einem Steuerfeld oder einer Seitenleiste ausgeführt wird, hat Zugriff auf dieselben APIs wie die Seite der Entwicklertools.

Das Erstellen eines einfachen Seitenleistenbereichs für das Steuerfeld „Elemente“ sieht so aus:

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

Es gibt mehrere Möglichkeiten, Inhalte in einem Seitenleistenfenster anzuzeigen:

  • HTML-Inhalt. Rufen Sie setPage auf, um eine HTML-Seite anzugeben, die im Bereich angezeigt werden soll.
  • JSON-Daten. Übergeben Sie ein JSON-Objekt an setObject.
  • JavaScript-Ausdruck. Übergeben Sie einen Ausdruck an setExpression. Die Entwicklertools werten den Ausdruck im Kontext der geprüften Seite aus und zeigen den Rückgabewert an.

Sowohl für setObject als auch für setExpression wird im Bereich der Wert so angezeigt, wie er in der Entwicklertools-Konsole erscheinen würde. Mit setExpression können Sie jedoch DOM-Elemente und beliebige JavaScript-Objekte anzeigen lassen, während setObject nur JSON-Objekte unterstützt.

Kommunikation zwischen Erweiterungskomponenten

In den folgenden Abschnitten werden einige typische Szenarien für die Kommunikation zwischen den verschiedenen Komponenten einer Entwicklertools-Erweiterung beschrieben.

Inhaltsskript einfügen

tabs.executeScript kann von der Entwicklertools-Seite nicht direkt aufgerufen werden. Zum Einfügen eines Inhaltsskripts von der Entwicklertools-Seite müssen Sie die ID des Tabs des geprüften Fensters mithilfe der inspectedWindow.tabId-Eigenschaft abrufen und eine Nachricht an die Hintergrundseite senden. Rufen Sie auf der Hintergrundseite tabs.executeScript auf, um das Skript einzufügen.

Die folgenden Code-Snippets zeigen, wie ein Inhaltsskript mit executeScript injiziert wird.

// 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"
});

Code für die Hintergrundseite:

// 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 im geprüften Fenster auswerten

Mit der Methode inspectedWindow.eval können Sie JavaScript-Code im Kontext der geprüften Seite ausführen. Du kannst die eval-Methode über eine Entwicklertools-Seite, einen Bereich oder einen Seitenleistenbereich aufrufen.

Standardmäßig wird der Ausdruck im Kontext des Hauptframes der Seite ausgewertet. Jetzt sind Sie vielleicht mit den Funktionen der Commandline API der Entwicklertools vertraut, wie z. B. Elementprüfung (inspect(elem)), Funktionsstörungen (debug(fn)), Kopieren in die Zwischenablage (copy()) und mehr. inspectedWindow.eval() verwendet denselben Kontext und dieselben Optionen für die Skriptausführung wie den Code, der in der Entwicklertools-Konsole eingegeben wurde. Dadurch wird der Zugriff auf diese APIs innerhalb der Auswertung ermöglicht. In SOAK wird es beispielsweise zur Prüfung eines Elements verwendet:

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

Alternativ können Sie die Option useContentScriptContext: true für inspectedWindow.eval() verwenden, um den Ausdruck im selben Kontext wie die Inhaltsskripts auszuwerten. Durch den Aufruf von eval mit useContentScriptContext: true wird kein Content-Skript-Kontext erstellt. Daher müssen Sie ein Kontextskript vor dem Aufruf von eval laden, entweder durch Aufrufen von executeScript oder durch Angeben eines Inhaltsskripts in der Datei manifest.json.

Sobald der Kontextskriptkontext vorhanden ist, können Sie mit dieser Option zusätzliche Inhaltsskripte einfügen.

Die Methode eval ist leistungsstark, wenn sie im richtigen Kontext eingesetzt wird, und bei unsachgemäßer Verwendung gefährlich. Verwenden Sie die Methode tabs.executeScript, wenn Sie keinen Zugriff auf den JavaScript-Kontext der geprüften Seite benötigen. Ausführliche Hinweise und einen Vergleich der beiden Methoden finden Sie unter inspectedWindow.

Ausgewähltes Element an ein Inhaltsskript übergeben

Das Inhaltsskript hat keinen direkten Zugriff auf das aktuell ausgewählte Element. Jeder Code, den Sie mit inspectedWindow.eval ausführen, hat jedoch Zugriff auf die Entwicklertools-Konsole und die Befehlszeilen-APIs. Im ausgewerteten Code können Sie beispielsweise $0 verwenden, um auf das ausgewählte Element zuzugreifen.

So übergeben Sie das ausgewählte Element an ein Inhaltsskript:

  • Erstellen Sie im Content-Skript eine Methode, die das ausgewählte Element als Argument verwendet.
  • Rufen Sie die Methode auf der Seite „Entwicklertools“ mit inspectedWindow.eval und der Option useContentScriptContext: true auf.

Der Code in Ihrem Inhaltsskript könnte in etwa wie folgt aussehen:

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

Rufen Sie die Methode auf der Seite Entwicklertools wie folgt auf:

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

Die Option useContentScriptContext: true gibt an, dass der Ausdruck im selben Kontext wie die Inhaltsskripts ausgewertet werden muss, damit er auf die Methode setSelectedElement zugreifen kann.

window eines Referenzbereichs abrufen

Um postMessage von einem Entwicklertools-Bereich aus zu postMessage, benötigst du einen Verweis auf das zugehörige window-Objekt. Rufen Sie das iFrame-Fenster eines Bereichs über den Event-Handler panel.onShown ab:

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

Nachrichten von Inhaltsskripts zur Seite „Entwicklertools“ senden

Die Kommunikation zwischen der Entwicklertools-Seite und den Inhaltsskripten erfolgt indirekt über die Hintergrundseite.

Beim Senden einer Nachricht an ein Inhaltsskript kann die Hintergrundseite die Methode tabs.sendMessage verwenden, die eine Nachricht an die Inhaltsskripts in einem bestimmten Tab weiterleitet, wie unter Inhaltsskript einfügen gezeigt.

Beim Senden einer Nachricht von einem Inhaltsskript gibt es keine vordefinierte Methode, um eine Nachricht an die richtige Instanz der Entwicklertools-Seite zu senden, die dem aktuellen Tab zugeordnet ist. Als Behelfslösung können Sie die Seite mit den Entwicklertools eine langlebige Verbindung zur Hintergrundseite herstellen und die Hintergrundseite eine Zuordnung von Tab-IDs zu Verbindungen erstellen lassen, damit jede Nachricht an die richtige Verbindung weitergeleitet werden kann.

// 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;
});

Die Seite der Entwicklertools (oder der Bereich oder die Seitenleiste) stellt die Verbindung so her:

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

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

Nachrichten von eingefügten Skripts an die Seite „Entwicklertools“

Die obige Lösung funktioniert zwar für Inhaltsskripte. Code, der direkt in die Seite eingeschleust wird (z. B. durch Anfügen eines <script>-Tags oder über inspectedWindow.eval), erfordert jedoch eine andere Strategie. In diesem Kontext gibt runtime.sendMessage nicht wie erwartet Nachrichten an das Hintergrundskript weiter.

Als Behelfslösung können Sie das eingefügte Skript mit einem Inhaltsskript kombinieren, das als Vermittler dient. Mit der window.postMessage API können Sie Nachrichten an das Inhaltsskript übergeben. Hier ein Beispiel mit dem Hintergrundskript aus dem vorherigen Abschnitt:

// 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);
});

Ihre Nachricht fließt jetzt vom eingefügten Skript über das Inhaltsskript zum Hintergrundskript und schließlich zur Seite der Entwicklertools.

Sie können auch zwei alternative Techniken zur Nachrichtenweitergabe in Betracht ziehen.

Erkennen, wann die Entwicklertools geöffnet und geschlossen werden

Wenn deine Erweiterung erfassen muss, ob das Entwicklertools-Fenster geöffnet ist, kannst du der Hintergrundseite einen onConnect-Listener hinzufügen und über die Entwicklertools-Seite connect aufrufen. Da auf jedem Tab ein eigenes Entwicklertools-Fenster geöffnet sein kann, erhältst du möglicherweise mehrere Verbindungsereignisse. Wenn Sie wissen möchten, ob ein Entwicklertools-Fenster geöffnet ist, müssen Sie die Verbindungsereignisse wie unten dargestellt zählen:

// 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.");
          }
      });
    }
});

Die Seite der Entwicklertools erstellt eine Verbindung wie diese:

// devtools.js

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

Entwicklertools-Erweiterungsbeispiele

Sehen Sie sich den Quellcode dieser Beispiele für DevTools-Erweiterungen an:

Weitere Informationen

Informationen zu den Standard-APIs, die Erweiterungen verwenden können, finden Sie unter chrome.* APIs und Web-APIs.

Wir freuen uns über dein Feedback. Ihre Kommentare und Vorschläge helfen uns, die APIs zu verbessern.

Beispiele

Beispiele, in denen DevTools APIs verwendet werden, finden Sie unter Beispiele.