Rozszerzanie narzędzi deweloperskich

Omówienie

Rozszerzenie do Narzędzi deweloperskich dodaje nowe funkcje do Narzędzi deweloperskich w Chrome. Może dodawać nowe panele UI paski boczne, wchodzij w interakcję z kontrolowaną stroną, uzyskuj informacje o żądaniach sieciowych itd. Wyświetl polecanych rozszerzeń do Narzędzi deweloperskich. Rozszerzenia w Narzędziach deweloperskich mają dostęp do dodatkowego zestawu Interfejsy API rozszerzeń typowych dla Narzędzi deweloperskich:

Rozszerzenie do Narzędzi deweloperskich ma strukturę taką jak każde inne rozszerzenie: może mieć stronę w tle, treść skrypty i inne elementy. Oprócz tego każde rozszerzenie Narzędzi deweloperskich ma stronę Narzędzia deweloperskie, na której można znaleźć do interfejsów API Narzędzi deweloperskich.

Schemat architektury przedstawiający stronę narzędzi deweloperskich komunikującą się z
       sprawdzone okno i stronę w tle. Wyświetla się strona w tle
       komunikacją ze skryptami treści i dostępem do interfejsów API rozszerzeń.
       Strona Narzędzi deweloperskich ma dostęp do interfejsów API Narzędzi deweloperskich, na przykład służących do tworzenia paneli.

Strona Narzędzia deweloperskie

Przy każdym otwarciu okna Narzędzi deweloperskich tworzona jest instancja strony Narzędzia deweloperskiego rozszerzenia. Strona Narzędzia deweloperskie istnieje przez cały okres ważności okna Narzędzi deweloperskich. Strona Narzędzia deweloperskie ma dostęp do Interfejsy API Narzędzi deweloperskich i ograniczony zestaw interfejsów API rozszerzeń. W szczególności strona Narzędzia deweloperskie może:

  • Twórz panele i wchodź z nimi w interakcje za pomocą interfejsów API devtools.panels.
  • Uzyskaj informacje o kontrolowanym oknie i oceń w nim kod za pomocą interfejsów API devtools.inspectedWindow.
  • Uzyskuj informacje o żądaniach sieciowych za pomocą interfejsów API devtools.network.

Strona Narzędzi deweloperskich nie może bezpośrednio korzystać z większości interfejsów API rozszerzeń. Ma dostęp do tego samego podzbioru interfejsów API extension i runtime, do których ma dostęp skrypt treści. Polubienie treści skrypt, strona Narzędzi deweloperskich może komunikować się ze stroną w tle za pomocą przekazywania wiadomości. Dla przykład: Injecting a Content Script (Wstawianie skryptu treści).

Tworzenie rozszerzenia w Narzędziach deweloperskich

Aby utworzyć stronę w Narzędziach deweloperskich dla rozszerzenia, dodaj w rozszerzeniu pole devtools_page plik manifestu:

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

Dla każdej instancji tworzone jest wystąpienie devtools_page określone w pliku manifestu rozszerzenia. Otwarto okno Narzędzi deweloperskich. Strona może dodać inne strony rozszerzeń w formie paneli i pasków bocznych do Okno narzędzi deweloperskich za pomocą interfejsu API devtools.panels.

Moduły interfejsu API chrome.devtools.* są dostępne tylko dla stron wczytywanych przy użyciu Narzędzi deweloperskich okno. Skrypty treści i inne strony rozszerzeń nie mają tych interfejsów API. Interfejsy API są więc dostępne tylko przez cały okres ważności okna Narzędzi deweloperskich.

Istnieją też interfejsy API Narzędzi deweloperskich, które wciąż są w fazie eksperymentalnej. Więcej informacji znajdziesz na stronie chrome.experimental*. interfejsów API.

Elementy interfejsu Narzędzi deweloperskich: panele i panele paska bocznego

Oprócz standardowych elementów interfejsu rozszerzeń, takich jak działania przeglądarki, menu kontekstowe i wyskakujące okienka, Elementy interfejsu można dodawać do okna Narzędzi deweloperskich za pomocą rozszerzenia Narzędzia deweloperskie:

  • Panel to karta najwyższego poziomu, czyli panele Elementy, Źródła i Sieć.
  • Panel paska bocznego zawiera dodatkowy interfejs związany z panelem. Style, style wynikowe Panele detektorów zdarzeń w panelu Elementy to przykłady paneli na pasku bocznym. (Pamiętaj, że wygląd paneli na pasku bocznym może nie odpowiadać obrazowi (w zależności od używanej wersji Chrome) i gdzie znajduje się okno Narzędzia deweloperskie).

