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
How to Disable Scrolling Temporarily
React Setstate Not Updating State
Uploading Both Data and Files in One Form Using Ajax
Remove Accents/Diacritics in a String in JavaScript
What Are Valid Date Time Strings in JavaScript
How to Check If an Element Is Hidden in Jquery
How to Efficiently Count the Number of Keys/Properties of an Object in JavaScript
++Somevariable Vs. Somevariable++ in JavaScript
Query-String Encoding of a JavaScript Object
JavaScript Variable Number of Arguments to Function
How to Add Dynamically Named Properties to JavaScript Object
How to Completely Uninstall Node.Js, and Reinstall from Beginning (Mac Os X)
Origin Is Not Allowed by Access-Control-Allow-Origin
Get JavaScript Object from Array of Objects by Value of Property
Set a Default Parameter Value For a JavaScript Function