Ich lerne, wie man Chrome-Erweiterungen erstellt. Ich habe gerade angefangen, eine zu entwickeln, um YouTube-Events zu verfolgen. Ich möchte es mit dem YouTube Flash Player verwenden (später werde ich versuchen, es mit HTML5 kompatibel zu machen).
manifest.json:
{
"name": "MyExtension",
"version": "1.0",
"description": "Gotta catch Youtube events!",
"permissions": ["tabs", "http://*/*"],
"content_scripts" : [{
"matches" : [ "www.youtube.com/*"],
"js" : ["myScript.js"]
}]
}
myScript.js:
function state() { console.log("State Changed!"); }
var player = document.getElementById("movie_player");
player.addEventListener("onStateChange", "state");
console.log("Started!");
Das Problem ist, dass die Konsole mir das "Started!" , aber es gibt kein "State Changed!" wenn ich YouTube-Videos abspiele / pausiere.
Wenn dieser Code in die Konsole eingefügt wird, hat es funktioniert. Was mache ich falsch?
player.addEventListener("onStateChange", state);
https://
http://
www.youtube.com/*
Antworten:
Inhaltsskripte werden in einer Umgebung mit "isolierter Welt" ausgeführt . Sie müssen Ihre
state()
Methode in die Seite selbst einfügen.Wenn Sie eine der
chrome.*
APIs im Skript verwenden möchten , müssen Sie einen speziellen Ereignishandler implementieren, wie in dieser Antwort beschrieben: Chrome-Erweiterung - Abrufen der ursprünglichen Nachricht von Google Mail .Wenn Sie keine
chrome.*
APIs verwenden müssen, empfehle ich dringend, den gesamten JS-Code durch Hinzufügen eines<script>
Tags in die Seite einzufügen:Inhaltsverzeichnis
Methode 1: Injizieren Sie eine andere Datei
Dies ist die einfachste / beste Methode, wenn Sie viel Code haben. Fügen Sie beispielsweise Ihren tatsächlichen JS-Code in eine Datei in Ihrer Erweiterung ein
script.js
. Lassen Sie dann Ihr Inhaltsskript wie folgt aussehen (hier erklärt: Google Chome "Application Shortcut" Custom Javascript ):Hinweis: Wenn Sie diese Methode verwenden, muss die injizierte
script.js
Datei zum"web_accessible_resources"
Abschnitt hinzugefügt werden ( Beispiel ). Wenn Sie dies nicht tun, wird Chrome verweigert Ihr Skript und zeigt den folgenden Fehler in der Konsole zu laden:Methode 2: Injizieren Sie eingebetteten Code
Diese Methode ist nützlich, wenn Sie schnell einen kleinen Code ausführen möchten. (Siehe auch: So deaktivieren Sie Facebook-Hotkeys mit der Chrome-Erweiterung? )
Hinweis: Vorlagenliterale werden nur in Chrome 41 und höher unterstützt. Wenn die Erweiterung in Chrome 40- funktionieren soll, verwenden Sie:
Methode 2b: Verwenden einer Funktion
Für einen großen Teil des Codes ist das Zitieren der Zeichenfolge nicht möglich. Anstatt ein Array zu verwenden, kann eine Funktion verwendet und stringifiziert werden:
Diese Methode funktioniert, da der
+
Operator für Zeichenfolgen und eine Funktion alle Objekte in eine Zeichenfolge konvertiert. Wenn Sie den Code mehrmals verwenden möchten, sollten Sie eine Funktion erstellen, um eine Wiederholung des Codes zu vermeiden. Eine Implementierung könnte folgendermaßen aussehen:Hinweis: Da die Funktion serialisiert ist, gehen der ursprüngliche Bereich und alle gebundenen Eigenschaften verloren!
Methode 3: Verwenden eines Inline-Ereignisses
Manchmal möchten Sie sofort Code ausführen, z. B. um Code auszuführen, bevor das
<head>
Element erstellt wird. Dies kann durch Einfügen eines<script>
Tags mit erfolgentextContent
(siehe Methode 2 / 2b).Eine Alternative, die jedoch nicht empfohlen wird, ist die Verwendung von Inline-Ereignissen. Es wird nicht empfohlen, da Inline-Ereignis-Listener blockiert werden, wenn die Seite eine Inhaltssicherheitsrichtlinie definiert, die Inline-Skripts verbietet. Von der Erweiterung eingefügte Inline-Skripte werden dagegen weiterhin ausgeführt. Wenn Sie weiterhin Inline-Ereignisse verwenden möchten, gehen Sie wie folgt vor:
Hinweis: Bei dieser Methode wird davon ausgegangen, dass keine anderen globalen Ereignis-Listener für das
reset
Ereignis vorhanden sind. Wenn ja, können Sie auch eines der anderen globalen Ereignisse auswählen. Öffnen Sie einfach die JavaScript-Konsole (F12), geben Siedocument.documentElement.on
die verfügbaren Ereignisse ein und wählen Sie sie aus.Dynamische Werte im injizierten Code
Gelegentlich müssen Sie eine beliebige Variable an die injizierte Funktion übergeben. Zum Beispiel:
Um diesen Code einzufügen, müssen Sie die Variablen als Argumente an die anonyme Funktion übergeben. Stellen Sie sicher, dass Sie es richtig implementieren! Folgendes wird nicht funktionieren:
Die Lösung besteht darin,
JSON.stringify
vor dem Übergeben des Arguments zu verwenden. Beispiel:Wenn Sie viele Variablen haben, lohnt es sich, diese
JSON.stringify
einmal zu verwenden , um die Lesbarkeit zu verbessern:quelle
script-src
Direktive blockiert werden , die den Ursprung der Erweiterung ausschließt. Methode 2 kann mithilfe eines CSP blockiert werden, der "unsafe-inline" ausschließt.script.parentNode.removeChild(script);
. Mein Grund dafür ist, dass ich mein Chaos gerne aufräumte. Wenn ein Inline-Skript in das Dokument eingefügt wird, wird es sofort ausgeführt und das<script>
Tag kann sicher entfernt werden.location.href = "javascript: alert('yeah')";
beliebige Stelle in Ihrem Inhaltsskript. Es ist einfacher für kurze Codeausschnitte und kann auch auf die JS-Objekte der Seite zugreifen.javascript:
. Code, der sich über mehrere Zeilen erstreckt, funktioniert möglicherweise nicht wie erwartet. Ein Zeilenkommentar (//
) schneidet den Rest ab, sodass dies fehlschlägt :location.href = 'javascript:// Do something <newline> alert(0);';
. Dies kann umgangen werden, indem sichergestellt wird, dass Sie mehrzeilige Kommentare verwenden. Eine andere Sache, auf die Sie achten sollten, ist, dass das Ergebnis des Ausdrucks nichtig sein sollte.javascript:window.x = 'some variable';
Das Dokument wird entladen und durch den Ausdruck "eine Variable" ersetzt. Bei richtiger Anwendung ist es in der Tat eine attraktive Alternative zu<script>
.Die einzige Sache
fehltVor Rob Ws hervorragender Antwort verbirgt sich die Kommunikation zwischen dem injizierten Seitenskript und dem Inhaltsskript.Fügen Sie auf der Empfangsseite (entweder Ihr Inhaltsskript oder das Skript für die injizierte Seite) einen Ereignis-Listener hinzu:
Auf der Initiatorseite (Inhaltsskript oder injiziertes Seitenskript) senden Sie das Ereignis:
Anmerkungen:
Um in Firefox ein Objekt (dh keinen primitiven Wert) aus dem Inhaltsskript an den Seitenkontext zu senden, müssen Sie es explizit mit
cloneInto
(einer integrierten Funktion) in das Ziel klonen , da es sonst mit einem Sicherheitsverletzungsfehler fehlschlägt .quelle
CustomEvent
Konstruktor ersetzt die veraltetedocument.createEvent
API.CustomEvent
Konstruktor übergeben. Ich habe zwei sehr verwirrende Rückschläge erlebt: 1. Einfach einfache Anführungszeichen um 'Detail' zu setzen, machte den Wert verwirrend,null
wenn er vom Hörer meines Inhaltsskripts empfangen wurde. 2. Noch wichtiger ist, aus irgendeinem Grund musste ichJSON.parse(JSON.stringify(myData))
oder es würde auch werdennull
. Angesichts dessen scheint mir die Behauptung des folgenden Chromium-Entwicklers, dass der Algorithmus "strukturierter Klon" automatisch verwendet wird, nicht wahr zu sein. bugs.chromium.org/p/chromium/issues/detail?id=260378#c18Ich hatte auch das Problem der Bestellung geladener Skripte, das durch sequentielles Laden von Skripten gelöst wurde. Die Beladung basiert auf Rob W Antwort .
Das Anwendungsbeispiel wäre:
Eigentlich bin ich ein bisschen neu bei JS, also zögern Sie nicht, mich auf die besseren Wege zu schicken.
quelle
formulaImageUrl
oder verwendetcodeImageUrl
, wird die Funktionalität der Seite effektiv zerstört. Wenn Sie eine Variable an die Webseite übergeben möchten, empfehle ich, die Daten an das Skriptelement (e.g. script.dataset.formulaImageUrl = formulaImageUrl;
) anzuhängen und z. B.(function() { var dataset = document.currentScript.dataset; alert(dataset.formulaImageUrl;) })();
im Skript zu verwenden, um auf die Daten zuzugreifen.dataset
?document.currentScript
zeigt nur auf das Skript-Tag, während es ausgeführt wird. Wenn Sie jemals auf das Skript-Tag und / oder seine Attribute / Eigenschaften (z. B.dataset
) zugreifen möchten, müssen Sie es in einer Variablen speichern. Wir benötigen ein IIFE, um einen Abschluss zum Speichern dieser Variablen zu erhalten, ohne den globalen Namespace zu verschmutzen.return;
).Im Inhaltsskript füge ich dem Kopf ein Skript-Tag hinzu, das einen 'onmessage'-Handler innerhalb des von mir verwendeten Handlers bindet, um Code auszuführen. Im Standinhaltsskript verwende ich auch den onmessage-Handler, sodass ich eine bidirektionale Kommunikation bekomme. Chrome Docs
pmListener.js ist ein URL-Listener für Post-Nachrichten
Auf diese Weise kann ich eine bidirektionale Kommunikation zwischen CS und Real Dom herstellen. Dies ist zum Beispiel sehr nützlich, wenn Sie Webscoket-Ereignisse oder beliebige Variablen oder Ereignisse im Speicher abhören müssen.
quelle
Sie können eine von mir erstellte Dienstprogrammfunktion verwenden, um Code im Seitenkontext auszuführen und den zurückgegebenen Wert zurückzugewinnen.
Dazu wird eine Funktion in eine Zeichenfolge serialisiert und in die Webseite eingefügt.
Das Dienstprogramm ist hier auf GitHub verfügbar .
Anwendungsbeispiele -
quelle
Wenn Sie anstelle von Text eine reine Funktion einfügen möchten, können Sie folgende Methode verwenden:
Und Sie können Parameter an die Funktionen übergeben (leider können keine Objekte und Arrays stringifiziert werden). Fügen Sie es wie folgt in die Barethesen ein:
quelle