Chrome Extension Message Passing: Response Not Sent

Chrome Extension Message passing: response not sent

From the documentation for chrome.runtime.onMessage.addListener:

This function becomes invalid when the event listener returns, unless you return true from the event listener to indicate you wish to send a response asynchronously (this will keep the message channel open to the other end until sendResponse is called).

So you just need to add return true; after the call to getUrls to indicate that you'll call the response function asynchronously.

Chrome extension message passing is not working?

Iván Nokonoko answered the problem above in comments. Posting it here for brevity -

background.js

var hasExecutedOnce = false

function addUI(tabId) {
chrome.tabs.sendMessage(tabId, {
from: 'background',
subject: 'isUIAdded?',
})
}

chrome.browserAction.onClicked.addListener(function(tab) {
if (!hasExecutedOnce) {
chrome.tabs.executeScript(
tab.id,
{
file: 'contentScript.js',
},
function() {
addUI(tab.id)
},
)
hasExecutedOnce = true
}
addUI(tab.id)
})

manifest.json

{
"manifest_version": 2,
"name": "Sample",
"version": "1.0.0",
"description": "Sample Extension",
"icons": {
"16": "icon16.png",
"19": "icon19.png",
"24": "icon24.png",
"32": "icon32.png",
"38": "icon38.png",
"48": "icon48.png",
"64": "icon64.png",
"128": "icon128.png"
},
"background": {
"scripts": ["background.js"],
"persistent": false
},
"browser_action": {
"default_icon": {
"19": "icon19.png",
"38": "icon38.png"
}
},
"permissions": ["activeTab", "<all_urls>"]
}

contentScript.js

var body = document.getElementsByTagName('body')[0]

function insertUI() {
var div = document.createElement('div')
div.setAttribute('id', 'sample-extension-12345')
div.innerHTML = `<h1>Sample Extension</h1>`
body.appendChild(div)
}

function removeUI() {
document.getElementById('sample-extension-12345').remove()
}

function main() {
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.subject === 'isUIAdded?') {
const id = document.getElementById('sample-extension-12345')
if (id === null) insertUI()
else removeUI()
}
})
}

main()

Chrome Extension message not sending response (undefined)

For future reference: I solved this by switching the onMessage/sendMessage to the background script and the content script, respectively. I'm not sure why this worked, but it did.

chrome extension message passing no response-farewell: undefined

The popup does not exist while it's closed.

As such, at the moment when message is sent there is likely no-one listening, so the callback called with undefined as response (and with chrome.runtime.lastError set).

From an architecture standpoint, the background page is the one always available to process a message; as such, onMessage listeners are, in most (not all) cases better off in there.

I would recommend taking a look at this question as well, where I explain some concepts in more detail: Pass a variable from content script to popup.

Also, just in case, all this greeting-goodbye sample code is just an example; you can pass anything JSON-serializable.

Chrome extension message passing not working (background.js to content.js)

Your current background script is wrong or rather doesn't do anything meaningful/useful. The background script runs in a separate hidden background page (or a service worker in ManifestV3). See also Accessing console and devtools of extension's background.js.

A background script runs when a) the browser profile starts, b) when the extension is re-enabled/re-loaded, or c) installed/updated. So, your code immediately queries the tabs and sends a message to whatever tab is active, hence there's no guarantee it even contains a web page: there can be nothing (an empty new tab) or it can be an internal chrome:// page for browser settings or the tab may still be pending content script execution (see the note at the end of this answer).

Note for ManifestV2 extensions: switching the background script to "persistent": false won't help you either. It will only make the script wake up on an API event or when the popup is opened, but you're not registering any API events nor have you declared a popup. You should switch to "persistent": false anyway but for a different reason: to have it running only on demand.

Solution

The usual purpose of the background script is to register handlers for chrome API events such as chrome.tabs.onUpdated or chrome.webNavigation.onHistoryStateUpdated and so on, otherwise it's highly probable you don't need the background script at all. In the event handler you can send a message to the tab using chrome.tabs.sendMessage or chrome.tabs.connect with this tab's id. A lot of people mistakenly send it to the active tab but usually it doesn't make sense as the event may have occurred in an inactive/backgrounded tab. Usually you should send it to the tab that generated the event, look for tab or tabId in the parameter passed to the handler, refer to the documentation on those events.

Also note that the content scripts run after DOMContentLoaded by default so if you send a message while the page is still loading it'll fail. In that case you can either run them at document_start or use a different approach e.g. don't declare a content script but rather inject it programmatically. There's no universal answer, it depends on the use case.

If you really need to send a message to the content script on extension startup/restart then you'll have to reload all matching tabs first via chrome.tabs.reload (so the content scripts will run automatically) or reinject the scripts explicitly.

Chrome Extension: Message Passing from Content to Background Script

Currently you're injecting code in page context which is both an unnecessary overcomplication and wrong as you inject the background script which already runs in the hidden separate background page of the extension that's not related to the web page. See how to open background.js devtools and console.

Remove script_injection.js, injection_ui.js and web_accessible_resources section and unnecessary permissions from manifest.json as well as jquery.js.

Declare parameters of onMessage listener correctly per the documentation.

Use "persistent": false, more info.

{
"name": "Dummy Extension",
"version": "1.0",
"manifest_version": 2,
"description": "This is a dummy extension.",
"browser_action": {
"default_title": "Download Images from Anywhere",
"default_popup": "popup.html"
},
"content_scripts": [{
"matches": ["https://dummywebsite.com/*"],
"js": ["content.js"],
"css": ["style.css"]
}],
"permissions": [
"storage",
"downloads"
],
"background": {
"scripts": ["background.js"],
"persistent": false
}
}

Let's use a standard name content.js with standard JS inside, no jquery. If you still want jquery, then declare it in manifest.json as "js": ["jquery.js", "content.js"]

content.js:

for (const thumb of document.querySelectorAll('.image-thumbnail')) {
thumb.appendChild(Object.assign(document.createElement('button'), {
className: 'DummyAddedButton',
textContent: 'Download',
}));
}

document.addEventListener('click', e => {
if (e.target.matches('.DummyAddedButton')) {
chrome.runtime.sendMessage(e.target.closest('.image-thumbnail').src);
}
});

background.js:

chrome.runtime.onMessage.addListener((message, sender, sendMessage) => {
chrome.downloads.download({url: message, filename: 'image.jpg'});
});

Don't forget to reload the extension on chrome://extensions page and the web page tab after you edit manifest.json or the content scripts.



Related Topics



Leave a reply



Submit