Reputation: 95
I'm making my first chrome extension and noticed that messages being sent from my popup.html page were getting duplicated in my content.js message event listener. I've console logged "sending message" before every message send and "message received" before every message, and I don't understand how the messages are being duplicated. I've also checked the chrome dev docs for sendMessage and onMessage and it specifies that the onMessage listener should only be fired once per sendMessage event.
Any help would be appreciated.
popup.html
<!DOCTYPE html>
<html>
<head>
<title>Messaging Practice</title>
</head>
<body>
<h1>Messaging Practice</h1>
<input type="button" id="send-message" value="Button">
<script src="popup.js"></script>
</body>
</html>
content.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log('message received')
console.log(request);
}
);
popup.js
var messageButton = document.querySelector("#send-message");
messageButton.onclick = function() {
chrome.tabs.query({currentWindow: true, active: true},
function(tabs) {
chrome.tabs.executeScript(
tabs[0].id, {file: "content.js"}
)
console.log("sending message")
chrome.tabs.sendMessage(tabs[0].id, "string message")
});
}
background.js
chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
chrome.declarativeContent.onPageChanged.addRules([{
conditions: [new chrome.declarativeContent.PageStateMatcher({
pageUrl: {hostEquals: 'stackoverflow.com'},
})],
actions: [new chrome.declarativeContent.ShowPageAction()]
}]);
});
manifest.json
{
"name": "Send Messages Practice",
"version": "1.0",
"manifest_version": 2,
"description": "Simple messaging practice with the chrome api",
"permissions": ["declarativeContent", "activeTab"],
"background": {
"scripts": ["background.js"],
"persistant": true
},
"page_action": {
"default_popup": "popup.html",
"scripts": ["content.js"],
"matches": ["http://*/*","https://*/*"]
}
}
Upvotes: 6
Views: 4048
Reputation: 1241
I think this happens because the webpage into which you injected content.js
has iframes, to which content.js
will also be injected. To solve this, all you need to do is listen for messages only in the main window.
// Check if the current window is top-level and not in an iframe
if (window.self === window.top && window.frameElement === null) {
// listen to messages from background
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
// Handle the received message
});
}
Upvotes: 0
Reputation: 101
Please make sure to inject the script only once—the script that contains chrome.runtime.onMessage.addListener().
The mistake I was making was that every time I sent a message, I was also injecting the script repeatedly, like this:
ChromeService.execInActiveTab((tab) => {
// @ts-ignore
chrome.scripting.executeScript({
target: {tabId: tab.id},
files: ["assets/js/autofill.js"],
}, () => {
// @ts-ignore
chrome.tabs.sendMessage(tab.id, {setDropdownValue: {fieldId: fieldId, fieldValue: value}});
});
});
Simply separating the logic for script injection and message sending resolved the issue for me.
Upvotes: 0
Reputation: 41
Adding "return true;" to event handlers will prevent your code from firing again and again:
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
if (request.action == "show_alert") {
alert(request.alert);
return true;
}
});
Upvotes: 4
Reputation: 6033
Get the same problem when I run my extension with multiple frames. @Wayne Smallman solution works for me:
recommending that all_frames be set to false in the manifest file
Upvotes: 3