When running in test (reloading an unpacked extension), about 1 out of 5 times my event page's chrome.runtime object does not (yet) have the 'onInstalled' property.
// Cannot read property 'addListener' of undefined
chrome.runtime.onInstalled.addListener(...)
Feels like a race condition on startup within the extension container?
When the error throws, chrome.runtime only has the following:
{OnInstalledReason, OnRestartRequiredReason, PlatformArch,
PlatformNaclArch, PlatformOs, RequestUpdateCheckStatus, connect, sendMessage}
Try moving the event listener to a background script if they are in a content script. Content scripts have limited access to Chrome API. You can define it in the manifest. Then, if needed, you can send it from the background to a content script.
{
"manifest_version": 2,
"name": "someName",
"version": "0.0",
"description": ":D",
"content_scripts": [
{
"matches": ["https://*/*", "http://*/*"],
"js": ["content.js"]
}
],
"background":{
"scripts":["background.js"]
}
}
According to the linked Issue 601559, this was a bug in Chrome that was fixed in Chrome 51 (May 2016).
Related
I'm writing a Chrome extension that will redirect me to a URL when clicking on the browser action icon.
I'm trying to use:
chrome.browserAction.onClicked.addListener
but I get
Uncaught TypeError: Cannot read property 'onClicked' of undefined
This is my manifest file:
{
"name": "first extension",
"version": "2.2.12",
"description": "redirct to a link icon",
"browser_action": {
"default_icon": "icontest.png",
"default_title": "Do action"
},
"permissions": ["tabs", "http://*/*"],
"content_scripts": [{
"matches": ["http://*.twitter.com/*", "https://*.twitter.com/*"],
"js": ["twterland.js"]
}],
"icons": {
"16": "icontest.png",
"48": "icontest.png",
"128": "icontest.png"
}
}
This is my js file:
chrome.browserAction.onClicked.addListener(function(tab) { alert("hi"); });
ManifestV3
manifest.json: use action not browser_action, see also the migration guide.
"action": {},
"background": {"service_worker": "background.js"},
background.js: use chrome.action not chrome.browserAction.
Classic ManifestV2
For those who already have added something like
"background": {
"scripts": ["background.js"]
}
and still gets Cannot read property 'onClicked' of undefined - just add
"browser_action": {}
into your manifest.json
It seems like the code is in your twterland.js file, which is your content script. browserAction can only be used in extension pages, so you can not use it in content scripts.
Document: https://developer.chrome.com/extensions/content_scripts
However, content scripts have some limitations. They cannot:
- Use chrome.* APIs (except for parts of chrome.extension)
- Use variables or functions defined by their extension's pages
- Use variables or functions defined by web pages or by other content scripts
Put it on the background page instead.
If you do not have a "browser_action" property defined in your manifest.json then this error may occur. #Kirill's answer works but you also have to add a blank icon.png file else chrome will throw an error that it cannot find such a file.
Adding this to the manifest.json file should suppress this is error:
"browser_action": {}
Be sure to read the documentation for further reference on how to use the "browser_action" setting.
The same problem may appear if you are using manifest_version 3.
In this case
"background.scripts" should be replaced with "background.service_worker"
"browser_action" should be replaced with "action"
in js code chrome.browserAction should be replaced with chrome.action
detailed information could be found here: Manifest version 3 migration documentation
I was also getting this, adding
"persistent": true
to my background declaration in manifest.json solved it.
Please notice that you can heave only one of app, browser_action, page_actions present in your manifest.json file.
For example, to use the chrome.browserAction.setBadgeText you should have the browser_action field in your manifest.json.
Make sure we don't have jquery.js before background.js in the scripts array of background in manifest.json.
"background": {
"scripts": ["background.js","jquery.js"]
}
I added a simple background script to my Chrome extension.
My manifest.json file:
{
"name" : "Test extension",
"version" : "1.0",
"description" : "Test extension.",
"background" : {
"scripts": ["background.js"]
},
"devtools_page": "devtools.html",
"permissions": ["http://*/*", "https://*/*"],
"manifest_version": 2
}
I go to chrome://extensions and select background.js in Inspect views.
It opens devtools where I go to Sources and add a break point to my background.js:
function foo() {
return 5;
}
foo(); //break point here
Then a reload my extension in chrome://extensions.
Nothing happens. The breakpoint is not triggered.
Is my background script running at all?
SIMPLE ANSWER... I struggled with this for a while too...
Once you click background.html (or background.js), it will open in a SEPARATE debugger window. At that point, SIMPLY reload it by hitting the F5 or CTRL-F5 key(s) from the debugger window (while it is in focus).
NOTE: You MAY receive errors about recreating objects that already exist (since they were created when you first clicked on your page(or script)
In order to reload the backgroud page and still keeping your breakpoints, you should switch to console and enter:
window.location.reload();
An even better way: call chrome.runtime.reload() from the background's console, it's a documented call to reload.
I tested it and breakpoints fire.
I am trying to write a Chrome extension which detects process crashes.
First i went to about:flags page of Chrome and enabled "Experimental Extension APIs".
This is the extension I wrote:
manifest.json:
{
"manifest_version": 2,
"name": "CrashDetect",
"description": "Detects crashes in processes.",
"version": "1.0",
"permissions": [
"experimental","tabs"
],
"background": {
"scripts": ["background.js"]
}
}
backround.js:
chrome.experimental.processes.onExited.addListener(function(integer processId, integer exitType, integerexitCode) {
chrome.tabs.getCurrent(function(Tab tab) {
chrome.tabs.update(tab.id, {url:"http:\\127.0.0.1\""});
};)
});
Then I visited about://crash page of Chrome. But onExited listener does not execute.
Have I done anything wrong in manifest.json or background.js?
There a couple errors in your code. First you have the types of the parameters in the function declaration, change it to:
function(processId, exitType, integerexitCode){
Second, you put };) instead of });. Try inspecting the background page to see syntax errors.
Alright, after playing around with it some as I was unfamiliar with this particular API, I found that none of the events fired if I didn't include a handler for onUpdated. I really doubt that this is the intended behavior and I will check to see if there is a bug report on it. For now just do something like this to get it working:
chrome.experimental.processes.onUpdated.addListener(function(process){});
chrome.experimental.processes.onExited.addListener(function(processId, exitType, integerexitCode){
chrome.tabs.query({active:true, currentWindow:true},function(tabs){
chrome.tabs.update(tabs[0].id, {url:"http:\\127.0.0.1"});
});
});
Notice that I did swap out your getCurrent for a chrome.tabs.query as the former would have given you an error. This does lead to the behavior of if you close a tab, the next tab will be redirected. Perhaps you could try to filter by exitType and not include normal exits.
This has been bugging me and I can't figure out the solution.
"content_scripts": [
{
"matches": ["chrome-extension://_MSG_##extension_id/*"],
"js": ["contentscript.js"]
}
],
if i was to replace the "chrome-extensions://.." with a url such as http://google.com/* it will work.
I even tried fallowing the pattern on chrome develoeprs pag along with replacing extension id with the actual id.
I am basically trying to inject the content script into a local page "in the extension folder"
Sorry, but you aren't meant to be able to inject content scripts into other extensions. The docs are wrong, I have reported this issue while ago.
Well I have a list of domains (about 10) which my chrome extension is going to interact with.
As I studied the chrome extensions documentation this needs to use content_scripts
I have included these lines in the manifest.json
"content_scripts": [ {
"all_frames": true,
"js": [ "js/main.js" ],
"matches": [ "http://domain1.com/*",
"http://domain2.com/*",
"http://domain3.com/*",
"http://domain4.com/*",
"http://domain5.com/*",
"http://domain6.com/*",
"http://domain7.com/*",
"http://domain8.com/*",
"http://domain9.com/*",
"http://domain10.com/*"
],
"run_at": "document_start"
}],
This means that during loading every page that the url matches the defined url's in the manifest file, then the main.js will be injected to the page. Am I right? yes.
So I want to do some UI when the script is injected through page action
I included these lines to the manifest:
"page_action": {
"default_icon": "images/pa.png",
"default_title": "This in one of that 10 domains, that is why I showed up!"
},
It seems that it is not enough. and I have to manually trigger the page action.
but where ?
I realized that for this purpose I would need a background.html file.
but Why I can not include the trigger at the same main.js file?
answer:
However, content scripts have some limitations. They **cannot**:
- Use chrome.* APIs (except for parts of chrome.extension)
- Use variables or functions defined by their extension's pages
- Use variables or functions defined by web pages or by other content scripts
So included it in the manifest:
"background_page": "background.html"
and this is the content:
<html>
<head>
<script>
function check (tab_id , data , tab){
//test just one domain to be simple
if (tab.url.indexOf('domain1.com') > -1){
chrome.pageAction.show(tab_id);
};
};
chrome.tabs.onUpdated.addListener(check);
</script>
</head>
</html>
Fair enough until here,
What I want and I don't know is how to add the ability of toggle on/off the extension.
User clicks on the page action icon -> the icon changes and turns off/on (the main.js would act different)
Instead of adding the content script through the manifest, you can also use the chrome.tabs.onUpdated in conjunction with chrome.tabs.executeScript:
// Example:
var url_pattern = /^http:\/\/(domain1|domain2|domain3|etc)\//i;
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if (url_pattern.test(tab.url)) {
if (changeInfo.status === 'complete') { // Or 'loading'
chrome.tabs.executeScript(tabId, {'file':'main.js'});
chrome.pageAction.show(tabId);
}
} else {
chrome.pageAction.hide(tabId);
}
});
Do not forget to check for the value changeInfo.status, because otherwise, the content script will be executed twice.
In one of these if-statements, you can incorporate a check whether the extension is active or not, and act upon it:
if (changeInfo.status === 'complete' && am_I_active_questionmark) ...
Side not: Instead of using background_page, you can also use "background": {"scripts":["bg.js"]}, and place the background script in bg.js.