Estou aprendendo a criar extensões do Chrome. Comecei a desenvolver um para capturar eventos do YouTube. Quero usá-lo com o YouTube Flash Player (mais tarde tentarei torná-lo compatível com 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!");
O problema é que o console me dá o "Iniciado!" , mas não há "Estado alterado!" quando reproduzo / pausa vídeos do YouTube.
Quando esse código é colocado no console, ele funcionou. O que estou fazendo errado?
player.addEventListener("onStateChange", state);
https://
ouhttp://
, issowww.youtube.com/*
não deixaria você compactar a extensão e geraria um erro de separador de esquema ausenteRespostas:
Os scripts de conteúdo são executados em um ambiente de "mundo isolado" . Você precisa injetar seu
state()
método na própria página.Quando você deseja usar uma das
chrome.*
APIs no script, precisa implementar um manipulador de eventos especial, conforme descrito nesta resposta: Extensão do Chrome - recuperando a mensagem original do Gmail .Caso contrário, se você não precisar usar
chrome.*
APIs, recomendo injetar todo o seu código JS na página adicionando uma<script>
tag:Índice
Método 1: Injetar outro arquivo
Este é o método mais fácil / melhor quando você tem muito código. Inclua seu código JS real em um arquivo na sua extensão, digamos
script.js
. Em seguida, deixe o seu script de conteúdo da seguinte maneira (explicado aqui: Javascript personalizado do "Google Shortcut" do Google Chome ):Nota: Se você usar esse método, o
script.js
arquivo injetado deverá ser adicionado à"web_accessible_resources"
seção ( exemplo ). Caso contrário, o Chrome se recusará a carregar seu script e exibirá o seguinte erro no console:Método 2: injetar código incorporado
Esse método é útil quando você deseja executar rapidamente um pequeno pedaço de código. (Veja também: Como desativar as teclas de atalho do facebook com a extensão do Chrome? ).
Nota: os literais de modelo são suportados apenas no Chrome 41 e superior. Se você deseja que a extensão funcione no Chrome 40-, use:
Método 2b: usando uma função
Para um grande pedaço de código, não é possível citar a string. Em vez de usar uma matriz, uma função pode ser usada e stringificada:
Este método funciona, porque o
+
operador em cadeias e uma função converte todos os objetos em uma cadeia. Se você pretende usar o código mais de uma vez, é aconselhável criar uma função para evitar a repetição do código. Uma implementação pode se parecer com:Nota: Como a função é serializada, o escopo original e todas as propriedades associadas são perdidas!
Método 3: usando um evento embutido
Às vezes, você deseja executar algum código imediatamente, por exemplo, para executar um código antes que o
<head>
elemento seja criado. Isso pode ser feito inserindo uma<script>
etiqueta comtextContent
(consulte o método 2 / 2b).Uma alternativa, mas não recomendada, é usar eventos embutidos. Não é recomendado porque, se a página definir uma política de Segurança de Conteúdo que proíba scripts embutidos, os ouvintes de eventos embutidos serão bloqueados. Os scripts embutidos injetados pela extensão, por outro lado, ainda são executados. Se você ainda deseja usar eventos embutidos, é assim:
Nota: Este método assume que não há outros ouvintes de eventos globais que manipulam o
reset
evento. Se houver, você também pode escolher um dos outros eventos globais. Basta abrir o console do JavaScript (F12), digitardocument.documentElement.on
e escolher os eventos disponíveis.Valores dinâmicos no código injetado
Ocasionalmente, você precisa passar uma variável arbitrária para a função injetada. Por exemplo:
Para injetar esse código, você precisa passar as variáveis como argumentos para a função anônima. Certifique-se de implementá-lo corretamente! O seguinte não funcionará:
A solução é usar
JSON.stringify
antes de passar o argumento. Exemplo:Se você tiver muitas variáveis, vale a pena usar
JSON.stringify
uma vez, para melhorar a legibilidade, da seguinte maneira:fonte
script-src
diretiva que exclua a origem da extensão, o método 2 pode ser bloqueado usando um CSP que exclui "linha não segura" `.script.parentNode.removeChild(script);
. Minha razão para fazer isso é porque eu gosto de limpar minha bagunça. Quando um script embutido é inserido no documento, ele é imediatamente executado e a<script>
tag pode ser removida com segurança.location.href = "javascript: alert('yeah')";
em qualquer lugar do seu script de conteúdo. É mais fácil para trechos curtos de código e também pode acessar os objetos JS da página.javascript:
. O código que abrange várias linhas pode não funcionar conforme o esperado. Uma linha-comment (//
) irá truncar o restante, de modo que este irá falhar:location.href = 'javascript:// Do something <newline> alert(0);';
. Isso pode ser contornado, garantindo que você use comentários de várias linhas. Outra coisa a ter cuidado é que o resultado da expressão deve ser nulo.javascript:window.x = 'some variable';
fará com que o documento seja descarregado e substituído pela frase 'alguma variável'. Se usado corretamente, é de fato uma alternativa atraente<script>
.A única coisa
ausência deOculto da excelente resposta de Rob W é como se comunicar entre o script da página injetado e o script de conteúdo.No lado do recebimento (seu script de conteúdo ou o script da página injetada), adicione um ouvinte de evento:
No lado do iniciador (script de conteúdo ou script de página injetado), envie o evento:
Notas:
No Firefox, para enviar um objeto (ou seja, não um valor primitivo) do script de conteúdo para o contexto da página, é necessário cloná-lo explicitamente no destino usando
cloneInto
(uma função interna), caso contrário, ocorrerá um erro de violação de segurança .fonte
CustomEvent
construtor substitui adocument.createEvent
API reprovada .CustomEvent
construtor. Eu experimentei dois contratempos muito confusos: 1. simplesmente colocar aspas simples em torno de 'detalhes' fez perplexamente o valornull
quando recebido pelo ouvinte do meu Script de conteúdo. 2. Mais importante, por algum motivo eu tiveJSON.parse(JSON.stringify(myData))
que fazê-lo, ou ele também se tornarianull
. Diante disso, parece-me que a afirmação do desenvolvedor do Chromium a seguir - de que o algoritmo "clone estruturado" é usado automaticamente - não é verdadeira. bugs.chromium.org/p/chromium/issues/detail?id=260378#c18Também enfrentei o problema de ordenar scripts carregados, que foi resolvido através do carregamento sequencial de scripts. O carregamento é baseada na resposta de Rob W .
O exemplo de uso seria:
Na verdade, sou um pouco iniciante no JS, então fique à vontade para me dar um ping nas melhores maneiras.
fonte
formulaImageUrl
orcodeImageUrl
, você está destruindo efetivamente a funcionalidade da página. Se você deseja passar uma variável para a página da web, sugiro anexar os dados ao elemento de script (e.g. script.dataset.formulaImageUrl = formulaImageUrl;
) e usar, por exemplo,(function() { var dataset = document.currentScript.dataset; alert(dataset.formulaImageUrl;) })();
no script para acessar os dados.dataset
?document.currentScript
apenas aponta para a tag de script enquanto está em execução. Se você quiser acessar a tag de script e / ou seus atributos / propriedades (por exemplodataset
), precisará armazená-la em uma variável. Precisamos de um IIFE para obter um fechamento para armazenar essa variável sem poluir o espaço para nome global.return;
).no script de conteúdo, adiciono uma tag de script à cabeça que liga um manipulador 'onmessage', dentro do manipulador que eu uso, eval para executar o código. No script de conteúdo do estande, também uso o manipulador onmessage, para obter uma comunicação bidirecional. Documentos do Chrome
pmListener.js é um ouvinte de URL de postagem
Dessa forma, posso ter uma comunicação bidirecional entre o CS e o Real Dom. É muito útil, por exemplo, se você precisar ouvir eventos do webscoket ou qualquer variável ou evento da memória.
fonte
Você pode usar uma função de utilitário que eu criei com a finalidade de executar código no contexto da página e recuperar o valor retornado.
Isso é feito serializando uma função em uma string e injetando-a na página da web.
O utilitário está disponível aqui no GitHub .
Exemplos de uso -
fonte
Se você deseja injetar função pura, em vez de texto, você pode usar este método:
E você pode passar parâmetros (infelizmente, nenhum objeto e matriz pode ser especificado) para as funções. Adicione-o nos baretheses, assim:
fonte