Eri*_*c G 6 javascript iframe google-chrome-extension firefox-addon-webextensions
我遇到了一个问题,从我的后台脚本发送数据到我的脚本pageAction.我的内容脚本添加了一个<iframe />,而JavaScript <iframe />正在从我的后台脚本接收数据,但它似乎没有在我的pageAction.
在我的后台脚本中,我有类似的东西:
chrome.tabs.sendMessage(senderTab.tab.id,
{
foo:bar
});
Run Code Online (Sandbox Code Playgroud)
在我的后台脚本中senderTab.tab.id,onMessageListener中的"sender"在哪里.
在<iframe />由我的内容脚本注入的JavaScript中,我有类似的东西:
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log("received in iframe:", request);
}
});
Run Code Online (Sandbox Code Playgroud)
在<iframe />完全按预期接收该消息.
我在我的脑中放了相同的JavaScript page_action.js,但它没有从后台脚本接收任何数据.chrome.pageAction.show(senderTab.tab.id);在调用之前激活pageActionchrome.tabs.sendMessage(senderTab.tab.id ...
附加到我的pageAction的HTML页面是不是同一个标签的一部分吗?由于这tabId使我能够激活/"显示"图标,我认为用于pageAction的JavaScript中的监听器也应该从chrome.tabs.sendMessage(senderTab.tab.id ...
在我的内容脚本中,我使用以下内容将数据发送到后台脚本:
chrome.runtime.sendMessage({
foo: bar
});
Run Code Online (Sandbox Code Playgroud)
当内容脚本发送上述消息时,pageAction JavaScript正在拾取它.
如何获取后台脚本以正确地将数据发送到我的pageAction?我不希望有pageAction请求/轮询,而是希望pageAction只是监听和接收.例如,如果它显示的是pageAction HTML,它应该能够在后台页面进行更改时实时更新.
Mak*_*yen 12
在后台环境中打开的页面包括:
background页面始终保持加载状态.)使用(MDN)不会向其中任何一个发送消息.您需要使用(MDN)向它们发送消息.除背景页面和事件页面外,其中任何一个的范围仅在显示时才存在.显然,当代码不存在时,您无法与代码进行通信.范围存在时,您可以使用以下方式与其中任何一个进行通信:tabs.sendMessage()runtime.sendMessage()
Directly
From the background context, you can directly change variables, or call functions, in another page that is also in the background context (i.e. not content scripts), after having gotten a reference to its global scope, its Window, using extension.getViews()(MDN), extension.getBackgroundPage()(MDN), or other method(MDN).
For example, you can call a function created with function myFunction in the page of the first returned view by using something like:
winViews = chrome.extension.getViews();
winViews[0].myFunction(foo);
Run Code Online (Sandbox Code Playgroud)
It should be noted that in your callback from tabs.create()(MDN) or windows.create()(MDN) the view for the newly opened tab or window will probably not yet exist. You will need to use some methodology to wait for the view to exist.2 See below for recommended ways to communicate with newly opened tabs or windows.
Directly manipulating values in the other page's scope allows you to communicate any type of data you desire.
Messaging
Receive messages using chrome.runtime.onMessage(MDN), 3 which were sent with chrome.runtime.sendMessage()(MDN). Each time you receive a message in a runtime.onMessage listener, there will be a sendResponse function provided as the third argument which allows you to directly respond to the message. If the original sender has not supplied a callback to receive such a response in their call to chrome.runtime.sendMessage(), then the response is lost. If using Promises (e.g. browser.runtime.sendMessage() in Firefox), the response is passed as an argument when the Promise is fulfilled. If you want to send the response asynchronously, you will need to return true; from your runtime.onMessage listener.
Ports
You can also connect ports, using chrome.runtime.connect()(MDN) and chrome.runtime.onConnect(MDN) for longer term messaging.
Use chrome.tabs.sendMessage() to send to content scripts
If you want to send from the background context (e.g. background script or popup) to a content script you would use chrome.tabs.sendMessage()/chrome.runtime.onMessage, or connect port(s) using chrome.tabs.connect()(MDN)/chrome.runtime.onConnect.
JSON-serializable data only
Using messaging, you can only pass data which is JSON-serializable.
Messages are received by all scripts in the background, except the sender
Messages sent to the background context are received by all scripts in the background context which have registered a listener, except the script which sent it.3 There is no way to specify that it is only to be received by a specific script. Thus, if you have multiple potential recipients, you will need to create a way to be sure that the message received was intended for that script. The ways to do so usually rely on specific properties existing in the message (e.g. use a destination or recipient property to indicate what script is to receive it, or define that some type of messages are always for one recipient or another), or to differentiate based on the sender(MDN) supplied to the message handler (e.g. if messages from one sender are always only for a specific recipient). There is no set way to do this, you must choose/create a way to do it for use in your extension.
For a more detailed discussion of this issue, please see: Messages intended for one script in the background context are received by all
Data in a StorageArea
Store data to a StorageArea(MDN) and be notified of the change in other scripts using chrome.storage.onChanged(MDN). The storage.onChanged event can be listened to in both the background context and content scripts.
You can only store data which is JSON-serializable into a StorageArea.
Which method is best to use in any particular situation will depends on what you are wanting to communicate (type of data, state change, etc.), and to which portion, or portions, of your extension you are wanting to communicate from and to. For instance, if you want to communicate information which is not JSON-serializable, you would need to do so directly (i.e. not messaging or using a StorageArea). You can use multiple methods in the same extension.
None of the popups (e.g. browser action, or page action) are directly associated with the active tab. There is no concept of a shared or separate instance per tab. However, the user can open one popup in each Chrome window. If more than one popup is open (a maximum of one per Chrome window), then each is in a separate instance (separate scope; has its own Window), but are in the same context. When a popup is actually visible, it exists in the background context.
There is only ever one page action or browser action popup open at a time per Chrome window. The HTML file which will be open will be whichever one has been defined for the active tab of the current window and opened by the user by clicking on the page/browser action button. This can be assigned a different HTML document for different tabs by using chrome.browserAction.setPopup()(MDN), or chrome.pageAction.setPopup()(MDN), and specifying a tabId. The popup can/will be destroyed for multiple reasons, but definitely when another tab becomes the active tab in the window in which the popup is open.
However, any method of communication used will only communicate to the one(s) which is/are currently open, not ones which are not open. If popups are open for more than one Chrome window at a time, then they are separate instances, with their own scope (i.e. their own Window). You can think of this something like having the same web page open in more than one tab.
If you have a background script, the background script context is persistent across the entire instance of Chrome. If you do not have a background script the context may be created when needed (e.g. a popup is shown) and destroyed when no longer needed.
chrome.tabs.sendMessage() can not communicate to popupsAs mentioned above, even if the popup did exist, it will exist in the background context. Calling chrome.tabs.sendMessage() sends a message to content scripts injected into a tab/frame, not to the background context. Thus, it will not send a message to a non-content script like a popup.
Calling chrome.pageAction.show()(MDN) just causes the page action button to be shown. It does not cause any associated popup to be shown. If the popup/options page/other page is not actually being shown (not just the button), then its scope does not exist. When it does not exist, it, obviously, can not receive any message
Instead of the page action's ability to show()(MDN) or hide()(MDN) the button, browser actions can enable()(MDN) or disable()(MDN) the button.
You can use tabs.create()(MDN) or windows.create()(MDN) to open a tab or window containing an HTML page from within your extension. However, the callback for both of those API calls is executed prior to the page's DOM existing and thus prior to any JavaScript associated with the page existing. Thus, you can not immediately access the DOM created by the contents of that page, nor interact with the JavaScript for the page. Very specifically: no runtime.onMessage() listeners will have been added, so no messages sent at that time will be received by the newly opening page.
The best ways to resolve this issue are:
chrome.extension.getBackgroundPage() to read the data directly.storage.local(MDN). The opening page can then read it when its JavaScript is run. For example, you could use a key called messageToNewExtensionPage.runtime.sendMessage(), then initiate the transfer of the data from your newly opening page by sending a message from the that page's code to the source of the data (using runtime.sendMessage(), or tabs.sendMessage() for content script sources) requesting the data. The script with the data can then send the data back using the sendResponse(MDN) function provided by runtime.onMessage().There are multiple methods which you can use. Which way is best will depend on exactly what you are doing (e.g. when you need to access the view with respect to the code being executed in the view). A simple method would be just to poll waiting for the view to exist. The following code does that for opening a window:
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.
}
Run Code Online (Sandbox Code Playgroud)In Firefox versions prior to version 51, the runtime.onMessage listener will be called for messages sent from the same script (e.g. messages sent by the background script will also be received by the background script). In those versions of Firefox, if you unconditionally call runtime.sendMessage() from within a runtime.onMessage listener, you will set up an infi