gpt4 book ai didi

javascript - 网站可以调用浏览器扩展吗?

转载 作者:行者123 更新时间:2023-12-03 01:54:39 27 4
gpt4 key购买 nike

我是浏览器扩展开发的新手,我了解浏览器扩展更改页面并向其中注入(inject)代码的概念。

有没有办法可以扭转这个方向?我编写了一个扩展程序,提供了一组API,想要使用该扩展程序的网站可以检测到该扩展程序的存在,如果存在,该网站可以调用我的API方法,例如var extension = Extenion(foo, bar)。在Chrome,Firefox和Safari中可能吗?

例子:

  • Google创建了一个名为BeautifierExtension的新扩展。它具有一组作为JS对象的API。
  • 用户转到reddit.com。 Reddit.com检测BeautifierExtension并通过调用beautifer = Beautifier();
  • 来调用API

    请参阅#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支持,则原始答案如下:

    尽管这里描述的原理(网页脚本注入(inject),长期运行的后台脚本,消息传递)适用于几乎所有浏览器扩展框架,但我都会以Chrome为中心的角度回答。

    从高层次上讲,您想要做的是将 content script注入(inject)每个网页中,从而添加一个可访问该网页的API。当站点调用API时,API会触发内容脚本执行某些操作,例如通过异步回调将消息发送到后台页面和/或将结果发送回内容脚本。

    这里的主要困难是“注入(inject)”到网页中的内容脚本不能直接更改页面的JavaScript execution environment。它们共享DOM,因此在内容脚本和Web页面之间共享对DOM结构的 事件的更改,但是不共享函数和变量。例子:
  • DOM操作:如果内容脚本将<div>元素添加到页面,则可以正常工作。内容脚本和页面都将看到新的<div>
  • 事件:如果内容脚本设置了事件监听器,例如,单击元素,则事件发生时,监听器将成功触发。如果页面为从内容脚本触发的自定义事件设置了侦听器,则在内容脚本触发这些事件时将成功接收它们。
  • 函数:如果内容脚本定义了新的全局函数foo()(如在设置新API时可能会尝试的)。页面无法查看或执行foo,因为foo仅存在于内容脚本的执行环境中,而不存在于页面环境中。

  • 那么,如何设置适当的API?答案有很多步骤:
  • 在较低级别上,将您的API设置为event-based。该网页使用dispatchEvent触发自定义DOM事件,内容脚本使用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 constructor中。这里的示例非常简单-一旦内容脚本具有页面中的数据(很可能是pass itbackground page进行进一步处理),您显然可以在内容脚本中执行更多操作。
  • 但是,这只是成功的一半。在上面的示例中,普通网页必须自己创建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,则需要在 list 的 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");
  • 我们的API流程还有另外一个缺点: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...
    });
  • 解决加载时脚本可用性问题的另一种方法是将 list 中内容脚本的run_at属性设置为"document_start",如下所示:

    manifest.json:
        "content_scripts": [
    {
    "matches": ["https://example.com/*"],
    "js": [
    "myapi.js"
    ],
    "run_at": "document_start"
    }
    ],

    摘自docs:

    In the case of "document_start", the files are injected after any files from css, but before any other DOM is constructed or any other script is run.



    对于某些内容脚本,与“API加载”事件相比,它可能更合适且工作量更少。
  • 为了将结果发送回页面,您需要提供一个异步回调函数。由于事件触发/侦听本质上是异步的,因此无法从API同步返回结果(即,您的网站端API函数在内容脚本通过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是必需的,这样它们就不会读取错误的响应。

  • 我认为这就是一切!因此,当您考虑其他扩展也可以将侦听器绑定(bind)到事件以窃听页面如何使用API​​时,这不是出于胆小,甚至可能不值得。我仅了解所有这些信息,因为我为学校项目制作了概念验证的加密API(并随后了解了与此相关的主要安全隐患)。

    总计:内容脚本可以侦听普通网页中的自定义事件,并且该脚本还可以注入(inject)具有使网页更容易触发这些事件的功能的脚本文件。内容脚本可以将消息传递到后台页面,然后由该页面存储,转换或传输消息中的数据。

    关于javascript - 网站可以调用浏览器扩展吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10526995/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com