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

zd287kbt  于 2023-02-01  发布在  Go
关注(0)|答案(3)|浏览(251)

我认为chrome扩展总体上很简单,也很强大,但有一件事总是让我困惑,那就是试图在代码可能运行的各种脚本之间进行通信。有从浏览器操作的“default_popup”页面引用时运行的代码,“background”的“scripts”属性中的代码和内容脚本。
这些类别中的脚本在什么上下文中运行,它们如何相互通信?

ca1c2owp

ca1c2owp1#

∮三种不同的背景∮
作为Chrome扩展程序开发人员,您可以区分三种不同的环境。

*扩展代码,在Chrome扩展进程中运行

请注意,非扩展页面中的<iframe src="chrome-extension://EXTENSIONID/page.htm">通常被视为第二种情况(内容脚本),因为框架是在一个非特权的标签进程中加载的。由于out-of-process iframes是为Chrome 56中的扩展启动的,因此这些页面由扩展进程处理,因此它们可能使用相同的扩展API全集。

访问扩展进程中的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进行通信

消息通道始终有两个端点:发送者和接收者。
要成为接收者,使用chrome.runtime.onMessage.addListener方法绑定一个事件监听器,这可以通过扩展代码和内容脚本来完成。
要在扩展内传递消息,请使用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向扩展代码发送消息。如果您想从一个内容脚本向另一个内容脚本发送消息,则需要一个后台/事件页面,该页面接收消息并将其发送到所需的选项卡。请参阅此答案中的示例。
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只能被调用一次,你将收到以下错误:
无法发送响应:如果你想在chrome.runtime.onMessage监听器返回后发送一个响应(消息是由扩展名 EXTENSION ID HERE 发送的),那么它必须返回true
按照错误提示执行操作,在onMessage事件侦听器中添加return true;

chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
    setTimeout(function() { // Example: asynchronous invocation of sendResponse
        sendResponse('async response');
    }, 200);
    return true;
});

我在本节中解释了简单的一次性消息传递的实际应用,如果你想了解更多关于长寿命消息通道或跨扩展消息传递的信息,请阅读tutorial from the official documentation
消息传递API已经经历了几次名称更改。如果您阅读了以前的示例,请记住这一点。历史和兼容性说明可以在这里找到。

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

与页面进行通信是可能的。Apsillers给出了一个很好的答案,解释了如何在(非扩展)页面和内容脚本之间建立通信通道。请阅读他的答案:网站能否调用浏览器扩展?
apsiller的方法相对于文档中的方法的优点是使用了一个自定义事件,文档使用window.postMessage向页面发送消息,但这可能会导致与不期望消息事件的编码错误的页面发生冲突。

2o7dmzc5

2o7dmzc52#

Google文档包含了所有的信息,但是很难将所有的信息整合在一起。主要有两种类型的脚本:
1.后台脚本可以完全访问Chrome api,但无法与目标网页交互。
2.内容脚本可以相互交互,也可以与网页的DOM交互(但不能与其脚本交互,因为它是独立的),但只能有限地访问Chrome api。
无论何时加载新页面(除非您使用"matches"来限制内容脚本的运行位置),这两个脚本都会运行。
您可以通过message passing在两者之间进行通信,这在内容脚本中比在后台脚本中更容易实现,因为您需要知道后者的标签ID。
其他脚本(browserAction.jspageAction.jsoptionsPage.js)只有在对应的html页面打开时才运行(就好像你在浏览器窗口中打开网页,这才是你真正在做的事情),它们在限制和能力上与后台脚本类似。
尽量避免与页面脚本交互。我所知道的最好的方法是通过共享DOM交互(实际上就是在html注解中编写javascript代码)。但是你的扩展的目标不是为此设计的,所以你必须在网页中包含你自己的脚本。使用内容脚本将脚本元素写入文档(它的src
chrome.extension.getURL("myscript.js")
你需要
"web_accessible_resources": ["myscript.js"]
在你的旅客名单上。

hwazgwia

hwazgwia3#

我已经有一段时间没有处理chrome的扩展了。我记得在我弄明白它是如何工作之前,我经历了相当大的斗争。为了让你的扩展与浏览器通信,你可以很容易地使用你的javascript/background文件。要与网页进行通信,您需要使用chrome.tabs.executeScript,但这确实很棘手,可能是一个真正的麻烦。我建议你选择google's tour on extensions,并给予他们的API一个真正的好忽略,一切都在那里!我祝你好运,我希望这个答案对你有帮助!:P

相关问题