I am researching the possibility that I might be able to use a Chrome extension to automate browsing and navigation (conditionally). My hope is that the extension can load a remote page (in the background) and inject a javascript to evaluate clickable links and click (by calling the click method) the appropriate (evaluated by some javascript logic) link, then repeat process for the resulting page.
My ability to javascript is not the problem - but I am struggling to discern whether (or not) a chrome extension can load pages in the back and inject script into them (making the DOM accessible).
I would be pleased if anyone could confirm (or deny) the ability to do so - and if so, some helpful pointers on where I should research next.
#Rob W - it seems the experimental features fit the bill perfectly. But my first tests seem to show the features are still very experimental ... ie. no objects get returned from callbacks:
background.html
function getAllosTabs(osTabs){
var x = osTabs;
alert(x.length); // error: osTabs is undefined
}
function createOffScreenTabCallback(offscreenTab){
document.write("offscreen tab created");
chrome.experimental.offscreenTabs.getAll(getAllosTabs);
alert(offscreenTab); // error: offscreenTab is undefined
}
var ostab = chrome.experimental.offscreenTabs.create({"url":"http://www.google.com"}, createOffScreenTabCallback)
alert(ostab); // error: ostab is undefined
Some further digging into the chromium source code on github revealed a limitation creating offscreenTab from background:
Note that you can't create offscreen tabs from background pages, since they
don't have an associated WebContents. The lifetime of offscreen tabs is tied
to their creating tab, so requiring visible tabs as the parent helps prevent
offscreen tab leaking.
So far it seems like it is unlikely that I can create an extension that browses (automatically and conditionally) in the background but I'll still keep trying - perhaps creating it from script in the popup might work. It won't run automatically at computer startup but it will run when the browser is open and the user clicks the browseraction.
Any further suggestions are highly welcome.
Some clarifications:
there's no "background" tabs except extension's background page (with iframes) but pages loaded in iframes can know they are being loaded in frames and can break or break at even the best counter-framebreaker scripts
offscreenTab is still experimental and is very much visible, as its intended use is different from what you need it for
content scripts, and chrome.tabs.update() are the only way handle the automated navigation part; aside being extremely harsh to program, problems and limitations are numerous, including CSP (Content-Security-Policy), their isolated context isolating event data, etc.
Alternatives... not many really. The thing is you're using your user's computer and browser to do your things and regardless of how dirty they are not, chrome's dev team still won't like it and will through many things at you and your extension (like the v2 manifest).
You can use NPAPI to start another instance chrome.exe --load-extension=iMacros.
Related
Context:
I am creating a Chrome extension that hides certain elements of certain sites
In this specific case, I'm trying to hide the main feed of YouTube's home and trending pages
The script has no trouble on all other sites, including Twitter, Facebook etc.
But on YouTube, it's causing the page to crash
Roughly speaking, what the script does is:
Observes any mutation on document (childList: true, subtree: true, characterData: false)
Searches for the existence of certain nodes in the document
Changes some of their styles to hide them (or if already hidden, does nothing)
Adds a small menu into the node with a button to unhide the node
The MutationObserver is never disconnected because it needs to keep watching in the case of single-page apps where the page stays the same but different nodes come and go
So it keeps checking that the hidden nodes are still hidden every time there's any new mutation to the document or its subtree (heavy load on performance, I know - but it works fine on every other site)
YouTube issue:
YouTube always throws up a warning as follows, even when I am not running my script on it (in other words, YouTube's code is already a bit suspect):
[Violation] Added non-passive event listener to a scroll-blocking <some> event. Consider marking event handler as 'passive' to make the page more responsive. See <URL>
The specific event is either touchstart or wheel. This error can display in the 100s of times even when I am not running my script.
When I run my script, this error seems to blow up even more, and display more times than usual
Eventually, the entire page crashes or takes far longer to load than it should (but it does sometimes eventually make it all the way, showing that my extension is not completely breaking down)
There's also another warning that tends to show, [Violation] 'readystatechange' handler took <N>ms
This warning shows far fewer times than the other (see screenshot below)
Interestingly, usually loading youtube.com home page when starting off in a new tab is fine, and my extension successfully hides (i.e. changes styles on + injects some extra HTML into) the node it's meant to hide
I then get a crash or extremely slow page load when I try to navigate within YouTube, e.g. specifically going to the Trending page using the left-hand side menu, OR occasionally when I hit refresh on the page
Things I've tried:
Overriding the default addEventListener method on EventTarget.prototype, which I have so far failed to do successfully - not sure I understand how to do this despite trying a few methods from SO
Blocking the script that this error originates from (desktop_polymer_inlined_html_polymer_flags_v2.js) using the Chrome WebRequest API, but that doesn't work because it breaks the whole page
Questions:
Is it likely that this 'non-passive event listener' warning is interplaying with my script to cause the crashing of the page? Or that my script is causing more listeners to be added than the page would usually?
How can I stop this error from happening (e.g. how do I prevent the event listeners from being created by YouTube's JS)?
Does anyone know anything about the way YouTube is built that would make it crash if you try to 1) modify a style on an element directly 2) add another element into a parent element 3) continually check styles on an element? Builtwith.com was not much help.
Is there something else I am missing here? Another way I can change my content script to make it interplay better with YouTube?*
*I know a tempting answer will be 'don't observe the document'/'observe it less' but this is more or less non-negotiable in terms of the way the browser extension needs to work.
Screenshot:
Chrome profiling:
Note: having looked into them individually, none of the functions that are taking up the huge amount of time are part of my extension. So perhaps YouTube is reacting badly to the DOM modifications that my extension performs.
I recently had an issue whereby a user was complaining that they couldn't access a certain page because the link wasn't where it was supposed to be.
After some head-scratching, I had them disable all browser extensions and sure enough the problem went away. Re-enable extensions one by one...
AdBlock.
For some reason, it was blocking the links to the pages the user wanted to access.
Now, I don't run ads and never plan to, so usually I just tell people with this problem to whitelist the site and all is well. But if someone never knew there was a problem to begin with, I would actually lose traffic because of this. So how can I avoid this?
The only thing I can really think of is to detect AdBlock and pop up a small notice explaining that AdBlock is known to corrupt the website and that, since we don't run ads, they may want to disable it for the site. I mean, the site is a game, and this isn't the first time a browser extension has broken it, but I don't think first-time visitors would be too happy to see a popup asking to disable their blocker, you know?
So any solution that would actually prevent AdBlock from corrupting the site in the first place would be great.
You cannot prevent Chrome extensions from running. They operate in their own separate thread, with a privileged API, and hidden from page scripts.
Detecting adblockers is awkward. The easiest way is to create a 'sacrificial element' - a div with a class like 'ad_unit', for example - add it to the DOM and then wait a frame to see if it has been hidden (with display: none, for example, or a getBoundingClientRect check).
Element checking is tricky, though, because strictly speaking there's no guarantee an adblocker will run synchronously or before your checking code.
Because adblockers run in a privileged mode, their operation does not trigger events in the nonprivileged script space. To put it more simply: you can't use DOMMutationEvents to spy when a foreign extension messes with your page.
The other option is to try and load a 'sacrificial file' - an image with a URI that looks like an advert, say - and then attach an onError handler to the element. If it throws an error that looks suspicious (I think it's ERR_BLOCKED_BY_CLIENT on Chrome), then you show your warning message.
Your final choice is to try and avoid incurring Adblock's wrath in the first place. Adblockers generally use open blacklists of URIs and CSS selectors, like EasyList (https://easylist.to/easylist/easylist.txt) - this is what AdblockPlus uses and a fair few others. You could just try and make sure your DOM elements never have IDs or classes that collide with any of those selectors. It's a big list, though, and it can change at any time.
I am getting confused understanding the practices generally followed in the popular chrome extensions. I am trying to develop my own chrome extension and after going through the basic tutorial, I have a default popup page that opens whenever I click the extension icon near my address bar. So far so good! While checking the source codes of some good extensions installed in my chrome browser, I came to know, none of them uses the default_popup page but definitely invokes some javascripts through either the background page or content scripts. But the final behaviour as seen by the user is functionally like a popup at the upper right corner of the screen, though more presentable. Is there any reason for not using default_popup over using other mechanisms?
I think it really depends on what your app needs in terms of functionality and design. As there are no real reasons why you might want to choose one over the other. Most information can be passed from the page to the extension app and vice versa. Users expect a popup when they click on the button but injected popups are also supported and commonly used in Chrome, Firefox and Safari.
Pros/Cons:
If your extension depends on the page content then you can inject scripts that analyze the page and inject divs accordingly. You can send analyzed data back to the extension and open a popup but thats an additional step. If your extension has nothing to do with the specific page then you would be better off using a popup.
Popups close when you switch tabs or your browser loses focus. Injected popups need not.
Don't inject scripts and stylesheets into pages willy nilly. They interfere with a website's native js/css and also stuff injected by other externsions which is near impossible to fully account for.
When I disable the extension that I am developing, the content that I injected remains on the page (and things get messy since the JavaScript is no longer hiding the content). Is there a way that I can recognize the event and reload the page when it is disabled?
Yes its possible to detect the situation, thou i think its fine if the user needs to refresh manually uppon uninstall/disable.
One way is to regularly message your extension from the injected script to check if its still alive. I do this for an extension of mine to detect when chrome updated it, which has similar consequences as the old version of the background script goes away without notice and the content script is left orphan.
Unfortunately, I don't think there is - somewhat by design. Extensions are intended to run on top of web pages, and the web page shouldn't typically modify its behavior for extensions. This abstraction, though, results in web pages being unaware of an extension's running state.
If you are the one disabling the extension, you could make a "clean up" method which refreshes all pages on which the extension is running, but you'd have to manually trigger that prior to disabling it.
I am new on add-on development using the SDK.
I want to ask you guys if it is possible to start my extension automatically after I open my browser? At the moment I starts after I press my widget icon in the toolbar (the panel shows a table with some data I get from the DOM).
Another thing I want to ask you: is it possible to show a loading screen (like a ajax gif) inside my panel (my extension needs a few seconds after switching a tab, to get the DOM data) every time I press the toolbar button.
First of all: One question per post, please.
Extensions are always started with the browser. When it comes to SDK add-ons, your main.js will be called. It's your job to perform any additional initialization form there.
Panels contain regular HTML pages and therefore can use images.
It's impossible to tell you more, without you providing more details and the code you got so far!