Previously in MV2, this code setup was working when I inserted the javascript string to a created script element using text property/field and appending it to the webpage. In this javascript, I access the chrome storage api to update things needed for when the tab next triggers the onChanged message. I don't need this part of the storage data in the background page, just the content script. In MV2 I did NOT need a separate file, additional manifest declarations, and chrome runtime message passing...
However, now with MV3, this does not work anymore. Upon research/reading it is my understanding that this is no longer allowed to be done. But, lots of users noted a workaround by using another .js file and having that new .js file in the manifest under "web_accessible_resources". I did this, and copied all the javascript string text as needed to the new .js file. I then set the previously created script element src property/field to the new file. The problem I run into is this new .js file has no access to the chrome api. I cannot use chrome.tabs to send a message, or chrome.local.storage, as the chrome.tabs and chrome.local are undefined.
I did notice I that the chrome variable has access to the runtime. A little more research mentions I can send messages from the webpage, using "externally_connected" in the manifest. I then added the chrome.runtime.sendMessage(...) call in the correct place in the .js file, so that I could receive the message in the background.js page and act accordingly. I added the chrome.runtime.onMessageExternal.addListener(...) function to the background.js file, with a simple console.log(...) call to verify it works, but alas, the background.js page never receives the message.
I did add my extensionid to the chrome.runtime.sendMessage call from the new .js page (the one that is appended/injected into the webpage). I also tried matching my extensionid and "*" for the externally_connected property of the manifest. I also added multiple variations of the webpage urls/domains for the matches section of the externally_connected (the same urls/domains that my content_scripts match on and work).
The injected javascript file does get an "undefined" for the sendMessage response, and triggers the "receiving end has closed" error. Which I know all to well because of my next message.
To preface, in the past 6 months I have mostly eliminated all the previous "sendMessage" and onMessage.* calls and replaced it with the port system. I also tried passing the port through to the injected javascript (stringifying the port with functions) and that does not work either.
These are the examples I've been following:
https://developer.chrome.com/docs/extensions/mv3/manifest/externally_connectable/https://stackoverflow.com/questions/18124500/using-externally-connectable-to-send-data-from-www-to-chrome-extensionSnippets of my manifest (the example2 urls aren't needed, that's what the website was before example1 urls - these are the same as the matches in my content_scripts section):
"web_accessible_resources": [
{
"resources": [ "injected_scripts.js" ],
"matches": [ "<all_urls>" ]
}
],
"externally_connectable": {
"ids": [
"*"
],
"matches": [
"
https://example1.com/*",
"
https://example2.2.com/*",
"
http://example2.2.com/*",
"
https://example1.com/exact/url"
]
}
Webpage javascript injection (which happens on above exact url):
var newJS = document.createElement('script');
newJS.src = chrome.runtime.getURL('/injected_scripts.js');
newJS.onload = function() {
console.log('injected_scripts.js loaded...');
};
if(document.head) {
document.head.appendChild(newJS);
} else if(document.documentElement) {
document.documentElement.appendChild(newJS);
}
Injected javascript (inside one of the functions):
chrome.runtime.sendMessage('extensionID', {action: 'test'}, function(response) { console.log(response); });
And finally background.js:
chrome.runtime.onMessageExternal.addListener(function(request, sender, sendResponse) {
console.log('background.js (onMessageExternal)...');
}