Estoy aprendiendo cómo crear extensiones de Chrome. Acabo de comenzar a desarrollar uno para ver los eventos de YouTube. Quiero usarlo con YouTube Flash Player (más adelante intentaré hacerlo compatible con HTML5).
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!");
El problema es que la consola me da el "¡Iniciado!" , pero no hay "¡Estado cambiado!" cuando reproduzco / detengo videos de YouTube.
Cuando este código se coloca en la consola, funcionó. ¿Qué estoy haciendo mal?
player.addEventListener("onStateChange", state);
https://
ohttp://
, estowww.youtube.com/*
no le permitiría empacar la extensión y arrojaría un error de separador de esquema faltanteRespuestas:
Los scripts de contenido se ejecutan en un entorno de "mundo aislado" . Tienes que inyectar tu
state()
método en la página misma.Cuando desee utilizar una de las
chrome.*
API en el script, debe implementar un controlador de eventos especial, como se describe en esta respuesta: Extensión de Chrome: recuperación del mensaje original de Gmail .De lo contrario, si no tiene que usar
chrome.*
API, le recomiendo que inyecte todo su código JS en la página agregando una<script>
etiqueta:Tabla de contenido
Método 1: inyectar otro archivo
Este es el método más fácil / mejor cuando tienes mucho código. Incluya su código JS real en un archivo dentro de su extensión, digamos
script.js
. Luego, deje que su script de contenido sea el siguiente (explicado aquí: Google Chome "Acceso directo a la aplicación" Javascript personalizado ):Nota: Si usa este método, el
script.js
archivo inyectado debe agregarse a la"web_accessible_resources"
sección ( ejemplo ). Si no lo hace, Chrome se negará a cargar su script y mostrará el siguiente error en la consola:Método 2: inyectar código incrustado
Este método es útil cuando desea ejecutar rápidamente un pequeño fragmento de código. (Consulte también: ¿Cómo deshabilitar las teclas de acceso rápido de Facebook con la extensión de Chrome? ).
Nota: los literales de plantilla solo son compatibles con Chrome 41 y versiones posteriores. Si desea que la extensión funcione en Chrome 40-, use:
Método 2b: uso de una función
Para una gran porción de código, no es factible citar la cadena. En lugar de usar una matriz, se puede usar una función y stringificar:
Este método funciona, porque el
+
operador en cadenas y una función convierte todos los objetos en una cadena. Si tiene la intención de usar el código más de una vez, es aconsejable crear una función para evitar la repetición del código. Una implementación podría verse así:Nota: ¡Dado que la función está serializada, el alcance original y todas las propiedades enlazadas se pierden!
Método 3: usar un evento en línea
A veces, desea ejecutar un código inmediatamente, por ejemplo, ejecutar un código antes de
<head>
crear el elemento. Esto se puede hacer insertando una<script>
etiqueta contextContent
(ver método 2 / 2b).Una alternativa, pero no recomendada, es usar eventos en línea. No se recomienda porque si la página define una política de seguridad de contenido que prohíbe los scripts en línea, entonces los escuchas de eventos en línea están bloqueados. Los scripts en línea inyectados por la extensión, por otro lado, aún se ejecutan. Si aún desea utilizar eventos en línea, así es como:
Nota: Este método supone que no hay otros escuchas de eventos globales que manejen el
reset
evento. Si lo hay, también puede elegir uno de los otros eventos globales. Simplemente abra la consola de JavaScript (F12), escribadocument.documentElement.on
y seleccione los eventos disponibles.Valores dinámicos en el código inyectado
Ocasionalmente, debe pasar una variable arbitraria a la función inyectada. Por ejemplo:
Para inyectar este código, debe pasar las variables como argumentos a la función anónima. ¡Asegúrese de implementarlo correctamente! Lo siguiente no funcionará:
La solución es usar
JSON.stringify
antes de pasar el argumento. Ejemplo:Si tiene muchas variables, vale la pena usar
JSON.stringify
una vez, para mejorar la legibilidad, de la siguiente manera:fuente
script-src
directiva que excluye el origen de la extensión, el método 2 se puede bloquear mediante el uso de un CSP que excluye la "línea insegura".script.parentNode.removeChild(script);
. Mi razón para hacerlo es porque me gusta limpiar mi desorden. Cuando se inserta una secuencia de comandos en línea en el documento, se ejecuta inmediatamente y la<script>
etiqueta se puede eliminar de forma segura.location.href = "javascript: alert('yeah')";
en cualquier parte de su secuencia de comandos de contenido. Es más fácil para fragmentos cortos de código, y también puede acceder a los objetos JS de la página.javascript:
. El código que abarca varias líneas podría no funcionar como se esperaba. Una línea-comment (//
) truncará el resto, por lo que este se producirá un error:location.href = 'javascript:// Do something <newline> alert(0);';
. Esto puede evitarse asegurándose de que utiliza comentarios de varias líneas. Otra cosa a tener cuidado es que el resultado de la expresión debe ser nulo.javascript:window.x = 'some variable';
hará que el documento se descargue y se reemplace con la frase 'alguna variable'. Si se usa correctamente, es una alternativa atractiva a<script>
.La única cosa
desaparecidooculto de la excelente respuesta de Rob W está cómo comunicarse entre el guión de la página inyectada y el guión de contenido.En el lado receptor (ya sea su secuencia de comandos de contenido o la secuencia de comandos de la página inyectada) agregue un detector de eventos:
En el lado del iniciador (secuencia de comandos de contenido o secuencia de comandos de página inyectada) envíe el evento:
Notas:
En Firefox, para enviar un objeto (es decir, no un valor primitivo) desde el script de contenido al contexto de la página, debe clonarlo explícitamente en el destino utilizando
cloneInto
(una función incorporada), de lo contrario fallará con un error de violación de seguridad .fuente
CustomEvent
constructor reemplaza ladocument.createEvent
API en desuso .CustomEvent
constructor. Experimenté 2 contratiempos muy confusos: 1. simplemente poner comillas simples alrededor de 'detalle' hizo que el valor fuera desconcertantenull
cuando fue recibido por el oyente de mi Script de Contenido. 2. Más importante aún, por alguna razón tuve que hacerloJSON.parse(JSON.stringify(myData))
o de lo contrario también se convertiríanull
. Dado esto, me parece que la siguiente afirmación del desarrollador de Chromium, que el algoritmo de "clon estructurado" se usa automáticamente, no es cierto. bugs.chromium.org/p/chromium/issues/detail?id=260378#c18También me enfrenté al problema de ordenar los scripts cargados, que se resolvió mediante la carga secuencial de scripts. La carga se basa en la respuesta de Rob W .
El ejemplo de uso sería:
En realidad, soy un poco nuevo en JS, así que siéntete libre de enviarme un ping a las mejores formas.
fuente
formulaImageUrl
ocodeImageUrl
, está destruyendo efectivamente la funcionalidad de la página. Si desea pasar una variable a la página web, sugiero adjuntar los datos al elemento del script (e.g. script.dataset.formulaImageUrl = formulaImageUrl;
) y usar, por ejemplo,(function() { var dataset = document.currentScript.dataset; alert(dataset.formulaImageUrl;) })();
en el script para acceder a los datos.dataset
?document.currentScript
solo apunta a la etiqueta del script mientras se está ejecutando. Si alguna vez desea acceder a la etiqueta del script y / o sus atributos / propiedades (por ejemplodataset
), debe almacenarla en una variable. Necesitamos un IIFE para obtener un cierre para almacenar esta variable sin contaminar el espacio de nombres global.return;
).en la secuencia de comandos de contenido, agrego una etiqueta de secuencia de comandos a la cabeza que une un controlador 'onmessage', dentro del controlador que uso, eval para ejecutar el código. En el script de contenido de la cabina, también uso el controlador onmessage, por lo que obtengo comunicación bidireccional. Documentos de Chrome
pmListener.js es un oyente de URL de mensaje de publicación
De esta manera, puedo tener comunicación de 2 vías entre CS a Real Dom. Es muy útil, por ejemplo, si necesita escuchar eventos de webcoket o cualquier evento o variable en memoria.
fuente
Puede usar una función de utilidad que he creado con el fin de ejecutar código en el contexto de la página y recuperar el valor devuelto.
Esto se hace serializando una función en una cadena e inyectándola en la página web.
La utilidad está disponible aquí en GitHub .
Ejemplos de uso -
fuente
Si desea inyectar una función pura, en lugar de texto, puede usar este método:
Y puede pasar parámetros (desafortunadamente no se pueden clasificar en cadena objetos y matrices) a las funciones. Agréguelo a los baretheses, así:
fuente