我正在尝试将消息从后台页面发送到内容脚本,然后将消息从该内容脚本发送到注入的脚本。我已经尝试过了,但是没有用。
这是我的代码的样子。
manifest.json
{ "manifest_version": 2, "name": "NAME", "description": ":D", "version": "0.0", "permissions": [ "tabs","<all_urls>" ], "content_scripts": [ { "matches": ["<all_urls>"], "js": ["content_script.js"] } ], "web_accessible_resources": [ "injected.js" ], "background":{ "scripts":["background.js"] } }
background.js
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response){}); });
content_script.js
var s = document.createElement('script'); s.src = chrome.extension.getURL('injected.js'); s.onload = function(){ this.parentNode.removeChild(this); }; (document.head||document.documentElement).appendChild(s); chrome.runtime.onMessage.addListener( function(request, sender, sendResponse) { document.dispatchEvent(new CustomEvent('Buffer2Remote', {todo: "LOL"})); });
injection.js
document.addEventListener('Buffer2Remote', function(e){ alert(e.todo); });
从第一部分背景-> content_script开始,消息发送不起作用。我的代码有什么问题吗?
由于内容脚本的注入方式,您的脚本无法使用。
与某些人期望的相反,当您(重新)加载扩展程序时,Chrome 不会将内容脚本注入 与清单中的模式匹配的 现有标签 中。仅在加载扩展名之后,任何导航都将检查URL是否匹配并注入代码。
因此,时间表:
chrome://extensions/
1-如果您重新加载扩展程序,也会发生这种情况。如果注入了内容脚本,它将继续处理其事件/不会被卸载,但无法再与扩展通信。(有关详细信息,请参阅末尾的附录)
解决方案1: 您可以先询问要发送消息的选项卡,以了解消息是否准备就绪 ,然后在静音时以编程方式注入脚本。考虑:
// Background function ensureSendMessage(tabId, message, callback){ chrome.tabs.sendMessage(tabId, {ping: true}, function(response){ if(response && response.pong) { // Content script ready chrome.tabs.sendMessage(tabId, message, callback); } else { // No listener on the other end chrome.tabs.executeScript(tabId, {file: "content_script.js"}, function(){ if(chrome.runtime.lastError) { console.error(chrome.runtime.lastError); throw Error("Unable to inject script into tab " + tabId); } // OK, now it's injected and ready chrome.tabs.sendMessage(tabId, message, callback); }); } }); } chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { ensureSendMessage(tabs[0].id, {greeting: "hello"}); });
和
// Content script chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { if(request.ping) { sendResponse({pong: true}); return; } /* Content script action */ });
解决方案2: 始终注入脚本,但要确保脚本仅执行一次。
// Background function ensureSendMessage(tabId, message, callback){ chrome.tabs.executeScript(tabId, {file: "content_script.js"}, function(){ if(chrome.runtime.lastError) { console.error(chrome.runtime.lastError); throw Error("Unable to inject script into tab " + tabId); } // OK, now it's injected and ready chrome.tabs.sendMessage(tabId, message, callback); }); }
// Content script var injected; if(!injected){ injected = true; /* your toplevel code */ }
这比较简单,但是在扩展分机重新加载方面比较复杂。重新加载扩展后,旧脚本仍然存在1,但它不再是“您的”上下文- 因此injected将是未定义的。当心可能两次执行脚本的副作用。
injected
解决方案3: 在初始化时不加选择地注入您的内容脚本 。仅当可以安全运行两次相同的内容脚本或在页面完全加载后运行该脚本时,才可以安全地执行此操作。
chrome.tabs.query({}, function(tabs) { for(var i in tabs) { // Filter by url if needed; that would require "tabs" permission // Note that injection will simply fail for tabs that you don't have permissions for chrome.tabs.executeScript(tabs[i].id, {file: "content_script.js"}, function() { // Now you can use normal messaging }); } });
我也怀疑您希望它以某种操作运行,而不是以扩展负载运行。例如,您可以使用浏览器动作并将代码包装在chrome.browserAction.onClicked侦听器中。
chrome.browserAction.onClicked
重新加载扩展程序后,人们会期望Chrome清理所有内容脚本。但是显然不是这样。内容脚本的侦听器未禁用。但是,任何带有父扩展名的消息传递都会失败。 这可能应该被认为是一个错误,并且可能在某个时候被修复。 我将这个状态称为“孤立”
在两种情况下,这都不是问题:
但是,如果不是这种情况,那么您就会遇到问题:内容脚本可能正在执行某些操作,但是失败或干扰了其自身的另一个非孤立实例。
一个解决方案是:
代码,内容脚本:
function heartbeat(success, failure) { chrome.runtime.sendMessage({heartbeat: true}, function(reply){ if(chrome.runtime.lastError){ failure(); } else { success(); } }); } function handler() { heartbeat( function(){ // hearbeat success /* Do stuff */ }, function(){ // hearbeat failure someEvent.removeListener(handler); console.log("Goodbye, cruel world!"); } ); } someEvent.addListener(handler);
后台脚本:
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { if(request.heartbeat) { sendResponse(request); return; } /* ... */ });