Resumen y solución de problemas para la extensión de Manifest V3: Accediendo a funciones locales
En este artículo se aborda el problema que se presenta al desarrollar una extensión de Chrome bajo el modelo de Manifest V3, donde se requiere interactuar con una función JavaScript de una página web externa (no controlada por el desarrollador). A continuación, se analizan las dos estrategias intentadas y se propone una solución.
Contexto del Problema
El objetivo es ejecutar una función local getValue()
de una página externa y enviar su resultado a un script de fondo (service worker) de la extensión. Sin embargo, las limitaciones de seguridad y el contexto de ejecución entre scripts de la extensión y contenido causan complicaciones.
Estrategias Intentadas
-
Ejecutar
getValue()
encontent_scripts
:- Se logra invocar la función local usando
"world": "MAIN"
pero se enfrenta al errorExtension context invalidated
al intentar usarchrome.runtime.sendMessage()
.
- Se logra invocar la función local usando
- Enviar un mensaje desde
content_scripts
abackground.js
:- Se puede enviar un mensaje correctamente, pero se produce un
ReferenceError
porquegetValue()
no está accesible en el contexto del script de contenido.
- Se puede enviar un mensaje correctamente, pero se produce un
Código Proporcionado
- manifest.json:
{
"manifest_version": 3,
"name": "ExtName",
"version": "0.0.1",
"content_scripts": [
{
"matches": ["*://url/*"],
"js": ["main.js"]
}
],
"host_permissions": [
"*://*/*"
],
"background": {
"service_worker": "background.js"
}
}
- main.js:
var intervalID = window.setInterval(checkValue, 1000);
async function checkValue() {
let value = getValue();
if (value) {
const response = await chrome.runtime.sendMessage({status: value});
console.log(response.text);
}
};
- background.js:
function handleMessage(request, sender, sendResponse) {
console.log(request.status);
sendResponse({ text: "Received!" });
}
chrome.runtime.onMessage.addListener(handleMessage);
- Script de página externa:
function getValue() {
return "value";
}
Solución Propuesta
Para poder acceder tanto a la función getValue()
en la página como enviar correctamente los mensajes al service worker, se puede modificar el enfoque utilizando una combinación de inyección y manejo de mensajes:
-
Inyección de un script en la página que capture el valor y lo envíe a la extensión.
En lugar de intentar acceder a
getValue()
directamente desdemain.js
, se puede crear un script que ejecute esta función y envíe el resultado a través dechrome.runtime.sendMessage()
.Modifiquemos
main.js
para inyectar un script que llame agetValue()
y envíe el resultado a la extensión:
var intervalID = window.setInterval(async () => {
const value = await new Promise((resolve) => {
chrome.scripting.executeScript({
target: { tabId: /* ID de la pestaña actual */ },
func: getValue
}, (injectionResults) => {
resolve(injectionResults[0].result);
});
});
if (value) {
const response = await chrome.runtime.sendMessage({status: value});
console.log(response.text);
}
}, 1000);
Conclusión
El acceso a funciones locales en páginas web externas desde una extensión de Chrome puede ser complicado debido a las restricciones del modelo de seguridad. Sin embargo, al inyectar scripts que interactúan con el DOM de la página, se puede lograr la comunicación necesaria entre la extensión y el contenido de la página. Esta solución asegura que se cumplan las reglas de seguridad mientras se logra la funcionalidad requerida.