Contextos e methods de comunicação entre a ação do navegador, os scripts de segundo plano e os scripts de conteúdo das extensões do Chrome?

Acho que as extensões do chrome são em geral bem simples e muito poderosas, mas uma coisa que sempre me confunde é tentar se comunicar entre os vários scripts nos quais o código pode ser executado. Há o código que é executado quando referenciado na página “default_popup” da ação do navegador. , o código na propriedade “scripts” de “background” e os scripts de conteúdo.

Em que contexto os scripts dessas categorias são executados e como cada um pode se comunicar com os outros?

Três contextos diferentes

Como desenvolvedor de extensões do Chrome, você pode distinguir três ambientes diferentes.

  1. Código de extensão , executado no processo da sua extensão do Chrome
    • Página de fundo / evento
    • Ação do navegador / pop-up de ação da página
    • A página dentro de uma barra de informações .
    • Guias cujo quadro de nível superior é um documento da sua extensão, como a página de opções .
  2. Scripts de conteúdo , em execução no processo da guia.
  3. Código de não extensão em execução no processo da guia ( injetado por scripts de conteúdo ).

Observe que em páginas sem extensão costumava ser tratado como caso 2 (scripts de conteúdo), porque o quadro foi carregado em um processo de guia sem privilégios. Como os iframes fora do processo foram lançados para extensões no Chrome 56, essas páginas são tratadas pelo processo de extensão e, portanto, podem usar o mesmo conjunto completo de APIs de extensão. Essa mudança de comportamento (permitindo que frameworks de extensão usem APIs de extensões privilegiadas) é intencional .

Acessando o object da window dentro de um processo de extensão

Como todo código de extensão é executado no mesmo processo, eles podem acessar o outro object de window global. Esse recurso não é bem conhecido, mas permite manipular objects JavaScript e DOM diretamente no mesmo processo de extensão. Geralmente, é melhor não usar esse método, mas use as APIs de transmissão de mensagens .

 // To access the `window` of a background page, use var bgWindowObject = chrome.extension.getBackgroundPage() ; // To access the `window` of an event or background page, use: chrome.runtime.getBackgroundPage (function(bgWindowObject) { // Do something with `bgWindow` if you want }); // To access the `window` of the badge's popup page (only if it's open!!!), use var popupWindowObject = chrome.extension.getViews({type:'popup'})[0] ; // To access the `window` of the options page (called /options.html), use var allWindowObjects = chrome.extension.getViews({type:'tab'}) ; var popupWindowObjects = allWindowObjects.filter(function(windowObject) { return windowObject.location.pathname == '/options.html'; }); // Example: Get the `window` object of the first options page: var popupWindowObject = popupWindowObjects[0]; 

Para manter esta seção curta, limitei o exemplo de código intencionalmente a uma demonstração de access a outros objects de window global. Você poderia usar esses methods para definir um método global, definir uma variável global, chamar uma function global etc.
… desde que a página esteja aberta. Alguém pensou que a janela do pop-up está sempre disponível. Isso não é verdade, quando o popup é fechado, o object global é descartado!

Comunicação por passagem de mensagem

Um canal de mensagens sempre tem duas extremidades: o remetente e um receptor.
Para se tornar um receptor, ligue um ouvinte de evento usando o método chrome.runtime.onMessage.addListener . Isso pode ser feito por código de extensão e scripts de conteúdo.

