sintaxis - script type= text/javascript src=
Comunicarse entre scripts en el contexto de fondo(script de fondo, acción del navegador, acción de página, página de opciones, etc.) (1)
Comunicación con una página en el contexto de fondo
Las páginas que están abiertas en el contexto de fondo incluyen:
- páginas de fondo / scripts ( MDN )
-
páginas de eventos
(Firefox no admite páginas de eventos. Todas las páginas de
background
manifest.json permanecen cargadas en todo momento ). - ventanas emergentes de acción del navegador ( MDN )
- ventanas emergentes de acción de página ( MDN )
- páginas de opciones ( MDN1 , MDN2 ) (en una ventana emergente, una pestaña o ventana)
- páginas de acción de la barra lateral (NDN) (no disponible en Chrome)
- Cualquier contenido HTML contenido dentro de su extensión que se abre normalmente en una pestaña, ventana (por ejemplo, un panel) o marco. 1
El uso de
tabs.sendMessage()
(
MDN
)
no enviará un mensaje a ninguno de ellos.
runtime.sendMessage()
usar
runtime.sendMessage()
(
MDN
)
para enviarles un mensaje.
El alcance de cualquiera de ellos, excepto las páginas de fondo y las páginas de eventos, solo existe cuando se muestra.
Obviamente, no puede comunicarse con el código cuando no existe.
Cuando existe el alcance, puede comunicarse con cualquiera de ellos utilizando:
-
Directamente
Desde el contexto de fondo, puede cambiar directamente las variables, o llamar a funciones, en otra página que también está en el contexto de fondo (es decir, no en los scripts de contenido), después de haber obtenido una referencia a su alcance global, su Window , usandoextension.getViews()
( MDN ) ,extension.getBackgroundPage()
( MDN ) u otro método ( MDN ) .
Por ejemplo, puede llamar a una función creada con lafunction myFunction
en la página de la primera vista devuelta usando algo como:winViews = chrome.extension.getViews(); winViews[0].myFunction(foo);
Debe tenerse en cuenta que en su devolución de llamada de
tabs.create()
( MDN ) owindows.create()
( MDN ) la vista para la pestaña o ventana recién abierta probablemente todavía no exista. Deberá utilizar alguna metodología para esperar a que exista la vista. 2 Consulte a continuación las formas recomendadas de comunicarse con pestañas o ventanas recién abiertas.La manipulación directa de valores en el alcance de la otra página le permite comunicar cualquier tipo de datos que desee.
-
Mensajería
Reciba mensajes usandochrome.runtime.onMessage
( MDN ) , 3 que fueron enviados con runtime.sendMessage() ( MDN ) . Cada vez que reciba un mensaje en un escucharuntime.onMessage
, habrá una funciónsendResponse
provista como el tercer argumento que le permite responder directamente al mensaje. Si el remitente original no ha proporcionado una devolución de llamada para recibir dicha respuesta en su llamada achrome.runtime.sendMessage()
, entonces la respuesta se pierde. Si usa Promesas (por ejemplo,browser.runtime.sendMessage()
en Firefox), la respuesta se pasa como argumento cuando se cumple la Promesa. Si desea enviar la respuesta de forma asincrónica, deberáreturn true;
de su oyenteruntime.onMessage
.Puertos
También puede conectar puertos, usandochrome.runtime.connect()
( MDN ) ychrome.runtime.onConnect
( MDN ) para mensajes a largo plazo.Use
chrome.tabs.sendMessage()
para enviar a los scripts de contenido
Si desea enviar desde el contexto de fondo (por ejemplo, secuencia de comandos de fondo o ventana emergente) a una secuencia de comandos de contenido, usaríachrome.tabs.sendMessage()
/chrome.runtime.onMessage
, o conectar los puertos mediantechrome.tabs.connect()
( MDN ) /chrome.runtime.onConnect
.Solo datos serializables con JSON
Al usar la mensajería, solo puede pasar datos que sean serializables con JSON.Todos los scripts reciben mensajes en segundo plano, excepto el remitente
Los mensajes enviados al contexto de fondo son recibidos por todos los scripts en el contexto de fondo que han registrado un oyente, excepto el script que lo envió. 3 No hay forma de especificar que solo sea recibido por un script específico. Por lo tanto, si tiene múltiples destinatarios potenciales, deberá crear una forma de asegurarse de que el mensaje recibido esté destinado a ese script. Las formas de hacerlo generalmente se basan en propiedades específicas existentes en el mensaje (por ejemplo, usar una propiedad dedestination
orecipient
para indicar qué script debe recibirlo, o definir que algúntype
de mensajes son siempre para un destinatario u otro), o para diferenciar según elsender
( MDN ) suministrado al manejador de mensajes (por ejemplo, si los mensajes de un remitente siempre son solo para un destinatario específico). No hay una forma establecida de hacer esto, debe elegir / crear una forma de hacerlo para usar en su extensión.Para una discusión más detallada de este problema, consulte: Todos reciben mensajes destinados a un script en el contexto de fondo
-
Datos en un área de almacenamiento
Almacene datos en un StorageArea ( MDN ) y StorageArea notificaciones del cambio en otros scripts utilizandochrome.storage.onChanged
( MDN ) . El eventostorage.onChanged
se puede escuchar tanto en el contexto de fondo como en los scripts de contenido.Solo puede almacenar datos que son serializables con JSON en un StorageArea.
El mejor método para usar en cualquier situación particular dependerá de lo que desee comunicar (tipo de datos, cambio de estado, etc.) y de qué parte o partes de su extensión desea comunicar desde y hacia . Por ejemplo, si desea comunicar información que no es serializable en JSON, deberá hacerlo directamente (es decir, no enviar mensajes o usar un StorageArea). Puede usar múltiples métodos en la misma extensión.
Más sobre ventanas emergentes
Ninguna de las ventanas emergentes (p. Ej., Acción del navegador o acción de la página) está directamente asociada con la pestaña activa. No existe el concepto de una instancia compartida o separada por pestaña. Sin embargo, el usuario puede abrir una ventana emergente en cada ventana de Chrome. Si hay más de una ventana emergente abierta (un máximo de una por ventana de Chrome), entonces cada una está en una instancia separada (ámbito separado; tiene su propia ventana), pero están en el mismo contexto. Cuando una ventana emergente es realmente visible, existe en el contexto de fondo.
Solo hay una acción de página o ventana emergente de acción de navegador abierta a la vez por ventana de Chrome.
El archivo HTML que se abrirá será el que haya sido definido para la pestaña activa de la ventana actual y
abierto por el usuario haciendo clic en el botón de acción de la página / navegador
.
Se le puede asignar un documento HTML diferente para diferentes pestañas usando
chrome.browserAction.setPopup()
(
MDN
)
o
chrome.pageAction.setPopup()
(
MDN
)
y especificando un
tabId
.
La ventana emergente puede / será destruida por múltiples razones, pero definitivamente cuando otra pestaña se convierte en la pestaña activa en la ventana en la que está abierta la ventana emergente.
Sin embargo, cualquier método de comunicación utilizado solo se comunicará con los que están abiertos actualmente, no con los que no están abiertos. Si las ventanas emergentes están abiertas para más de una ventana de Chrome a la vez, entonces son instancias separadas, con su propio alcance (es decir, su propia ventana). Puede pensar en esto como tener la misma página web abierta en más de una pestaña.
Si tiene un script de fondo, el contexto del script de fondo es persistente en toda la instancia de Chrome. Si no tiene un script de fondo, el contexto puede crearse cuando sea necesario (por ejemplo, se muestra una ventana emergente) y destruirse cuando ya no sea necesario.
chrome.tabs.sendMessage()
no puede comunicarse
con
ventanas emergentes
Como se mencionó anteriormente, incluso si la ventana emergente existiera, existirá en el contexto de fondo.
Llamar a
chrome.tabs.sendMessage()
envía un mensaje a los
scripts de contenido inyectados en una pestaña / marco
, no al contexto de fondo.
Por lo tanto, no enviará un mensaje a un script sin contenido como una ventana emergente.
Botón de acción: activar / desactivar (acción del navegador) frente a mostrar / ocultar (acción de la página)
Llamar a
chrome.pageAction.show()
(
MDN
)
solo hace que se muestre el
botón de
acción de página.
No hace que se muestre ninguna
ventana emergente
asociada.
Si la página emergente / opciones / otra página no se muestra realmente (no solo el botón), entonces su alcance no existe.
Cuando no existe, obviamente no puede recibir ningún mensaje.
En lugar de la capacidad de acción de la página para
chrome.pageAction.show()
(
MDN
)
u
hide()
(
MDN
)
el botón, las acciones del navegador pueden
enable()
(
MDN
)
o
disable()
(
MDN
)
el botón.
Abrir mediante programación una pestaña o ventana con HTML desde su extensión
Puede usar
tabs.create()
(
MDN
)
o
windows.create()
(
MDN
)
para abrir una pestaña o ventana que contenga una página HTML desde su extensión.
Sin embargo, la devolución de llamada para ambas llamadas API se ejecuta antes de que exista el DOM de la página y, por lo tanto, antes de cualquier JavaScript asociado con la página existente.
Por lo tanto, no puede acceder inmediatamente al DOM creado por el contenido de esa página, ni interactuar con el JavaScript de la página.
Muy específicamente: no se han agregado escuchas
runtime.onMessage()
por lo que la página recién abierta no
runtime.onMessage()
ningún mensaje enviado en ese momento.
Las mejores formas de resolver este problema son:
-
Tenga los datos disponibles para que la nueva página de apertura pueda obtener los datos cuando esté listo.
Haga esto antes de comenzar el proceso de abrir la página:
-
Si la fuente está en el contexto de fondo: almacene los datos en una variable disponible para el alcance global de la página de envío.
La página de apertura puede usar
chrome.extension.getBackgroundPage()
para leer los datos directamente. -
Si el origen de los datos está en el contexto de fondo o en un script de contenido: coloque los datos en
storage.local
( MDN ) . La página de apertura puede leerla cuando se ejecuta JavaScript. Por ejemplo, podría usar una clave llamadamessageToNewExtensionPage
.
-
Si la fuente está en el contexto de fondo: almacene los datos en una variable disponible para el alcance global de la página de envío.
La página de apertura puede usar
-
Si está utilizando
runtime.sendMessage()
, entonces inicie la transferencia de los datos desde su página recién abierta enviando un mensaje desde el código de esa página al origen de los datos (usandoruntime.sendMessage()
otabs.sendMessage()
para fuentes de script de contenido) solicitando los datos. El script con los datos puede enviar los datos de vuelta usando la funciónsendResponse
(MDN) proporcionada porruntime.onMessage()
. - Espere para interactuar con la página recién abierta hasta después de que al menos el DOM esté disponible, si no hasta después de que se haya ejecutado el JavaScript para la página. Si bien es posible hacer esto sin que la página recién abierta proporcione una notificación específica de que está en funcionamiento, hacerlo es más complejo y solo útil en algunos casos específicos (por ejemplo, si desea hacer algo antes de que se ejecute JavaScript en la nueva página) . 2
Referencias adicionales
Cromo
Firefox
- Con algunas excepciones menores: por ejemplo, usar un script de contenido para insertar contenido en el contexto de la página.
-
Existen varios métodos que puede usar. La mejor manera dependerá exactamente de lo que esté haciendo (por ejemplo, cuándo necesita acceder a la vista con respecto al código que se ejecuta en la vista). Un método simple sería simplemente sondear a la espera de que exista la vista. El siguiente código hace eso para abrir una ventana:
chrome.windows.create({url: myUrl},function(win){ //Poll for the view of the window ID. Poll every 50ms for a // maximum of 20 times (1 second). Then do a second set of polling to // accommodate slower machines. Testing on a single moderately fast machine // indicated the view was available after, at most, the second 50ms delay. waitForWindowId(win.id,50,20,actOnViewFound,do2ndWaitForWinId); }); function waitForWindowId(id,delay,maxTries,foundCallback,notFoundCallback) { if(maxTries--<=0){ if(typeof notFoundCallback === ''function''){ notFoundCallback(id,foundCallback); } return; } let views = chrome.extension.getViews({windowId:id}); if(views.length > 0){ if(typeof foundCallback === ''function''){ foundCallback(views[0]); } } else { setTimeout(waitForWindowId,delay,id,delay,maxTries,foundCallback ,notFoundCallback); } } function do2ndWaitForWinId(winId,foundCallback){ //Poll for the view of the window ID. Poll every 500ms for max 40 times (20s). waitForWindowId(winId,500,40,foundCallback,windowViewNotFound); } function windowViewNotFound(winId,foundCallback){ //Did not find the view for the window. Do what you want here. // Currently fail quietly. } function actOnViewFound(view){ //What you desire to happen with the view, when it exists. }
-
De MDN
:
En las versiones de Firefox anteriores a la versión 51, se llamará al oyente runtime.onMessage para los mensajes enviados desde el mismo script (por ejemplo, los mensajes enviados por el script de fondo también serán recibidos por el script de fondo). En esas versiones de Firefox, si llama incondicionalmente a runtime.sendMessage () desde un oyente runtime.onMessage, configurará un bucle infinito que maximizará la CPU y bloqueará Firefox. Si necesita llamar a runtime.sendMessage () desde un runtime.onMessage, deberá verificar la propiedad sender.url para verificar que no está enviando un mensaje en respuesta a un mensaje enviado desde el mismo script. Este error se resolvió a partir de Firefox 51.
Me encuentro con un problema al enviar datos desde mi script de fondo al script para mi
pageAction
.
Mi script de contenido agrega un
<iframe />
y el JavaScript en el
<iframe />
está recibiendo los datos de mi script de fondo, pero parece que no se recupera en mi
pageAction
.
En mi script de fondo tengo algo como:
chrome.tabs.sendMessage(senderTab.tab.id,
{
foo:bar
});
donde
senderTab.tab.id
es el "remitente" en
onMessage
Listener en mi script de fondo.
En el JavaScript cargado por el
<iframe />
inyectado por mi script de contenido tengo algo como:
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log("received in iframe:", request);
}
});
El
<iframe />
recibe el mensaje exactamente como se esperaba.
Puse el mismo JavaScript en mi
page_action.js
, pero no recibe ningún dato del script de fondo.
PageAction se activa con
chrome.pageAction.show(senderTab.tab.id);
antes de llamar a
chrome.tabs.sendMessage(senderTab.tab.id ...
¿La página HTML adjunta a mi pageAction no forma parte de la misma pestaña?
Dado que este
tabId
me permitió activar / "mostrar" el icono, creo que el oyente en JavaScript para la página Acción también debería recibir de
chrome.tabs.sendMessage(senderTab.tab.id ...
En mi script de contenido, uso lo siguiente para enviar datos al script de fondo:
chrome.runtime.sendMessage({
foo: bar
});
Cuando el script de contenido envía el mensaje anterior, el JavaScript de pageAction lo está recogiendo.
¿Cómo obtengo el script de fondo para enviar correctamente los datos a mi pageAction? No quiero tener una solicitud / encuesta de pageAction, en cambio quiero que pageAction solo escuche y reciba. Por ejemplo, si se muestra el HTML de PageAction, debería poder actualizarse en tiempo real a medida que la página de fondo realiza cambios.