Okno Narzędzi deweloperskich z panelem Elementy i panelem paska bocznego Style.

Każdy panel jest osobnym plikiem HTML, który może zawierać inne zasoby (JavaScript, CSS, obrazy itd. wł.). Tworzenie panelu podstawowego wygląda tak:

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

Skrypt JavaScript wykonywany w panelu lub panelu na pasku bocznym ma dostęp do tych samych interfejsów API co strona Narzędzi deweloperskich.

Tworzenie podstawowego panelu paska bocznego dla panelu Elementy wygląda tak:

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

Istnieje kilka sposobów wyświetlania zawartości w panelu paska bocznego:

  • Treść HTML. Wywołaj setPage, aby określić stronę HTML, która ma być wyświetlana w panelu.
  • Dane JSON. Przekaż obiekt JSON do setObject.
  • Wyrażenie JavaScript. Przekazuj wyrażenie do setExpression. Narzędzia deweloperskie oceniają w kontekście badanej strony i wyświetla zwracaną wartość.

Zarówno w przypadku setObject, jak i setExpression panel wyświetla wartość, która jest widoczna w polu Konsola Narzędzi deweloperskich. setExpression umożliwia jednak wyświetlanie elementów DOM i dowolnego JavaScriptu , a setObject obsługuje tylko obiekty JSON.

Komunikacja między komponentami rozszerzenia

W poniższych sekcjach opisano kilka typowych scenariuszy komunikacji między komponentów rozszerzenia do Narzędzi deweloperskich.

Wstrzyknięcie skryptu treści

Strona Narzędzi deweloperskich nie może bezpośrednio wywoływać narzędzia tabs.executeScript. Aby wstrzyknąć skrypt treści z na stronie Narzędzia deweloperskie, musisz pobrać identyfikator sprawdzanej karty okna za pomocą inspectedWindow.tabId i wyślij wiadomość na stronę w tle. Z poziomu stronę w tle, wywołaj tabs.executeScript, by wprowadzić skrypt.

Poniżej znajdziesz fragmenty kodu, które pokazują, jak wstawić skrypt treści za pomocą 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"
});

Kod strony w tle:

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

Ocena kodu JavaScript w sprawdzanym oknie

Możesz użyć metody inspectedWindow.eval do wykonywania kodu JavaScript w kontekście sprawdzonej strony. Metodę eval możesz wywołać z poziomu strony, panelu lub panelu Narzędzi deweloperskich.

Domyślnie wyrażenie jest sprawdzane w kontekście głównej ramki strony. Teraz możesz zapoznaj się z funkcjami interfejsu commandline APIdostępnymi w Narzędziach deweloperskich, takimi jak kontrola elementów (inspect(elem)), przerwa w działaniu funkcji (debug(fn)), kopiowanie do schowka (copy()) i inne działania. inspectedWindow.eval() używa tego samego kontekstu wykonania skryptu i tych samych opcji co kod wpisany na Konsola Narzędzi deweloperskich, która umożliwia dostęp do tych interfejsów API w ramach oceny. Na przykład funkcja SOAK go używa :

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

Możesz też użyć opcji useContentScriptContext: true dla inspectedWindow.eval(), aby oceniać wyrażenie w tym samym kontekście co skrypty treści. Dzwonię do: eval z: useContentScriptContext: true nie tworzy kontekstu skryptu treści, więc musisz wczytać skrypt kontekstowy przed wywołaniem funkcji eval, wywołując funkcję executeScript lub określając treść w pliku manifest.json.

Gdy kontekst skryptu będzie już istniał, możesz użyć tej opcji, by wstawić dodatkową treść skryptów.

Metoda eval jest skuteczna, gdy jest używana we właściwym kontekście, i niebezpieczna, gdy jest używana niewłaściwie. Użyj metody tabs.executeScript, jeśli nie potrzebujesz dostępu do Kontekst JavaScript sprawdzanej strony. Szczegółowe ostrzeżenia i porównanie 2 metod znajdziesz w artykule zobacz inspectedWindow.

Przekazywanie wybranego elementu do skryptu treści

Skrypt treści nie ma bezpośredniego dostępu do obecnie wybranego elementu. Jednak każdy kod do uruchamiania za pomocą inspectedWindow.eval ma dostęp do konsoli Narzędzi deweloperskich i interfejsów API wiersza poleceń. Na przykład w ocenionym kodzie możesz użyć polecenia $0, aby uzyskać dostęp do wybranego elementu.