Para passar mensagens dentro da extensão, use chrome.runtime.sendMessage . Se você quiser enviar uma mensagem para outra guia, chame chrome.tabs.sendMessage . A guia de destino é especificada incluindo um inteiro ( tabId ) como seu primeiro argumento. Observe que uma página de plano de fundo só pode enviar uma mensagem para uma guia. Para alcançar todas as abas, o método deve ser chamado para cada aba. Por exemplo:

 chrome.tabs.query ({}, function(tabs) { for (var i=0; i 

Os scripts de conteúdo só podem chamar chrome.runtime.sendMessage para enviar uma mensagem ao código de extensão. Se você quiser enviar uma mensagem de um script de conteúdo para outro script de conteúdo, será necessária uma página de plano de fundo / evento, que recebe uma mensagem e a envia para a guia desejada. Veja esta resposta para um exemplo.

Os methods sendMessage aceitam uma function opcional, que é recebida como um terceiro argumento para o evento onMessage .

 chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) { if (message === 'message') sendResponse('the response'); }); chrome.runtime.sendMessage('message', function(response) { console('sendResponse was called with: ' + response); }); 

O exemplo anterior mostra um comportamento óbvio. As coisas ficam mais complicadas quando você deseja enviar uma resposta de forma assíncrona, por exemplo, se você deseja executar uma solicitação AJAX para buscar alguns dados. Quando a function onMessage retorna sem ter chamado o sendResponse , o Chrome invocará imediatamente o sendResponse . Como sendResponse pode ser chamado apenas uma vez, você receberá o seguinte erro:

Não foi possível enviar a resposta: O listener chrome.runtime.onMessage deve retornar true se você quiser enviar uma resposta depois que o listener retornar (a mensagem foi enviada por extensão EXTENSION ID AQUI )

Faça como o erro sugere, adicione return true; dentro do seu ouvinte de evento onMessage:

 chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) { setTimeout(function() { // Example: asynchronous invocation of sendResponse sendResponse('async response'); }, 200); return true; }); 

Eu expliquei a aplicação prática da simples mensagem única que passa nesta seção. Se você quiser saber mais sobre canais de mensagens de longa duração ou mensagens entre ramais, leia o tutorial na documentação oficial .

A API de transmissão de mensagens sofreu várias alterações de nome. Tenha isso em mente se você ler exemplos antigos. A história e as notas de compatibilidade podem ser encontradas aqui .

Comunicação entre um script de conteúdo e a página

É possível se comunicar com a página. A Apsillers criou uma excelente resposta que explica como configurar um canal de comunicação entre uma página (sem extensão) e um script de conteúdo. Leia sua resposta em um site pode invocar uma extensão do navegador? .

A vantagem do método do apsiller sobre o método da documentação é que um evento customizado é usado. A documentação usa window.postMessage para enviar uma mensagem à página, mas isso pode causar conflito com páginas mal codificadas que não esperam os events de mensagem.

A documentação do Google tem tudo, mas é difícil reunir todas as informações. Existem dois tipos principais de scripts:
1. Os scripts de plano de fundo têm access total às APIs do Google Chrome, mas não podem interagir com a página da Web de destino.
2. Scripts de conteúdo podem interagir entre si e com o DOM da página da Web (mas não com seus scripts, dos quais ele é isolado), mas têm access limitado às api do Chrome.
Ambos são executados sempre que você carrega uma nova página (a menos que você tenha usado “correspondências” para restringir onde o script de conteúdo é executado).

Você pode se comunicar entre os dois através da passagem de mensagens . Isso é feito mais facilmente a partir de scripts de conteúdo do que de scripts de segundo plano, porque você precisa saber o ID da guia para o último.

Outros scripts ( browserAction.js , pageAction.js , optionsPage.js ) só são executados quando a página html correspondente é aberta (como se você estivesse abrindo a página da Web na janela do navegador, que é o que você realmente está fazendo). Eles são semelhantes aos scripts de segundo plano em restrições e habilidades.

Tente evitar a necessidade de interagir com os scripts de uma página. A melhor maneira que conheço é interagir através do DOM compartilhado (literalmente escrevendo código javascript dentro de comentários html). Mas o alvo da sua extensão não é projetado para isso, então você terá que include seu próprio script que faz isso na página da web. Use um script de conteúdo para gravar o elemento de script no documento (sua src é
chrome.extension.getURL("myscript.js") ,
e você precisará ter
"web_accessible_resources": ["myscript.js"]
em seu manifesto.

Já faz algum tempo desde que tive que lidar com as extensões do chrome. Eu lembro que foi uma luta e tanto antes de saber como as coisas funcionavam. Para que sua extensão se comunique com o navegador, é fácil usar o arquivo javascript / background e, para se comunicar com a página, é necessário usar o chrome.tabs.executeScript mas isso é muito complicado e pode ser uma verdadeira dor na bunda. Eu sugiro que você faça o tour do google sobre extensões e dê uma boa olhada na api, tudo está lá! Desejo-lhe boa sorte e espero que esta resposta tenha ajudado! : P