我在创建Chrome扩展程序时遇到问题。
我创建了一个<iframe>
,用户在点击我的扩展程序按钮时,会在任何网页中嵌入内容脚本。
在此<iframe>
中,有一个选择框,当更改时,应将消息发送回扩展程序。
然后,扩展程序应从Google电子表格中获取数据,然后将信息发送回<iframe>
。
我的 manifest.json 如下(编者注:过滤到相关字段):
{
// manifest.json
"background" : {
"scripts" : ["background.js"]
},
"browser_action": {
"default_icon": "icon-small.png"
},
"content_scripts": [ {
"js": ["jquery-1.11.1.min.js","selectionjfm.js","jquery-ui.min.js","nlp_compromise.js"],
"css":["jquery-ui.css"],
"matches": [ "http://*/*", "https://*/*"],
"all_frames":true,
"run_at": "document_end",
"info.status":"complete", "status": "complete"
}],
// ...
"permissions": [
"identity", "https://accounts.google.com/*", "https://www.googleapis.com/*","https://spreadsheets.google.com/*","tabs","storage","<all_urls>"
],
"web_accessible_resources": [
"jquery-ui.min.js","popup.html","popup.js","inject.js","jquery-1.11.1.min.js","loader.gif"
],
"oauth2": {
"client_id": "xxxxxxxxx.apps.googleusercontent.com",
"scopes": ["https://www.googleapis.com/auth/plus.login","https://spreadsheets.google.com/feeds"]
}
}
此扩展程序包含 selectionjfm.js 作为内容脚本,以这种方式插入<iframe>
:
// selectionjfm.js - content script as included in manifest.json
var iframe = document.createElement('iframe');
iframe.setAttribute("id", "my_id");
iframe.src = chrome.runtime.getURL('popup.html');
document.body.appendChild(iframe);
但是也以这种方式注入一个JavaScript文件 inject.js :
// selectionjfm.js - content script as included in manifest.json
var s = document.createElement('script');
s.src = chrome.runtime.getURL('inject.js');
(document.head || document.documentElement).appendChild(s);
console.log("[Content script 1] added inject.js to the content page");
var s = document.createElement('script');
s.src = chrome.runtime.getURL('jquery-1.11.1.min.js');
(document.head || document.documentElement).appendChild(s);
包含一个选择框。当用户在此框中选择其他值时,我需要使用Google Spreadsheet API针对Google电子表格运行请求。这就是为什么我想将一条消息发送回扩展,因为据我所知,它只能从那里使用这些API。
inject.js 会在<iframe>
选择框上的onchange
事件被触发时等待<iframe>
发送的消息。
// inject.js waitning for message from the iframe
window.addEventListener("message",
function (e) {...
<iframe>
发送的消息:
//poupup.js (iframe source)
var sel = document.getElementById("databaseselect");
sel.addEventListener("change", function (e) {
sendMessTobg("changedatabase",sel.selectedOptions[0].text);
});
然后尝试向 background.js :
发送消息// inject.js
if (e.data.message == "changedatabase") { // recieving message from the iframe : this works fine
if (e.data.data != null) {
console.log("[Content script] trying to send databasechange to extension");
chrome.runtime.sendMessage({
databasechange:true,
content:e.data.data
}, function (reply) {
if (chrome.runtime.lastError) {
console.log("[Content script] failure to send databasechange to extension");
} else {
console.log("[Content script] databasechange with backgroud is a success!");
}
});
}
}
然后是chrome.runtime.sendMessage
给出错误:
未捕获错误:连接的参数无效。
我在另一篇文章中看到过关于发送扩展ID的事情,但文档说这不是强制性的,因为如果没有给出,ID将是我自己的扩展名。
答案 0 :(得分:0)
此处的问题是您的inject.js
不再是内容脚本。您已将其添加到DOM,并became indistinguishable from the page's own code。 Chrome甚至不再知道它是扩展程序的一部分(以及扩展程序)。
因此,它不能以通常的方式调用chrome.runtime.sendMessage
- 这就是这个错误的含义。您需要以不同方式执行通信。
externally_connectable
不适用于您的情况,因为您希望它在任何网站上运行,并且该方法需要将特定域列入白名单。
因此,合理的追索权是use DOM events to communicate to a content script将传递信息。
..但是等等,你已经在使用DOM事件了。你只是在错误的背景下捕捉它!您的"message"
侦听器只需要是内容脚本,而不是页面级脚本。将其添加到selectionjfm.js
或者考虑是否确实需要将inject.js
注入页面。