Aby przekazać wybrany element do skryptu treści:

  • Utwórz w skrypcie treści metodę, która jako argument przybiera wybrany element.
  • Wywołaj metodę ze strony Narzędzia deweloperskie za pomocą polecenia inspectedWindow.eval z parametrem useContentScriptContext: true.

Kod w skrypcie treści może wyglądać mniej więcej tak:

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

Wywołaj tę metodę ze strony Narzędzia deweloperskie w ten sposób:

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

Opcja useContentScriptContext: true określa, że wyrażenie musi być oceniane w taki sam kontekst jak skrypty treści, więc ma dostęp do metody setSelectedElement.

Pobieram window panelu referencyjnego

Aby wykonać działanie postMessage z poziomu panelu narzędzi deweloperskich, potrzebujesz odniesienia do jego obiektu window. Pobierz okno iframe panelu z modułu obsługi zdarzeń panel.onShown:

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

Przesyłanie wiadomości ze skryptów treści na stronę Narzędzia deweloperskie

Komunikacja między stroną Narzędzi deweloperskich a skryptami treści jest pośrednia przez stronę w tle.

Podczas wysyłania wiadomości do skryptu treści strona w tle może używać parametru tabs.sendMessage, która przekierowuje wiadomość do skryptów treści na danej karcie, jak widać w sekcji Wstawianie skryptu treści.

W przypadku wysyłania wiadomości ze skryptu treści nie ma gotowej metody dostarczenia wiadomości. do odpowiedniego wystąpienia strony Narzędzi deweloperskich powiązanych z bieżącą kartą. Aby obejść ten problem, skonfiguruj opcję stronę w Narzędziach deweloperskich. strona w tle przechowuje mapę identyfikatorów kart połączeń, umożliwiając kierowanie każdej wiadomości do właściwego połączenia.

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

Strona Narzędzia deweloperskie (albo panel lub panel boczny) nawiązuje połączenie w ten sposób:

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

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

Komunikaty z wstrzykniętych skryptów na stronę Narzędzia deweloperskie

Powyższe rozwiązanie sprawdza się w przypadku skryptów treści, jednak kod wstawiany bezpośrednio na stronie (np. przez dołączenie tagu <script> lub za pomocą funkcji inspectedWindow.eval) wymaga tagu inną strategią. W tym kontekście runtime.sendMessage nie przekazuje wiadomości do skrypt działający w tle, zgodnie z oczekiwaniami.

Aby obejść ten problem, możesz połączyć wstawiony skrypt ze skryptem treści, który pełni funkcję pośrednikiem. Aby przekazywać wiadomości do skryptu treści, możesz użyć funkcji window.postMessage API. Oto przykład przy założeniu skryptu działającego w tle z poprzedniej sekcji:

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

Wiadomość będzie teraz przekazywana ze wstrzykiwanego skryptu do skryptu treści w tle skrypt i stronę narzędzi deweloperskich.

Możesz też rozważyć 2 alternatywne metody przekazywania wiadomości.

Wykrywanie otwierania i zamykania Narzędzi deweloperskich

Jeśli rozszerzenie ma monitorować, czy okno Narzędzi deweloperskich jest otwarte, możesz dodać rozszerzenie onConnect. detektora strony w tle i wywołać connect na stronie Narzędzi deweloperskich. Ponieważ każda karta może ma własne okno Narzędzi deweloperskich, możesz otrzymywać wiele zdarzeń połączenia. Aby śledzić, czy Okno Narzędzi deweloperskich jest otwarte. Musisz policzyć zdarzenia połączenia i rozłączenia, jak pokazano poniżej:

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

Strona Narzędzia deweloperskie tworzy takie połączenie:

// devtools.js

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

Przykłady rozszerzeń do Narzędzi deweloperskich

Przejrzyj źródła tych przykładowych rozszerzeń do Narzędzi deweloperskich:

Więcej informacji

Informacje na temat standardowych interfejsów API, z których mogą korzystać rozszerzenia, znajdziesz w sekcji chrome*. Interfejsy API i sieć Interfejsy API.

Prześlij nam opinię Twoje uwagi i sugestie pomogą nam ulepszyć interfejsy API.

Przykłady

Przykłady użycia interfejsów API Narzędzi deweloperskich znajdziesz w przykładach.