Why isn't my background script getting executed? - google-chrome-extension

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.

Related

Why is chrome.browserAction.onClicked undefined (in the background script)? [duplicate]

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"]
}

chrome.runtime.onInstalled SOMETIMES not defined in event page

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).

getCurrentTime() for YouTube Video

I'm writing a Chrome Extension in Javascript and I want to get the current time for the playing video on youtube.com. I tried using the answer from question Getting Current YouTube Video Time , e.g.:
ytplayer = document.getElementById("movie_player");
ytplayer.getCurrentTime();
However I do get following error: "Uncaught TypeError: Cannot read property 'getCurrentTime' of null";
What I am doing wrong? I tried different values for the ElementId - movie_player, player....
Any help is appreciated. Thanks in advance.
Cheers.
edit:
Here is my manifest:
{
"manifest_version": 2,
"name": "",
"description": "",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "basic.html"
},
"permissions": [
"tabs",
"activeTab", "http://*/*", "https://*/*"
]
}
Another thing is:
If I execute this code:
ytplayer = document.getElementById("movie_player");
ytplayer.getCurrentTime();
In the Javascript console on a Youtube Page it works fine and returns the current time.
If, however I execute this value from the extension or the console of the extension, the first line return value null.
So, as Ben assumed below, the issue seems to be that my extension doesn't even access the Youtube page.
Any help is appreciated, so thanks in advance.
Cheers
Use the following code works for chrome extension:
video = document.getElementsByClassName('video-stream')[0];
console.log(video);
console.log(video.currentTime);
In 2020, it seems we should use: player.playerInfo.currentTime.
full code on codepen
As Ben correctly assumed, you're executing the code in the context of your background page, which is wrong.
To interact with other pages, you need to inject a content script in them. See overview of that here. You'll probably need to learn how Messaging works so you can gather data in a content script and communicate it to the background page.
To make a minimal example, you can have a file inject.js
// WARNING: This example is out of date
// For the current HTML5 player, see other answers' code snippets
ytplayer = document.getElementById("movie_player");
ytplayer.getCurrentTime();
And in your background page script, you can inject that into the current page as follows (when the button is clicked, for instance)
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript({
file: 'inject.js'
});
});
Then, you'll see the result of the execution in the console of the currently open page. To report the result back, you'll need to use chrome.runtime.sendMessage
you can only use getElementById when you´r referencing to the correct page. You´r using the right id. if you´r trying to access the play form another page you can use the jquery .load() function
---------EDIT----------
in the sample they do it like so:
function getCurrentTime() {
var currentTime = player.getCurrentTime();
return roundNumber(currentTime, 3);
}

chrome.experimental.processes.onExited.addListener not working

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.

Chrome extension that focuses items in elements panel

I am trying to develop a chrome extension that among other things, will be able to focus an element in the elements panel of the chrome devtools.
I have been pulling my hair out trying to get this to work today but have had no luck so far.
I think part of the key to cracking what I need is here
Here are the main differences between the eval() and
chrome.tabs.executeScript() methods:
The eval() method does not use an isolated world for the code being evaluated, so the JavaScript state of the inspected window is
accessible to the code. Use this method when access to the JavaScript
state of the inspected page is required.
The execution context of the code being evaluated includes the Developer Tools console API. For example, the code can use inspect()
and $0.
The evaluated code may return a value that is passed to the extension callback. The returned value has to be a valid JSON object
(it may contain only primitive JavaScript types and acyclic references
to other JSON objects). Please observe extra care while processing the
data received from the inspected page — the execution context is
essentially controlled by the inspected page; a malicious page may
affect the data being returned to the extension.
But I cannot find the correct place to send the message to or execute the command in order for this to work I am just repeatedly told the following:
Error in event handler for 'undefined': $ is not defined
ReferenceError: $ is not defined
at Object.ftDev.processMsg (chrome-extension://ffhninlgmdgkjlibihgejadgekgchcmd/ftDev.js:39:31)
at chrome-extension://ffhninlgmdgkjlibihgejadgekgchcmd/ftDev.js:16:7
at chrome.Event.dispatchToListener (event_bindings:387:21)
at chrome.Event.dispatch_ (event_bindings:373:27)
at chrome.Event.dispatch (event_bindings:393:17)
at miscellaneous_bindings:166:35
at chrome.Event.dispatchToListener (event_bindings:387:21)
at chrome.Event.dispatch_ (event_bindings:373:27)
at chrome.Event.dispatch (event_bindings:393:17)
at Object.chromeHidden.Port.dispatchOnMessage (miscellaneous_bindings:254:22) event_bindings:377
chrome.Event.dispatch_
Ideally I would like to use the inspect() method of the chrome console not the $() method.
manifest.json
{
"name": "XXXXX Ad and Spotlight Debugger",
"version": "0.1",
"manifest_version": 2,
"description": "A tool to help you identify and debug XXXXXX ads and spotlights in Chrome",
"devtools_page": "ftDev.html",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html",
"default_title": "XXXXXX Debug Tool"
},
"background": {
"persistent": false,
"page": "background.html",
"js": ["background.js"]
},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["getFTContent.js"],
"all_frames": true
}],
"permissions": ["tabs","cookies","<all_urls>","devtools"]
}
Then there is similar code in the popup.js, background.js and devtools.js file that essentially boils down to this:
processMsg: function(request, sender, sendResponse) {
switch(request.type) {
case "inspect":
$(request.msg);
sendResponse(request.msg + "successfully inspected");
break;
default:
break;
}
} /*other cases removed for sake of brevity*/
Which when executed results in the error above. I am sure that I am trying to execute the command in the wrong context but I can't figure out how to apply it. In the popup.js file I have also tried executing the $ method as below
chrome.tabs.executeScript(tabId, {code: 'function(){$("#htmlID");}'}, function(){});
Any ideas help would be amazing I can supply more of my code if you think it's necessary but I think this pretty much sums up the problem.
Ok - so I had a look around at the font changer thing and it still wasn't quite what I was looking for in the end but then I had a Eureka moment when I was looking over this page for about the 15th time and realised that I had somehow missed the most important part on the page (at least in order to do what I wanted) which was this method
chrome.devtools.inspectedWindow.eval("string to evaluate", callBack)
It is noted that isn't necessarily a good idea for security reasons as it it doesn't run the code in the isolated world.
Anyway - if I run this code from my devtools' page js-code with the following
chrome.devtools.inspectedWindow.eval("inspect(*id_of_the_div_i_want_inspect*)")
Then it will select this item in the elements page of the devtools... it also made me extremely happy!
:D
I don't know if anyone else will ever need/want this but it too me a long(ish) time to figure it out so I hope it helps other people in future.
You can easily highlight DOM elements in any tab, where your content script is injected. As an example, look at Font Selector extension.
As the source code is available (and thoroughly explained) I'll not post it here. The effect you'll see is that after clicking the browser action button every DOM element under mouse cursor becomes highlighed with red border.
If you want to send some info about selected/highlighted element from the tab into your background page, you can do it via messaging (you have already used it, as I see).

Resources