I'm using a Firefox WebExtension that makes the link between a web page and a native executable (using native messaging API).
So far, I've been using a pair of content / background scripts, and I send / receive messages using window.PostMessage
like this:
Page Script
// Method used to municate with content sript of the Firefox WebExtension
var callExtension = function(JSONmessage, timeout, callbackFnk) {
var promiseRequest = new Promise((resolve, reject) => {
const listener = (event) => {
if (
event.source == window && event.data.direction
&& event.data.direction == "my-extension-from-content-script"
) {
resolve(event.data.message);
}
}
setTimeout(() => {
window.removeEventListener("message", listener);
resolve(false); // Timeout
}, timeout);
window.addEventListener("message", listener);
window.postMessage({
direction: "my-extension-from-page-script",
message: JSONmessage
}, "*");
});
promiseRequest.then((result) => {
// now we are calling our own callback function
if(typeof callbackFnk == 'function'){
callbackFnk.call(this, result);
}
});
};
// Checks the presence of the extension
callExtension("areYouThere", 200, function(result) {
if(result) {
$("#result").text("Extension installed");
} else {
$("#result").text("Extension not installed");
}
});
Content Script
window.addEventListener("message", function(event) {
if (event.source == window &&
event.data.direction &&
event.data.direction == "my-extension-from-page-script") {
if(event.data.message == "areYouThere") {
/** Checks the presence of the extension **/
window.postMessage({
direction: "my-extension-from-content-script",
message: "OK"
}, "*");
}
}
});
The code works fine on a simple web page, but when I try to make it work on a page that already uses a window.postMessage
and window.addEventListener ("message", ...)
, the message sent from the page is not captured by the extension, and so my extension cannot work.
Is there a way to send a message from the page script to the content script that does not use
window.postMessage
andwindow.addEventListener
?If not, how to be sure the message that is sent from
window.postMessage
from the page will be sent only to my extension and will not be captured by another listener?
I'm using a Firefox WebExtension that makes the link between a web page and a native executable (using native messaging API).
So far, I've been using a pair of content / background scripts, and I send / receive messages using window.PostMessage
like this:
Page Script
// Method used to municate with content sript of the Firefox WebExtension
var callExtension = function(JSONmessage, timeout, callbackFnk) {
var promiseRequest = new Promise((resolve, reject) => {
const listener = (event) => {
if (
event.source == window && event.data.direction
&& event.data.direction == "my-extension-from-content-script"
) {
resolve(event.data.message);
}
}
setTimeout(() => {
window.removeEventListener("message", listener);
resolve(false); // Timeout
}, timeout);
window.addEventListener("message", listener);
window.postMessage({
direction: "my-extension-from-page-script",
message: JSONmessage
}, "*");
});
promiseRequest.then((result) => {
// now we are calling our own callback function
if(typeof callbackFnk == 'function'){
callbackFnk.call(this, result);
}
});
};
// Checks the presence of the extension
callExtension("areYouThere", 200, function(result) {
if(result) {
$("#result").text("Extension installed");
} else {
$("#result").text("Extension not installed");
}
});
Content Script
window.addEventListener("message", function(event) {
if (event.source == window &&
event.data.direction &&
event.data.direction == "my-extension-from-page-script") {
if(event.data.message == "areYouThere") {
/** Checks the presence of the extension **/
window.postMessage({
direction: "my-extension-from-content-script",
message: "OK"
}, "*");
}
}
});
The code works fine on a simple web page, but when I try to make it work on a page that already uses a window.postMessage
and window.addEventListener ("message", ...)
, the message sent from the page is not captured by the extension, and so my extension cannot work.
Is there a way to send a message from the page script to the content script that does not use
window.postMessage
andwindow.addEventListener
?If not, how to be sure the message that is sent from
window.postMessage
from the page will be sent only to my extension and will not be captured by another listener?
- To be able to answer this (without just guessing as to why it is occurring), we are going to need a plete minimal reproducible example (including a manifset.json file) along with the actual URL on which you are trying to acplish this and it is failing. – Makyen ♦ Commented Mar 10, 2017 at 17:00
2 Answers
Reset to default 3It appears that the web page that you are working with is not playing nice with window.postMessage
. This is understandable, as such a web page would normally be expecting to be the only thing using it in the page.
You have four alternatives:
- Install your
message
event listener on thewindow
before the web page scritps install any listeners so that you receive the event first. This will most likely be done by injecting atdocument_start
and installing your listener prior to the scripts for the page being loaded. In addition to your call to.addEventListener()
being prior to any script on the page acting (i.e. injecting atdocument_start
), you should indicate that your listener willuseCapture
. This will cause your listener to be called prior to any listener added by page scripts. You will need to uniquely identify in the message content that messages are to/from your extension code. You will need to cancel the event (.stopImmediatePropagation()
and.stopPropagation()
) for those messages which are yours, and allow the event to propagate for those that are not. - Use a custom event just for your extension.
- Directly manipulate variables/functions and/or call functions in the page context by inserting additional
<script>
elements. - Dynamically change the code of the web page's scripts so they play nice. This will only work on a single page/domain and could easily break if the web page changes its code. While possible, this is not a good option.
Export a function from your content script, and then can call that from the page.
Content Script
var myContentScriptFunction = function(myVariable) {
alert(myVariable);
}
exportFunction(myContentScriptFunction, window, {defineAs: 'myContentScriptFunction'});
Page Script
if (window.myContentScriptFunction) window.myContentScriptFunction('Working');