我遇到了将数据从后台脚本发送到的脚本的问题pageAction。我的内容脚本添加了一个,<iframe />并且中的JavaScript <iframe />正在从我的后台脚本接收数据,但是似乎未在中检索到它pageAction。
pageAction
<iframe />
在我的后台脚本中,我有类似以下内容:
chrome.tabs.sendMessage(senderTab.tab.id, { foo:bar });
我的后台脚本senderTab.tab.id中的onMessage侦听器中的“发送者”在哪里?
senderTab.tab.id
onMessage
在<iframe />内容脚本注入的JavaScript中,我有类似以下内容:
chrome.runtime.onMessage.addListener( function(request, sender, sendResponse) { console.log("received in iframe:", request); } });
在<iframe />接收完全一样的预期消息。
我将相同的JavaScript放入了page_action.js,但它没有从后台脚本接收任何数据。chrome.pageAction.show(senderTab.tab.id);在我致电之前激活pageActionchrome.tabs.sendMessage(senderTab.tab.id ...
page_action.js
chrome.pageAction.show(senderTab.tab.id);
chrome.tabs.sendMessage(senderTab.tab.id ...
附加到我的pageAction的HTML页面不是同一选项卡的一部分吗?由于这tabId使我能够激活/“显示”图标,因此我认为pageAction的JavaScript中的侦听器也应从chrome.tabs.sendMessage(senderTab.tab.id ...
tabId
在我的内容脚本中,我使用以下命令将数据发送到后台脚本:
chrome.runtime.sendMessage({ foo: bar });
当内容脚本发送上述消息时,pageAction JavaScript会将其拾取。
如何获取后台脚本以将数据正确发送到pageAction?我不想有pageAction请求/投票,而是希望pageAction仅监听和接收。例如,如果显示了pageAction HTML,则它应该能够在后台页面进行更改时实时更新。
在后台上下文中打开的页面包括:
background
使用MDN不会向其中任何一个发送消息。您将需要使用MDN向他们发送消息。除背景页面和事件页面外,其中任何一个的作用域仅在显示时存在。显然,当代码不存在时,您将无法与代码进行通信。存在作用域时,您可以使用以下方法与其中任何一个进行通信:tabs.sendMessage()``runtime.sendMessage()
tabs.sendMessage()``runtime.sendMessage()
extension.getViews()``extension.getBackgroundPage()``function myFunction
winViews = chrome.extension.getViews();
winViews[0].myFunction(foo);
请注意,在您从MDN或MDN进行的回调中,新打开的选项卡或窗口的视图可能将不存在。您将需要使用某种方法来等待视图存在。2请参阅以下有关与新打开的选项卡或窗口进行通信的推荐方法。tabs.create()``windows.create()
tabs.create()``windows.create()
在其他页面范围内直接操作值可让您交流所需的任何类型的数据。
chrome.runtime.onMessage``chrome.runtime.sendMessage()``runtime.onMessage``sendResponse``chrome.runtime.sendMessage()``browser.runtime.sendMessage()``returntrue;``runtime.onMessage
端口 您还可以使用MDN和MDN连接端口以进行长期消息传递。chrome.runtime.connect()``chrome.runtime.onConnect
chrome.runtime.connect()``chrome.runtime.onConnect
使用chrome.tabs.sendMessage()发送到内容脚本 如果你想发送 的 背景环境(例如,背景脚本或弹出式) 到 你会使用内容脚本chrome.tabs.sendMessage()/ chrome.runtime.onMessage或连接端口使用(S)MDN。chrome.tabs.connect()``chrome.runtime.onConnect
chrome.tabs.sendMessage()
chrome.runtime.onMessage
chrome.tabs.connect()``chrome.runtime.onConnect
仅JSON可序列化的数据 使用消息传递,您只能传递JSON可序列化的数据。
消息被后台中的所有脚本接收,但发件人除外 发送到后台上下文中的消息被已注册侦听器的后台上下文中的所有脚本(发送脚本的接收者除外)接收。3无法指定仅由特定脚本接收。因此,如果您有多个潜在收件人,则需要创建一种方法来确保收到的邮件是针对该脚本的。这样做的方式通常取决于消息中存在的特定属性(例如,使用destination或recipient属性来指示要接收什么脚本的脚本,或者定义某些type消息始终用于某个收件人或另一个收件人),或者根据MDNsender提供给消息处理程序(例如,如果来自一个发件人的消息始终仅用于特定收件人)。没有固定的方法来执行此操作,您必须选择/创建一种在扩展程序中使用的方法。
destination
recipient
type
sender
chrome.storage.onChanged``storage.onChanged
您只能将可JSON序列化的数据存储到StorageArea中。
在任何特定情况下哪种方法最适合使用取决于您要交流的内容(数据类型,状态更改等),以及您要与之通信的扩展的哪一部分或哪一部分。 例如,如果您想传达不可JSON序列化的信息,则需要直接进行传达(即,不发送消息或使用StorageArea)。您可以在同一扩展中使用多种方法。
没有任何弹出窗口(例如,浏览器操作或页面操作)直接与活动选项卡相关联。每个选项卡没有共享或单独实例的概念。但是,用户可以在每个Chrome窗口中打开一个弹出窗口。如果打开了多个弹出窗口(每个Chrome窗口最多一个弹出窗口),则每个弹出窗口都在单独的实例中(单独的作用域;具有自己的Window),但处于相同的上下文中。当弹出窗口实际上是可见的时,它存在于后台上下文中。
每个Chrome窗口一次只能打开一个页面操作或浏览器操作弹出窗口。将为打开的HTML文件将是为当前窗口的活动标签定义的文件, 并由用户通过单击页面/浏览器操作按钮来打开 。通过使用(MDN)或(MDN)并指定一个,可以为不同的选项卡分配不同的HTML文档。可以/将破坏弹出窗口有多种原因,但是肯定是在打开弹出窗口的窗口中另一个选项卡变为活动选项卡时。chrome.browserAction.setPopup()chrome.pageAction.setPopup()tabId
chrome.browserAction.setPopup()
chrome.pageAction.setPopup()
但是,所使用的任何通信方法都只会与当前处于打开状态的通信,而不会与尚未打开的通信。如果一次打开多个Chrome窗口的弹出窗口,则它们是具有各自范围(即各自的Window)的单独实例。您可以想到 类似 在多个标签中打开同一网页的方法。
如果您有后台脚本,则后台脚本上下文将在整个Chrome实例中保持不变。如果您没有后台脚本,则可以在需要时创建上下文(例如,显示弹出窗口),并在不再需要时将其删除。
如上所述,即使弹出窗口确实存在,它也将存在于后台上下文中。调用chrome.tabs.sendMessage()会将消息发送到 插入到选项卡/框架中的内容脚本 ,而不是发送到后台上下文。因此,它不会将消息发送到非内容脚本(如弹出窗口)。
调用(MDN)仅导致显示页面操作 按钮 。它不会导致显示任何关联的 弹出窗口 。如果实际上未显示弹出窗口/选项页面/其他页面(不仅仅是按钮),则其范围不存在。当它不存在时,显然无法接收任何消息chrome.pageAction.show()
chrome.pageAction.show()
取而代之的是页面动作的能力(MDN)或(MDN)按钮,浏览器操作可(MDN)或(MDN)按钮。show()hide()enable()disable()
show()
hide()
enable()
disable()
您可以使用(MDN)或(MDN)从扩展程序中打开包含HTML页面的选项卡或窗口。但是,这两个API调用的回调都是在页面DOM存在之前执行的,因此是在与页面相关联的任何JavaScript之前执行的。因此,您无法立即访问该页面内容创建的DOM,也无法与该页面的JavaScript进行交互。具体来说:不会添加任何侦听器,因此新打开的页面不会接收到那时发送的消息。tabs.create()windows.create()runtime.onMessage()
tabs.create()
windows.create()
runtime.onMessage()
解决此问题的最佳方法是:
chrome.extension.getBackgroundPage()
storage.local
messageToNewExtensionPage
runtime.sendMessage()
tabs.sendMessage()
sendResponse
chrome.windows.create({url: myUrl},function(win){ //Poll for the view of the window ID. Poll every 50ms for a // maximum of 20 times (1 second). Then do a second set of polling to // accommodate slower machines. Testing on a single moderately fast machine // indicated the view was available after, at most, the second 50ms delay. waitForWindowId(win.id,50,20,actOnViewFound,do2ndWaitForWinId); }); function waitForWindowId(id,delay,maxTries,foundCallback,notFoundCallback) { if(maxTries--<=0){ if(typeof notFoundCallback === 'function'){ notFoundCallback(id,foundCallback); } return; } let views = chrome.extension.getViews({windowId:id}); if(views.length > 0){ if(typeof foundCallback === 'function'){ foundCallback(views[0]); } } else { setTimeout(waitForWindowId,delay,id,delay,maxTries,foundCallback ,notFoundCallback); } } function do2ndWaitForWinId(winId,foundCallback){ //Poll for the view of the window ID. Poll every 500ms for max 40 times (20s). waitForWindowId(winId,500,40,foundCallback,windowViewNotFound); } function windowViewNotFound(winId,foundCallback){ //Did not find the view for the window. Do what you want here. // Currently fail quietly. } function actOnViewFound(view){ //What you desire to happen with the view, when it exists. }
在版本51之前的Firefox版本中,将为同一脚本发送的消息调用runtime.onMessage侦听器(例如,由后台脚本发送的消息也将由后台脚本接收)。在那些版本的Firefox中,如果从runtime.onMessage侦听器中无条件调用runtime.sendMessage(),则将设置一个无限循环,该循环将最大程度地占用CPU并锁定Firefox。如果需要从runtime.onMessage内调用runtime.sendMessage(),则需要检查sender.url属性以确认您没有在响应同一脚本发送的消息时发送消息。自Firefox 51起,此错误已解决。