I am trying to migrate my browser extension to manifest version 3 but I am not able to access some properties from chrome.runtime in my service_worker. Code explains more than words I guess.
My background.js file:
function call() {
console.log({ runtime: chrome.runtime })
chrome.runtime.getPackageDirectoryEntry(() => null)
}
// putting it to timeout otherwise I couldn't access the logs page
setTimeout(() => {
call()
}, 0)
My manifest:
{
"manifest_version": 3,
"name": "Test",
"version": "0.0.0",
"background": {
"service_worker": "background.js"
}
}
When I open service worker page I can see
Uncaught TypeError: chrome.runtime.getPackageDirectoryEntry is not a function
The same code works with v2:
{
"manifest_version": 2,
"name": "Test",
"version": "0.0.0",
"background": {
"scripts": ["backgroud.js"]
}
}
The method I am trying to use is documented here but it is clearly missing in the runtime object (with plenty of others...)
Related
My extension currently uses the [esc] key to perform an action.
This is done in the content-script, using addEventListener('keydown').
I'd like the user to be able to choose a different shortcut.
I've updated to Manifest V3, and added a new "commands" key, i.e.
{
...
"manifest_version": 3,
"background": {
"service_worker": "background.js"
},
"content_scripts": [ {
"js": [ "screenshot.js" ],
"matches": [ "http://*/*", "https://*/*" ]
}],
"commands": {
"stop-animations": {
"description": "Stop Animations"
}
}
}
I've updated background.js to use chrome.commands.onCommand, and this works well.
But, how can I get my content-script to determine if the user has set their own shortcut?
Because I should not listen to the 'keydown' event to check if they have pressed the [esc] key.
I've tried using chrome.commands.getAll(), but this method is only available at install time.
A partial option would be to use something like browser.storage to set a simple boolean "custom-command-set" to true whenever onCommand is used, but I cannot think of a way to switch it off again if the user deletes the shortcut command (i.e. they want to go back to using the [esc] key).
At the moment I don't have a toolbar icon (action default_popup), or any other UI, and I'd prefer to not add one just to provide a custom way to set the shortcut.
Content scripts can't call chrome.commands.getAll() directly, so they need to send a message to the service worker. The SW calls chrome.commands.getAll() and sends the result back to the content script.
manifest.json
{
"manifest_version": 3,
"name": "chrome.commands.getAll",
"version": "1.0.0",
"background": {
"service_worker": "background.js"
},
"content_scripts": [
{
"js": [ "content_script.js" ],
"matches": [ "*://*/*" ]
}
],
"commands": {
"test": {
"description": "Test"
}
},
"permissions": ["commands"]
}
background.js
function commands_on_command(command) {
console.log("on_command", command);
}
function runtime_on_message(message, sender, sendResponse) {
if (message == "get_all_commands") {
chrome.commands.getAll()
.then(commands => {
console.log("background.js", "runtime_on_message", commands);
sendResponse(commands);
});
return true; // https://developer.chrome.com/docs/extensions/mv3/messaging/#simple
}
else {
console.log("background.js", "runtime_on_message", "unknown command");
sendResponse("unknown command");
}
}
chrome.commands.onCommand.addListener(commands_on_command);
chrome.runtime.onMessage.addListener(runtime_on_message);
content_script.js
(async () => {
let response = await chrome.runtime.sendMessage("get_all_commands");
console.log("content_script.js", response);
})();
I have written a simple extension just to learn how it works.
Manifest V3:
{ "name": "Sample",
"version": "1.0",
"manifest_version": 3,
"action": {
"default_name": "Sample",
"default_popup": "popup.html"
},
"background": {
"service_worker": "background.js"
},
"permissions": ["tabs", "storage", "activeTab", "clipboardRead", "scripting"],
"host_permissions": ["http://*/", "file://*/*", "https://*/", "*://*/*"]
}
popup.html:
.....
.....
<button id='getInfo' >GET</button>
.....
.....
popup.js:
....
document.getElementById("getInfo").addEventListener("click", function() {
chrome.tabs.query(
{active: true, currentWindow: true},
(tabs) => {
chrome.scripting.executeScript({
target: {tabId: tabs[0].id},
file: ['func.js'],
});
});
}
func.js:
alert("extension sample")
When i press the button 'GET' i receive an error in extension manager page.
The error says: "Error handling response: TypeError: Error in invocation of scripting.executeScript(scripting.ScriptInjection injection, optional function callback): Error at parameter 'injection': Unexpected property: 'file'."
I have tried with function instead of the file and it works.
How i can fix this error? Thank you.
chrome.scripting.executeScript does not have file property.
You should use files property.
Search for "executeScript" in the official Google documentation below to see the sample.
https://developer.chrome.com/docs/extensions/reference/scripting/
I am migrating my chrome extension from manifest version 2 to 3.
There is a problem in injecting the file with the click of the extension icon.
Manifest.json
{
"manifest_version": 3,
"name": "Name of Extension",
"description": "description",
"version": "1.0.0",
"background": {
"service_worker": "background.js"
},
"permissions": [
"activeTab",
"scripting"
]
}
Background.js - Manifest version 3 ( This code is not working )
chrome.action.onClicked.addListener(function() {
chrome.scripting.executeScript({
files: ['"function.js"']
});
});
background.js - Manifest version 2
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(tab.id, {file: "function.js"});
});
Use tab parameter as described in the documentation for onClicked
Specify tab's id as described in the documentation for executeScript
Remove the nested quotes in the file name
chrome.action.onClicked.addListener(tab => {
chrome.scripting.executeScript({
target: {tabId: tab.id},
files: ['function.js'],
});
});
Following Chrome Extension Manifest V3 rule I want to create an extension, that listens to particular network request and, for startes, just log them to the console of the currently opened tab (later I want to add custom script and styles to the page in the current tab).
For this I try to utilize chrome.scripting.executeScript.
When I implement the sample from https://github.com/GoogleChrome/chrome-extensions-samples/blob/main/examples/page-redder/manifest.json it works like expected for the chrome.action.onClicked listener.
As soon as I try to execute a script within the chrome.webRequest.onBeforeRequest listener, this error pops up:
Error in event handler: TypeError: Error in invocation of
scripting.executeScript(scripting.ScriptInjection injection, optional
function callback): Error at parameter 'injection': Error at property
'target': Missing required property 'tabId'.
at chrome.webRequest.onBeforeRequest.addListener.urls ()
Missing required property tabId? I assume it has to do with the lifecycle, but I cannot figure out what to do. This is my manifest:
{
"name": "Getting Started Example",
"description": "Build an Extension!",
"version": "1.0",
"manifest_version": 3,
"background": {
"service_worker": "background.js",
"matches": [ "<all_urls>"]
},
"host_permissions": [
"<all_urls>"
],
"permissions": [
"activeTab",
"tabs",
"webRequest",
"webNavigation",
"management",
"scripting"
]
}
And this is my script, I just slightly modified the "redden"-example:
function reddenPage(url) {
console.log(url);
}
chrome.webRequest.onBeforeRequest.addListener((tab) => {
chrome.scripting.executeScript({
target: { tabId: tab.id },
function: reddenPage,
args: [tab.url],
});
},
{urls: ["*://*.google.com/*"]},
[]);
I don't know exactly why, but the script from Github seems not work. This is how it works:
It's not only a couple of changed brackets, look at tab instead of (tab), but also tab.tabId instead of tab.id:
chrome.webRequest.onBeforeRequest.addListener(tab => {
chrome.scripting.executeScript(
{
target: { tabId: tab.tabId },
function: reddenPage,
args: [details.url],
},
() => { console.log('ZZZ') });
}, {
urls: ['<all_urls>']
});
I have created an extension that uses the executescript api to inject a piece of code (shown below) that basically on window.onbeforeunload confirms they want to close the page. I have the script working, and by using the file://*/* permission, got it to inject on file URLs. However, when testing it on a flash game I downloaded, the script didn't inject. The URL was externalfile:drive-randomtext/root/SWFNAME.swf. I tried adding externalfile://*/* in the permissions but got the following error message: There were warnings when trying to install this extension: Permission 'externalfile://*/*' is unknown or URL pattern is malformed. Is there an external file permission, or another way to do this?
Manifest.json:
{
"name": "name",
"short_name": "name",
"version": "3.6",
"manifest_version": 2,
"description": "Desc",
"permissions": [
"storage",
"http://*/",
"https://*/",
"tabs",
"activeTab",
"webNavigation",
"*://*/*",
"file://*/*"
],
"page_action": {
"default_icon": "logo.png"
},
"background": {
"scripts": ["disabled.js"]
}
}
Script that gets executed:
(hotkey-binding code too long, can be found here)
Mousetrap.bind('ctrl+m', function(e) {
window.onbeforeunload = confirmExit;function confirmExit(){alert('confirm exit is being called');return'Close page?';}
alert('Enabled');
return false;
});
Mousetrap.bind('ctrl+q', function(e) {
location.reload();
return false;
});