javascript - chrome 扩展的浏览器 Action 、后台脚本和内容脚本之间通信的上下文和方法?

标签 javascript google-chrome google-chrome-extension

我认为 chrome 扩展总体上非常简单且非常强大,但总是让我感到困惑的一件事是尝试在可能运行代码的各种脚本之间进行通信。当从浏览器操作的“default_popup”页面引用时,就会运行代码,“背景”的“脚本”属性中的代码和内容脚本。

这些类别中的脚本在什么上下文中运行,每个脚本如何与其他脚本通信?

最佳答案

三种不同的语境

作为 Chrome 扩展开发者,您可以区分三种不同的环境。

  • 分机码 , 在你的 Chrome 扩展程序中运行
  • Background/event
  • Browser action/page action弹窗
  • info bar内的页面.
  • 顶级框架是来自扩展程序的文档的选项卡,例如 options page .
  • Content scripts ,在选项卡的进程中运行。
  • 非分机码在选项卡的进程中运行 ( injected by content scripts )。

  • 请注意 <iframe src="chrome-extension://EXTENSIONID/page.htm">在非扩展页面中,过去被视为案例 2(内容脚本),因为框架是在非特权选项卡进程中加载​​的。自 out-of-process iframes在 Chrome 56 中为扩展启动,这些页面由扩展进程处理,因此它们可能使用相同的全套扩展 API。此 change in behavior (allowing extension frames to use privileged extension APIs) is intentional .

    访问 window扩展过程中的对象

    因为所有的扩展代码都运行在同一个进程中,所以它们可以互相访问全局window目的。这一特性并不广为人知,但允许在同一个扩展进程中直接操作 JavaScript 和 DOM 对象。通常最好不要使用这种方法,而是使用 message passing取而代之的是 API。
    // To access the `window` of a background page, use
    var bgWindowObject = chrome.extension.getBackgroundPage();
    // To access the `window` of an event or background page, use:
    chrome.runtime.getBackgroundPage(function(bgWindowObject) {
        // Do something with `bgWindow` if you want
    });
    
    // To access the `window` of the badge's popup page (only if it's open!!!), use
    var popupWindowObject = chrome.extension.getViews({type:'popup'})[0];
    
    // To access the `window` of the options page (called /options.html), use
    var allWindowObjects = chrome.extension.getViews({type:'tab'});
    var popupWindowObjects = allWindowObjects.filter(function(windowObject) {
        return windowObject.location.pathname == '/options.html';
    });
    // Example: Get the `window` object of the first options page:
    var popupWindowObject = popupWindowObjects[0];
    

    为了使本节简短,我有意将代码示例限制为访问其他全局 window 的演示。对象。您可以使用这些方法来定义全局方法、设置全局变量、调用全局函数等。
    ... 前提是页面是打开的。有人thought弹出窗口的 window始终可用。这不是真的,当弹出窗口关闭时,全局对象就被释放了!

    交流来自 message passing

    消息 channel 总是有两端:发送者和接收者。
    要成为接收者,请使用 chrome.runtime.onMessage.addListener 绑定(bind)事件监听器方法。这可以通过扩展代码和内容脚本来完成。

    要在扩展中传递消息,请使用 chrome.runtime.sendMessage .如果您想向另一个选项卡发送消息,请调用 chrome.tabs.sendMessage .目标选项卡是通过包含一个整数 ( tabId ) 作为其第一个参数来指定的。请注意,后台页面只能向一个选项卡发送消息。要访问所有选项卡,必须为每个选项卡调用该方法。例如:
    chrome.tabs.query({}, function(tabs) {
        for (var i=0; i<tabs.length; i++) {
            chrome.tabs.sendMessage(tabs[i].id, "some message");
        }
    });

    内容脚本只能调用 chrome.runtime.sendMessage 向分机代码发送消息。如果您想从一个内容脚本向另一个内容脚本发送消息,则需要一个背景/事件页面,它接收一条消息并将其发送到所需的选项卡。见 this answer举个例子。
    sendMessage方法接受一个可选函数,该函数作为 onMessage 的第三个参数被接收。事件。
    chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
        if (message === 'message') sendResponse('the response');
    });
    chrome.runtime.sendMessage('message', function(response) {
        console('sendResponse was called with: ' + response);
    });
    

    前面的示例显示了明显的行为。当您想要异步发送响应时,事情会变得更加棘手,例如,如果您想要执行 AJAX 请求以获取一些数据。当onMessage函数在没有调用的情况下返回 sendResponse ,Chrome 会立即调用 sendResponse .自 sendResponse只能调用一次,您将收到以下错误:

    Could not send response: The chrome.runtime.onMessage listener must return true if you want to send a response after the listener returns (message was sent by extension EXTENSION ID HERE)



    按照错误提示添加 return true;在您的 onMessage 事件监听器中:
    chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
        setTimeout(function() { // Example: asynchronous invocation of sendResponse
            sendResponse('async response');
        }, 200);
        return true;
    });
    

    在本节中,我已经解释了简单的一次性消息传递的实际应用。如果您想了解有关长期消息 channel 或跨扩展消息传递的更多信息,请阅读 tutorial from the official documentation .

    消息传递 API 经历了几次名称更改。如果您阅读旧示例,请记住这一点。历史和兼容性说明可以在 here 中找到.

    内容脚本和页面之间的通信

    可以与页面进行通信。 Apsillers 创建了一个很好的答案,它解释了如何在(非扩展)页面和内容脚本之间建立通信 channel 。阅读他的回答 Can a site invoke a browser extension? .

    apsiller 方法相对于 one from the documentation 的优势是使用了自定义事件。文档使用 window.postMessage向页面发送消息,但这可能会导致与不期望消息事件的错误编码页面发生冲突。

    关于javascript - chrome 扩展的浏览器 Action 、后台脚本和内容脚本之间通信的上下文和方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17246133/

    相关文章:

    javascript - 响应式设计中的灯箱错误视觉显示

    javascript - 调整大小和计算高度 - 错误

    javascript - Tinymce 切换格式,格式化按钮而不是编辑器

    javascript - 如何正确创建带有 'Url.Action' 查询字符串的 url,以便它在 Firefox 中工作

    javascript - Chrome Canvas 文本框

    css - 使用 css-transition 时 Chrome 字母会跳舞

    html - 谷歌浏览器自动填充删除背景图片

    javascript - Chrome 扩展程序 - 页面操作 : defining pages

    javascript - 注入(inject)的脚本无法声明变量

    javascript - onclick 不适用于 Chrome 扩展?