Reinyección del script de contenido de la extensión de Chrome después de la actualización o instalación

Resuelto Tom Ashworth asked hace 12 años • 7 respuestas

Después de instalar o actualizar la extensión de Chrome en la que estoy trabajando, los scripts de contenido (especificados en el manifiesto) no se reinyectan, por lo que se requiere una actualización de la página para que la extensión funcione. ¿Hay alguna manera de forzar que los scripts se vuelvan a inyectar?

Creo que podría inyectarlos nuevamente mediante programación eliminándolos del manifiesto y luego manejando qué páginas inyectar en la página de fondo, pero esta no es una buena solución.

No quiero actualizar automáticamente las pestañas del usuario porque eso podría perder algunos de sus datos. Safari actualiza automáticamente todas las páginas cuando instalas o actualizas una extensión.

Tom Ashworth avatar Jun 12 '12 17:06 Tom Ashworth
Aceptado

Hay una manera de permitir que una extensión de script de contenido pesado continúe funcionando después de una actualización y de hacer que funcione inmediatamente después de la instalación.

Instalar/actualizar

El método de instalación consiste simplemente en recorrer todas las pestañas de todas las ventanas e inyectar algunos scripts mediante programación en pestañas con URL coincidentes.

ManifiestoV3

manifiesto.json:

"background": {"service_worker": "background.js"},
"permissions": ["scripting"],
"host_permissions": ["<all_urls>"],

Estos host_permissions deben ser los mismos que los del script de contenido matches.

fondo.js:

chrome.runtime.onInstalled.addListener(async () => {
  for (const cs of chrome.runtime.getManifest().content_scripts) {
    for (const tab of await chrome.tabs.query({url: cs.matches})) {
      chrome.scripting.executeScript({
        files: cs.js,
        target: {tabId: tab.id, allFrames: cs.all_frames},
        injectImmediately: cs.run_at === 'document_start',
        // world: cs.world, // uncomment if you use it in manifest.json in Chrome 111+
      });
    }
  }
});

Este es un ejemplo simplificado que no maneja marcos. Puede utilizar la API getAllFrames y hacer coincidir las URL usted mismo; consulte la documentación para conocer los patrones coincidentes .

ManifiestoV2

Obviamente, debes hacerlo en una página de fondo o en un script de página de evento declarado en manifest.json:

"background": {
    "scripts": ["background.js"]
},

fondo.js:

// Add a `manifest` property to the `chrome` object.
chrome.manifest = chrome.runtime.getManifest();

var injectIntoTab = function (tab) {
    // You could iterate through the content scripts here
    var scripts = chrome.manifest.content_scripts[0].js;
    var i = 0, s = scripts.length;
    for( ; i < s; i++ ) {
        chrome.tabs.executeScript(tab.id, {
            file: scripts[i]
        });
    }
}

// Get all windows
chrome.windows.getAll({
    populate: true
}, function (windows) {
    var i = 0, w = windows.length, currentWindow;
    for( ; i < w; i++ ) {
        currentWindow = windows[i];
        var j = 0, t = currentWindow.tabs.length, currentTab;
        for( ; j < t; j++ ) {
            currentTab = currentWindow.tabs[j];
            // Skip chrome:// and https:// pages
            if( ! currentTab.url.match(/(chrome|https):\/\//gi) ) {
                injectIntoTab(currentTab);
            }
        }
    }
});

Curiosidades históricas

En la versión antigua de Chrome 26 y versiones anteriores, los scripts de contenido podían restaurar la conexión con el script en segundo plano. Se solucionó http://crbug.com/168263 en 2013. Puede ver un ejemplo de este truco en las revisiones anteriores de esta respuesta.

Tom Ashworth avatar Jul 22 '2012 08:07 Tom Ashworth

La única forma de forzar la inyección de un script de contenido sin actualizar la página es mediante inyección programática.

Puede obtener todas las pestañas e inyectar código en ellas utilizando la API de pestañas de Chrome. Por ejemplo, puede almacenar una versión del manifiesto en el almacenamiento local y comprobar cada vez si la versión del manifiesto es antigua (en la página de fondo). De ser así, puede obtener todas las pestañas activas e inyectar su código mediante programación, o cualquier otra solución que le permita Asegúrese de que la extensión esté actualizada.

Obtenga todas las pestañas usando:
chrome.tabs.query

e inyecta tu código en todas las páginas
chrome.tabs.executeScript(tabId, {file: "content_script.js"});

saroyanm avatar Jun 20 '2012 18:06 saroyanm