I'm writing a Chrome extension that analyzes the websites a user visits. I've decided to use chrome.tabs.onUpdated to run my analysis script instead of content_scripts in manifest.json, because chrome.tabs.onUpdated does a better job picking up page refreshes on AJAX heavy sites.
I don't need to analyze updates to new, empty tabs or to chrome-extension:// (local) pages, and in fact an error will be thrown if I do try to inject a script into those tabs. Is there a more automatic way to ignore those pages, or do I have to do it the manual way with Try/Catch blocks or by analyzing the URL? I'm sure I can do it manually, but it seems there should be a more automatic way to accomplish this.
You can ignore all local or internal chrome extension URLs by filtering out ones that start with 'chrome':
// Listen for changes on tabs
chrome.tabs.onUpdated.addListener(function(tabId, info, tab) {
log_console('tab', tab)
// If tab is not an internal chrome tab
if (!tab.url.startsWith('chrome')) {
console.log('Non-internal URL updated")
}
});
Note that you need the tabs permission in your manifest.json if you want to access the URL, otherwise tab.url will be undefined and this won't work. If you can't get the tabs permission, your best bet might be to just catch and handle the error when you try to inject.
Related
My Extension's content script interacts with every open tab.
When I update my Extension any existing tabs will have the old content script and my Extension will not function.
I have tried putting an alert on the page asking users to refresh (triggered by catching an error), which is confusing to users. This answer (chrome extension API for refreshing the page) shows how to refresh all open tabs...and if placed in background.js in the onInstalled listener (reason === "update") we can force all open tabs to refresh. But this feels invasive and alarming to the user.
What is the best practice?
I would like to write an extension that connects to all Chrome tabs that are html (critically, leaving out any tabs hosting non-html content such as chrome://extensions/ and other non-user tabs, as that would surely cause lots of internal errors if those special tabs aren't entirely excluded from handling by my business logic code). No need for a Chrome extension button.
I would then like to execute some code on any of those user html tabs:
When the user has clicked a hyperlink or button.
When navigation to a new url is about to begin (and get the target url)
After a new page has completed loading in any of the tabs (and get the url)
I am not sure which approach is currently best to use, for each of those above, and also am initially unable to get to the url. Currently, I'm trying a background tab (should I, really?). The trouble is I am unable to get to the url through the tab object with that approach ―
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
console.dir(tab);
});
It appears the tab object does not directly point at a url.
Regardless this pointwise issue, I wonder what might be the most robust approach for accomplishing the overall scenario described: getting notified of those events for all html user tabs, and getting the url in every case. In the official docs, a relevant sample is very much elusive to find.
I’ve been placing a page action on the options page of my Chrome extension. options.js calls chrome.runtime.connect({"name":"someName"}), and background.js has
chrome.runtime.onConnect.addListener(function(port) {
chrome.pageAction.show(port.sender.tab.id);
});
Unfortunately, in the new options_ui with the recommended default (and someday mandatory) "open_in_tab":false, the Sender's tab won't be set. Is there a way to get the tab id in order to show the page action?
I could use tabs.query to get the chrome://extensions/ tab, but that requires the tabs permission, which I currently don’t need. Active tab seems like it would work, but it doesn’t provide the tab id and isn’t enabled by opening an option dialog (source).
(Why do I want the page action on my options page? The extension works with a website that is only available ~7-10 weeks per year. I’d like my users to be able to interact with the extension the rest of the time, so that they can get used to the process. But I don’t want to adjust the displayed extension permissions just to do so. I can accomplish this by having the options page pretend to be the website in question.)
*By other js files, I mean the files you include in popup.html.
The following code works, so why should I use a background script?
Content script
chrome.extension.onMessage.addListener(
function(request, sender, sendResponse) {
//Some code
}
);
Script included in popup.html
chrome.tabs.query({active:true,windowId: chrome.windows.WINDOW_ID_CURRENT},
function(tab) {
chrome.tabs.sendMessage(tab[0].id, {method: "someMethod"},
function(response){
//Some code
});
});
This
Background pages live as long as the Chrome browser is active (and even longer if the "background" permission is set). Popup pages are only active when the badge's popup is open. The popup can only be opened by the user.
The background page's document is never visible, whilst the popup page becomes visible on click of the badge's button.
Besides that, there's no difference between background pages and popup pages. They run in the same extension's process, and have access to the same set of APIs.
If your extension only needs to be active while the popup is active, you don't need a background page. To save the state of the popup, just use the synchronous localStorage or the asynchronous chrome.storage API. When the variables you use are too complex to be stored using either API, a background page may be useful.
One example where the use of a background page is beneficial:
Imagine an extension that downloads a huge text file from a server. The creation of the resource is very resource-intensive for the server. Technically, everything can be done from within the popup. However, offloading the task to the background page allows the user to do other tasks while the file is downloading (if you use a popup only, the download will stop when the user closes the popup).
Though you didn't ask, I'd like to make you aware of event pages. They are similar to background pages, with one difference: Event pages are automatically closed when the extension is idle. In other words, event pages are only active when needed! By doing this, your extension will profit from the advantages of background pages without needlessly wasting the user's memory.
My last example is also a perfect example of when an event page has to be used. Besides doing the http request on behalf of the popup, the background page does nothing. If you use an event page instead of a background page, you get the best of both worlds: the popup page can be closed without interrupting the download, and the extension will not waste memory.
Documentation
Learn more about Background pages and Event pages
"Popup" in this answer refers to the optional panel of the chrome.browserAction or chrome.pageAction API, set by declaring the "default_popup" key in the manifest file, or programatically using the setPopup method.
An example would be if my extension overrides the newtab page and the user installs another extension that also overrides the newtab page. Currently, only one newtab extension shows up and it usually isn't mine.
What can I do to detect when such a conflict occurs and inform the user of such?
The management API doesn't tell me if the extensions override any pages, so I sadly can't use that.
This doesn't seem to be an exant feature of the API. I'd suggest you open a bug at http://crbug.com.
Failing that, you can perform the following nasty hack (which I haven't tested):
Have your new tab page send a message to your background page whenever it loads.
Listen for chrome.webNavigation.onBeforeNavigate events that deal with chrome://newtab:
chrome.webNavigation.onBeforeNavigate.addListener(function(details) {
/* send message */
}, { url: [{ urlEquals: 'chrome://newtab/' }] });
When webNavigation sees the browser load chrome://newtab but you don't see a message to your background page shortly afterwards, your new tab page is probably not being used. From there, you can send a notification, or open another tab/window with a notice.
Unfortunately, this requires the webNavigation permission, which is unfortunate if your extension doesn't otherwise need it. The warning that it carries ("This extension can access your tabs and browsing activity") might scare away some potential users, especially if there's no reason for it that is obvious to the user. (Then again, perhaps I'm being too optimistic about the security-conscientiousness of users.) If your extension currently uses the tabs API, then it already carries this notice anyway.