我是浏览器扩展开发的新手,我了解浏览器扩展更改页面并向其中注入代码的概念。
有没有办法可以扭转这个方向?我编写了一个扩展程序,提供了一组API,想要使用该扩展程序的网站可以检测到该扩展程序的存在,如果存在,该网站可以调用诸如这样的API方法varextension = Extenion(foo, bar)
。在Chrome,Firefox和Safari中可能吗?
例:
Google创建了一个名为BeautifierExtension的新扩展。它具有一组作为JS对象的API。
用户转到 Reddit.com。Reddit.com检测BeautifierExtension并通过调用来调用APIbeautifer = Beautifier();
请参阅#2-通常是通过扩展名来检测匹配的网站并更改页面。我有兴趣知道的是#2是否可能。
自从Chrome引入以来externally_connectable
,这在Chrome中非常容易做到。首先,在manifest.json
文件中指定允许的域:
"externally_connectable": {
"matches": ["*://*.example.com/*"]
}
用于chrome.runtime.sendMessage
从页面发送消息:
chrome.runtime.sendMessage(editorExtensionId, {openUrlInEditor: url},
function(response) {
// ...
});
最后,在您的背景页面中收听chrome.runtime.onMessageExternal
:
chrome.runtime.onMessageExternal.addListener(
function(request, sender, sendResponse) {
// verify `sender.url`, read `request` object, reply with `sednResponse(...)`...
});
如果您无权获得externally_connectable
支持,则原始答案如下:
尽管这里描述的原理(网页脚本注入,长时间运行的后台脚本,消息传递)适用于几乎所有浏览器扩展框架,但我都将从以Chrome为中心的角度回答。
从高层次上讲,您想要做的是将内容脚本注入每个网页,从而添加一个可访问该网页的API。当站点调用API时,API会触发内容脚本执行某些操作,例如通过异步回调将消息发送到后台页面和/或将结果发送回内容脚本。
这里的主要困难在于,“注入”到网页中的内容脚本不能直接更改页面的JavaScript执行环境。它们共享DOM,因此在内容脚本和网页之间共享 事件 和 DOM结构更改 ,但不共享函数和变量。例子:
DOM操作: 如果内容脚本将<div>
元素添加到页面,则将按预期工作。内容脚本和页面都将看到新的<div>
。
事件: 如果内容脚本设置了事件侦听器(例如,单击元素),则事件发生时侦听器将成功触发。如果页面为从内容脚本触发的自定义事件设置了侦听器,则在内容脚本触发这些事件时将成功接收它们。
函数: 如果内容脚本定义了新的全局函数foo()
(如您在设置新的API时可能尝试的)。该页面 无法 查看或执行foo
,因为它foo
仅存在于内容脚本的执行环境中,而不存在于页面的环境中。
那么,如何设置适当的API?答案有很多步骤:
dispatchEvent
,内容脚本使用侦听它们addEventListener
,并在收到事件时采取措施。这是一个简单的基于事件的存储API,网页可以使用该API进行扩展以为其存储数据:content_script.js (在您的扩展程序中):
// an object used to store things passed in from the API
internalStorage = {};
// listen for myStoreEvent fired from the page with key/value pair data
document.addEventListener('myStoreEvent', function(event) {
var dataFromPage = event.detail;
internalStorage[dataFromPage.key] = dataFromPage.value
});
非扩展网页,使用基于事件的API:
function sendDataToExtension(key, value) {
var dataObj = {"key":key, "value":value};
var storeEvent = new CustomEvent('myStoreEvent', {"detail":dataObj});
document.dispatchEvent(storeEvent);
}
sendDataToExtension("hello", "world");
如您所见,普通网页触发了内容脚本可以查看和响应的事件,因为它们共享DOM。事件具有附加的数据,并添加到CustomEvent
构造函数中。这里的示例非常简单-一旦内容脚本具有页面中的数据(很可能将其传递到后台页面以进行进一步处理),您显然可以在其内容中做更多的事情。
sendDataToExtension
自行创建。创建和触发自定义事件非常冗长(我的代码占用3行,并且相对简短)。您不想强迫网站仅使用API编写奥秘的事件触发代码。该解决方案有点令人讨厌:将<script>
标签添加到共享DOM,这会将事件触发代码添加到主页的执行环境中。内部 content_script.js:
// inject a script from the extension's files
// into the execution environment of the main page
var s = document.createElement('script');
s.src = chrome.extension.getURL("myapi.js");
document.documentElement.appendChild(s);
在其中定义的任何功能都myapi.js
可以访问主页。(如果使用"manifest_version":2
,则需要myapi.js
在清单的中包含web_accessible_resources
)。
myapi.js:
function sendDataToExtension(key, value) {
var dataObj = {"key":key, "value":value};
var storeEvent = new CustomEvent('myStoreEvent', {"detail":dataObj});
document.dispatchEvent(storeEvent);
}
现在 普通的网页 可以简单地执行以下操作:
sendDataToExtension("hello", "world");
myapi.js
脚本在加载时将无法完全使用。相反,它将在页面加载时间之后的一段时间加载。因此,纯网页需要知道何时可以安全地调用您的API。您可以通过myapi.js
触发页面监听的“ API就绪”事件来解决此问题。myapi.js:
function sendDataToExtension(key, value) {
// as above
}
// since this script is running, myapi.js has loaded, so let the page know
var customAPILoaded = new CustomEvent('customAPILoaded');
document.dispatchEvent(customAPILoaded);
*使用API的 *纯网页 :
document.addEventListener('customAPILoaded', function() {
sendDataToExtension("hello", "world");
// all API interaction goes in here, now that the API is loaded...
});
run_at
在清单中设置内容脚本的属性,"document_start"
如下所示:manifest.json:
"content_scripts": [
{
"matches": ["https://example.com/*"],
"js": [
"myapi.js"
],
"run_at": "document_start"
}
],
在“ document_start”的情况下,文件将在来自css的任何文件之后但在构造任何其他DOM或运行任何其他脚本之前注入。
对于某些内容脚本,与“ API加载”事件相比,它可能更合适且工作量更少。
myapi.js:
function getDataFromExtension(key, callback) {
var reqId = Math.random().toString(); // unique ID for this request
var dataObj = {"key":key, "reqId":reqId};
var fetchEvent = new CustomEvent('myFetchEvent', {"detail":dataObj});
document.dispatchEvent(fetchEvent);
// get ready for a reply from the content script
document.addEventListener('fetchResponse', function respListener(event) {
var data = event.detail;
// check if this response is for this request
if(data.reqId == reqId) {
callback(data.value);
document.removeEventListener('fetchResponse', respListener);
}
}
}
content_script.js (在您的扩展程序中):
// listen for myFetchEvent fired from the page with key
// then fire a fetchResponse event with the reply
document.addEventListener('myStoreEvent', function(event) {
var dataFromPage = event.detail;
var responseData = {"value":internalStorage[dataFromPage.key], "reqId":data.reqId};
var fetchResponse = new CustomEvent('fetchResponse', {"detail":responseData});
document.dispatchEvent(fetchResponse);
});
普通网页:
document.addEventListener('customAPILoaded', function() {
getDataFromExtension("hello", function(val) {
alert("extension says " + val);
});
});
reqId
情况下,你必须出一次多个请求是必要的,使他们不读错的响应。
我认为这就是一切!因此,当您考虑其他扩展也可以将侦听器绑定到事件以窃听页面如何使用API时,这不是出于胆小或可能不值得的。我只知道所有这一切,因为我为学校项目制作了概念验证的加密API(并随后了解了与之相关的主要安全隐患)。
总而言之:
内容脚本可以侦听来自普通网页的自定义事件,并且脚本还可以注入具有使网页更容易触发这些事件的功能的脚本文件。内容脚本可以将消息传递到后台页面,然后由该页面存储,转换或传输消息中的数据。
每个桌面浏览器都有一套开发工具,开箱即用,您可以将他们添加到您的浏览器的扩展或插件。 以下是两个具有一些实用功能的Chrome扩展程序,可帮助您调试设计。 Emmet Re:View Emmet Re:View是一个工具,它可以让你轻松查看您的网站在每个媒体查询(media queries)中的样子,并同步所有页面的滚动。 你可以在他们的网站上看到它的演示。 Download on the Chr
我想使用我的selenium2网格在几个浏览器上运行我的behat测试。我已经设法使它们以不同的behat.yml配置文件在每个环境/浏览器的基础上运行,但我希望配置一个behat配置文件来触发在我的所有节点上的运行。 我的behat.yml配置文件如下所示: 浏览器字段中的数组,config parser不喜欢 具有多个名称的字符串,认为我有一个以字符串sigh命名的浏览器 为我的seleniu
我可以创建一个插件或扩展的谷歌Chrome移动(Android谷歌Chrome)? 如果没有,我可以为谷歌Chrome(桌面)创建一个扩展,它将在谷歌Chrome栏中添加一个按钮。此按钮将在另一个web浏览器中打开页面(在我自己的web浏览器中),因此,此按钮应该启动我自己的web浏览器。
问题内容: 我想使用Python在本地计算机的网络浏览器(Chrome或Internet Explorer)中打开网站。 有没有可以为我做到这一点的模块? 问题答案: 该模块看起来很有希望
问题内容: 我已经创建了一个简单的 应用程序(使用),带有联系表单,当用户单击“提交”时,我想生成并发送电子邮件。为此,我一直试图像这样使用: …但是我在导入过程中遇到了很多错误。 我是否在这里缺少某些东西,或者根本不是为在浏览器中使用而设计的?如果是这种情况,我应该考虑其他选择吗? 问题答案: node.js用于服务器端JavaScript,它允许您执行浏览器无法完成的许多工作。 除了mailt
我喜欢firefox扩展的多帐户容器。我想切换到brave浏览器,但我找不到好的选择。由于API的限制,它是一种只能在firefox中工作的功能,还是可以通过扩展在基于chromium的浏览器中实现? 如果我想创建这个扩展,我可以让它与firefox的多帐户容器完全相同吗?我试图将扩展加载到brave中,但由于API的不同,我认为它有很多错误。因此,唯一的方法是对铬进行编程。这可能吗? 我找到了这