The messaging between the contents of the script and the background page in the chrome extension does not work, as it should be

Post the following code:

manifest.json

{ "manifest_version": 2, "name": "Demo", "description": "all_frames test", "version": "1.0", "background": { "scripts": ["background.js"] }, "content_scripts": [{ "matches": ["*://*/*"], "js": ["content.js"], "all_frames": true }], "permissions": [ "tabs", "*://*/*" ] } 

background.js

 chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) { var tabStatus = changeInfo.status; if (tabStatus == 'complete') { function return_msg_callback() { console.log('Got a msg from cs...') } chrome.tabs.sendMessage(tabId, { text: 'hey_cs' }, return_msg_callback); } }); 

content.js

 /* Listen for messages */ chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) { /* If the received message has the expected format... */ if (msg.text && (msg.text == 'hey_cs')) { console.log('Received a msg from bp...') sendResponse('hey_bp'); } }); 

Then, if I go to a site that includes multi-line iFrames with cross-starting, for example http://www.sport.es/ , you will see that all iFrames within the page receive a message from the background page, but only one of them may respond back. Is this normal behavior?

Thanks in advance for your reply.

+5
source share
3 answers

You send only one message with a direct callback, so naturally, Chrome can use this response callback only once (this is a one-time connection to one object, whether it be a page or iframe).

  • Solution 1 : send multiple messages to each iframe explicitly:

    manifest.json, additional permissions:

     "permissions": [ "webNavigation" ], 

    background.js

     chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) { ............. // before Chrome 49 it was chrome.webNavigation.getAllFrames(tabId, ..... // starting with Chrome 49 tabId is passed inside an object chrome.webNavigation.getAllFrames({tabId: tabId}, function(details) { details.forEach(function(frame) { chrome.tabs.sendMessage( tabId, {text: 'hey_cs'}, {frameId: frame.frameId}, function(response) { console.log(response) } ); }); }); }); 
  • Solution 2 : rework your background script logic so that the script content is leading in communication and allows it to send a message after loading it.

    content.js

     chrome.runtime.sendMessage({text: "hey"}, function(response) { console.log("Response: ", response); }); 

    background.js

     chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) { console.log("Received %o from %o, frame", msg, sender.tab, sender.frameId); sendResponse("Gotcha!"); }); 
+12
source

Instead of messaging, you can use executeScript for your purposes. Although the callback argument is rarely used (and I don’t think many people know how it works), it is perfect:

 chrome.tabs.executeScript(tabId, {file: "script.js"}, function(results) { // Whichever is returned by the last executed statement of script.js // is considered a result. // "results" is an Array of all results - collected from all frames }) 

You can verify, for example, that the last statement executed looks like

 // script.js /* ... */ result = { someFrameIdentifier: ..., data: ...}; // Note: you shouldn't do a "return" statement - it'll be an error, // since it not a function call. It just needs to evaluate to what you want. 

Make sure script.js can be executed multiple times in the same context.

For frame id, you can develop your own algorithm. Maybe the url is enough, maybe you can use the position of the frame in the hierarchy .

+3
source

Here's a clear way to bidirectionally communicate in the Chrome extension [Contents ⬄ Background]:

Inside Content Script:

Sends information to the background:

 chrome.extension.sendRequest({message: contentScriptMessage}); 

Gets information from the background:

 chrome.runtime.onMessage.addListener(function(request, sender) { console.log(request.message); }); 




Inner background script:

Sends information to the content script:

 chrome.extension.onRequest.addListener(function(request, sender) { console.log(request.message); }); 

Retrieves information from a content script:

 chrome.tabs.getSelected(null, function(tab) { chrome.tabs.sendMessage(tab.id, { message: "TEST" }); }); 
0
source

Source: https://habr.com/ru/post/1232248/


All Articles