I'm using browser.scripting.executeScript()
and i need to send a message to webext background script/service worker script. Usually it means using browser.runtime.sendMessage()
, but browser
is reportedly undefined in anomymous script. I can pass browser
as call script argument, but i believe it will be serialized and i'm not sure it survives the boundary passing.
Here is the code:
await browser.scripting.executeScript({
target: details,
world: "MAIN",
injectImmediately: true,
args: [tabId, frameId],
func: (tabId, frameId) => {
if (window.history.__pushState) {
console.warn("Already injected");
return;
}
window.history.__pushState = history.pushState;
console.log("Injected pushState()");
history.pushState = function(state, unused, url) {
// eslint-disable-next-line no-console
console.log("Intercepted pushState()", state, unused, url);
window.history.__pushState(state, unused, url);
console.log("debug", browser); // `browser` is undefined
browser.runtime.sendMessage({
type: "safari-onhistorystateupdated",
state, unused, url
});
};
}
});
How can i access browser
object in such anonymous script?
I was able to solve it by sending message from anonymous script to `window`:
window.postMessage({
type: "safari-onhistorystateupdated-content",
state, unused, url
});
And listening in window with injected content-script and resending it to webext background script:
window.addEventListener("message", (event) => {
if (!event.isTrusted)
return;
if (event && event.data && event.data.type === "safari-onhistorystateupdated-content") {
let {state, unused, url} = event.data;
browser.runtime.sendMessage({
type: "safari-onhistorystateupdated",
state, unused, url
});
}
},
false
);
Bg script was listening it:
async function handleMessage(message, sender) {
switch (message.type) {
...
case "safari-onhistorystateupdated":
const {state, unused, url} = message;
handleOnHistoryStateUpdated(
sender.tab.id, sender.frameId, state, unused, url);
break;
...
}
}
function onMessage(message, sender) {
if (typeof message == "object" && message != null && message.type) {
return handleMessage(message, sender);
}
return false;
}
...
browser.runtime.onMessage.addListener(onMessage);