I have a Chrome-based extension which works unfailingly in Chrome 26 through Chrome 70. It continues to work exactly as it does in Chrome in Firefox 47, 48, 49, but is now broken in FF/DevEdition 64.
I have no clue where to begin to look at what incompatibility FF later versions introduced/broke basic functions that worked in 47,48,49? Any pointers will be appreciated (even a link to archived versions in between so that I can grab a spare 'puter and find the exact version where it fails).
update: this is the daemon (background pg) code which opens the GUI interface
(excerpted):
var fireflyID = 0;
/* ... */
// msgpath 'class' [creates a bridge between the SDK (the GUI)
// and the tab it monitor/analyses/debugs ...
var msgpath = function(pathid, pathname, tabID, url, opener, reply) {
/* ... */
this.pathname = pathname;
this.sdk.path = url;
this.tab.tabID = tabID;
this.tab.port = chrome.tabs.connect(tabID);
this.tab.port.onMessage.addListener(handleSCRMsg);
/* ... */
this.connect = function() { //opening handshake with contentscr
this.tab.port.postMessage( {"msgtype":"connect" /* ... */};
};
this.accept = function() { //handshake accepted, open the sdk...
var fireflyURL;
fireflyURL = chrome.runtime.getURL(this.sdk.path);
// this works in Chrome26-Chrome70 (latest version)
// and Firefox 47-55, it opens the panel in FF56+,
// applies the title, but never displays the content?
// and yes .getURL() does add the right 'protocol' to the url
this.sdk.wdw = chrome.windows.create( {
"url" : fireflyURL +
"?portname=" + this.pathname + ";opener=",
"width" : 980,
"height" : 720,
"type" : "panel"
});
};
/* ... */
};
/* ... */
// msg from content-script...
var handeSCRMsg = function(msg) {
var mpath = null;
if (msg.msgpath) {
mpath = msgpaths[msg.msgpath];
/* ... */ // content scr accepts connection
if (msg.msgtype == "accept")
mpath.accept(); // msgpath object 'class' from above
/* ... */ // go open the sdk and splice the port connections
}
};
var handleCTRLMsg = function(msg) {
/* ... */
if (msg.msgtype == "open") {
pathid = fireflyID++;
pathname = "firefly"+pathid;
mpath = new msgpath(pathid, pathname, msg.tabID,
msg.path, msg.parent, msg.reply);
mpath.connect();
};
// wake up on pageAction (extension icon click)
chrome.pageAction.onClicked.addListener( function(tab) {
/* ... */
msg.tabID = tab.id;
msg.path = "sdkfirefly.html";
handleCTRLMsg(msg);
};
// content scr posts msg to daemon to tell daemon
// that dflibg dataflow library is in application
// 'tab' and it is ok to enable pageAction/icon
chrome.runtime.onMessage.addListener ( function (msg, sender) {
/* ... */
tab = sender.tab;
if (msg.msgtype == "activate")
chrome.pageAction.show(tab.id);
}
and that shows the pertinent logic/msg flow.
It is pretty basic stuff, and since it works in so many other instances
I'm rather confused as to where to investigate next.
Further update: Console log shows some firefox-internal xml errors - anything else is at the warning level (ff not paying attention to the manifest version number, or mis-processing the manifest) or a ff error [e.g., it complains about "browser-style" missing, but its there in page_action as it is supposed to be; then it complains about background.persistent but that is not there and does not apply to FF anyway...] None of this is material as the following seems to be the crux of the issue:
Upon further testing:
Extension loads and runs in FF47-FF55 on all platforms. Appears to not finish loading in FF56+ in Windows, but loads and runs as expected in FF47-FF64 on Linux.
The extension gui does [eventually] load in Win10/FF56 (i7-7700/3.6), but takes (wait for it) over 12 minutes for FF to load it (which makes it appear broken -- it takes 1/2 sec or less in Linux [ on an amd X4 860K], or 40 secs +/- in Win7 (i7-6700/3.4). Part of this is that there is something really wrong with the FF ipc mechanism used as a foundation layer for messaging between a tab and an extension page -->> it takes 14 secs for a round trip msg between the GUI->daemon->content-script->library, library->content_script->daemon->GUI (six hops total)
in win10/FF but it only takes millisecs in linux.
It appears that something radically changed between FF55 and FF56+ on Window$64bit platforms. Does anyone have a clue as to the difference, or a work-around using something other than the port ipc mechanism?
Thanks
After extensive testing, the problem appears to be how FF56 and newer interface with Windows7/10 to access the components of the extension - IFF the extension was loaded from a NAS/Samba or NFS mounted share. Why this has any effect on ipc as well is a complete mystery.
The solution is to copy the extension from the NAS appliance or Samba/NFS mounted share
to a physically local hard drive and temp-load the extension from there.
Related
This is for Windows.
I have a flash application I am converting to AIR. I built a captive installer using NSIS and it works fine. However I would like to have an icon on a website which checks if the application is already installed and ask the user if they wish to run it. If it is not installed, they get the option to download it.
I am fairly certain this is doable, because Zoom and GoToMeeting both do this.
My searching skills seem to be failing me when looking for this.
Edit:
It appears the best/only way to do this is to create a custom protocol for the application. Something like DoDaApp://.
Which brings up the next set of questions;
How to create an NSIS file which will create the appropriate registry entries on the client computer? As a user, not admin.
How to check if the protocol is currently installed on the computer?
This is a partial answer as it does not work in Edge. I'll explain the issue below.
As recommended in How to detect browser's protocol handlers you can use timeout & blur event handlers. Here is my interpretation of the code;
function checkCustomProtocol(inProtocol,inInstalLink,inTimeOut)
{
var timeout = inTimeOut;
window.addEventListener('blur',function(e)
{
window.clearTimeout(timeout);
}
)
timeout = window.setTimeout(function()
{
console.log('timeout');
window.location = inInstalLink;
}, inTimeOut
);
window.location = inProtocol;
}
Microsoft Edge is ever so helpful by popping up a dialog box telling you "You'll Need a new app to open this" which "blurs" the screen, not allowing download of the file.
So I will be posting another question on how to make it work in Edge. I have reviewed ismailhabib's code but the known issues section says it doesn't work with Edge either.
Here is a more complete answer. It has been lightly tested in IE 11, Microsoft Edge, Chrome and Firefox. I also added comments;
/*
checkCustomProtocol - check if custom protocol exists
inProtocol - URL of application to run eg: MyApp://
inInstallLink - URL to run when the protocol does not exist.
inTimeOut - time in miliseconds to wait for application to Launch.
*/
function checkCustomProtocol(inProtocol,inInstalLink,inTimeOut)
{
// Check if Microsoft Edge
if (navigator.msLaunchUri)
{
navigator.msLaunchUri(inProtocol, function ()
{
//It launched, nothing to do
},
function()
{
window.location = inInstalLink; //Launch alternative, typically app download.
}
);
}
else
{
// Not Edge
var timeout = inTimeOut;
//Set up a listener to see if it navigates away from the page.
// If so we assume the papplication launched
window.addEventListener('blur',function(e)
{
window.clearTimeout(timeout);
}
)
//Set a timeout so that if the application does not launch within the timeout we
// assume the protocol does not exist
timeout = window.setTimeout(function()
{
console.log('timeout');
window.location = inInstalLink; //Try to launch application
}, inTimeOut
);
window.location = inProtocol; //Launch alternative, typically app download.
}
}
I developed a google chrome extension that works good with Windows OS. but the problem that does not work with mac, I tried to check the problem, I found that function
chrome.tabs.executeScript
does not work on mac, this is the completely code that worked good with windows not mac.
// The onClicked callback function.
function onClickHandler(info, tab) {
// the problem in injecting code
chrome.tabs.executeScript
( null,{code:"var activeElm = document.activeElement; var inp_text = activeElm.value; console.log(activeElm.value);"});
};
chrome.contextMenus.onClicked.addListener(onClickHandler);
// Set up context menu tree at install time.
chrome.runtime.onInstalled.addListener(function() {
// Intentionally create an invalid item, to show off error checking in the
// create callback.
console.log("About to try creating an invalid item - an error about " +
"duplicate item child1 should show up");
chrome.contextMenus.create({"title": "consoleMe", "id": "child523", "contexts":["selection"]}, function() {
if (chrome.extension.lastError) {
console.log("Got expected error: " + chrome.extension.lastError.message);
}
});
});
Hint:
I use content_scripts injection files in the manifest file, but it seems did not activated on Google chrome on Mac.
"content_scripts": [
{
"matches": ["http://*/*","https://*/*"],
"js" : ["jquery.min.js","fix.js","injscript.js"],
"all_frames": false
}
],
OS : Mac 10.8 Mountain lion --
Google Chrome V 32
There should be no difference between Windows and Mac. It's likely that something else is different between your two setups.
It's not clear to me whether the javascript snippet above is a background script or an injected content script. Can you provide the full manifest and indicate which file the snippet belongs to?
If it's a background script, chrome.tabs.executeScript with null tabId will apply to the background page, which is not what you expect. Instead, pass tab.id for the tabId.
If it's a content script, the contextMenus API calls won't work because content scripts are not allowed to use chrome APIs (see https://developer.chrome.com/extensions/content_scripts.html).
I am using Roy Tanck's WP-Cumulus Tag Cloud viewer. It's an SWF file that is used with SWFObject.js to show a spinning sphere of tags. It works fine in Chrome and FireFox, but in Internet Explorer 10 the canvas is blank. If I right-click on the canvas I do see the attribution link to Roy Tanck's web site indicating the movie was loaded, and there are no errors showing in the Debugger's Console tab, but no sphere of tags, just a blank white canvas. I am using SWFObject v2.2 and my Flash player version is 11.8.800.175. I traced my main function (shown below) for creating the tag XML for the SWF and everything checks out fine. Unfortunately, I get nothing but a blank display for the movie and no errors in the console. I did look at the values for the flashvars and they are identical to what they are when I trace the method in Chrome and FireFox. Can anyone give me some things to try that might help fix this problem?:
// Create the tag cloud using the given associative array where the Key is the
// value to display in the tag cloud and the Value is the HREF for the link
// to be associated with the display value.
function createTagCloud(aryDisplayStringsWithLinks, style)
{
if (typeof aryDisplayStringsWithLinks == 'undefined')
return;
// Build tags XML partial for use by the Cumulus Tag Cloud.
var tagCloudXML = "<tags>";
var iCount = 0;
for (var Key in aryDisplayStringsWithLinks)
{
tagCloudXML += createOneTagCloudXMLElement(Key, aryDisplayStringsWithLinks[Key], style);
iCount++;
} // for()
tagCloudXML += "</tags>";
// Must have at least two elements or the tag cloud won't make any sense.
if (iCount < 2)
return;
var params =
{
wmode: "transparent"
};
var flashvars =
{
// TAGS HYPERLINKS ***MUST** HAVE THE STYLE ATTRIBUTE OR YOU WON'T SEE ANYTHING IN THE VIEWPORT! (and you
// will think it is broken when it is not).
tagcloud: tagCloudXML,
// tagcloud: '<tags><a href="http://google.com/" style="font-size:9pt;" >One</a><a href="http://microsoft.com/" style="font-size:9pt;" >Two</a></tags>',
mode: "tags",
distr: "true",
tcolor: "0x3366CC",
hicolor: "0x0000bb"
};
swfobject.embedSWF(
"/Content/flash/tagcloud.swf",
"flashcontent",
"470",
"380",
"9.0.0",
"",
flashvars
);
} // function createTagCloud(aryDisplayStringsWithLins) {
Are you facing the problem on
OS: windows 8
Browser: Internet Explorer 10
open the debugger (F12)
Cache (menu bar) -> select ["Always refresh from server"]
It will work now.
The problem exist when all request are not 200
Debugging further to find the fix without the above tweak
Found this check if it fixes the issue for you
Flash not working on Windows 8 / Internet explorer 10
My add-on creates a FireFox File menu command that triggers callback function 'launchApp'.
function launchApp() {
var ww = Cc["#mozilla.org/embedcomp/window-watcher;1"]
.getService(Components.interfaces.nsIWindowWatcher);
var appUrl='chrome://mrT2/mrT00.xul'; // production (fails)
var appUrl='file:///C:/mpa/##mrT-2.0/mrT00.xul'; // testing (works)
var win = ww.openWindow(null, appUrl, "mrT2-window", "chrome,resizable", null);
// Summary of results of ww.openWindow() for various appUrl values:
// 'chrome:///mrT2/mrT00.xul' 'No chrome package registered for ...' (true)
// 'chrome://mrT00.xul' 'Invalid chrome URI: /' (true)
// 'chrome:///mrT00.xul' and 'chrome://mrT2/mrT00.xul' seem valid yet both give:
//Error: NS_ERROR_ILLEGAL_VALUE: Component returned failure code: 0x80070057 ...
// ... (NS_ERROR_ILLEGAL_VALUE) [nsIWindowWatcher.openWindow] (unexplained)
return true;
The above code works nicely and is great for testing mrT00.xul (because it collects the file directly from where I am editing it).
However when I interchange the two appUrl vars to try and open the exact same file as shipped via the xpi (and now internal to firefox) I get the dreaded 'illegal value' 0x80070057.
After 2 long days of research and study I cannot fault my code. Can you?
Otherwise, how may I begin tracing nsiWindowWatcher to pinpoint the error?
Bad things can happen when an extension attempts to open a xul file outside the /content directory or inside it when the chrome.manifest file in the .xpi root is not in order. Firefox handling of both these situations is not above reproach, warnings being offered in neither case.
We are using software that registers its own protocol. We can run application from browser then by link like:
customprotocol://do_this.
but is there a way to check is such custom protocol supported by user`s system? If not we would like to ask user to install software first.
E.g:
if (canHandle ('customprotocol')) {
// run software
}
else {
// ask to install
}
Edit
I know about protocolLong property but it works only in IE.
Unfortunately, there's no easy way of achieving this. There's certainly no method of pre-determining whether or not the protocol handler is installed.
Internet Explorer, as you mentioned, has the protocolLong property but I'm having trouble getting it to return anything other than "Unknown Protocol" for all custom protocol handlers -- if anyone knows how to get IE to return the correct value please let me know so I can update this section. The best solution I've found with IE is to append to the user agent string or install a browser extension along with your app that exposes a Javascript accessible property.
Firefox is by far the easiest of the major browsers, as it will allow you to try and catch a navigation attempt that fails. The error object returned contains a name property whose value is NS_ERROR_UNKNOWN_PROTOCOL:
try {
iframe.contentWindow.location.href = "randomprotocolstring://test/";
} catch(e) {
if (e.name == "NS_ERROR_UNKNOWN_PROTOCOL")
window.location = "/download/";
}
Firefox will pop up with its own alert box:
Firefox doesn't know how to open this address, because the protocol (randomprotocolstring) isn't associated with any program.
Once you close this box, the catch block will execute and you have a working fallback.
Second is Opera, which allows you to employ the laws of predictability to detect success of a custom protocol link clicked. If a custom protocol click works, the page will remain the same location. If there is no handler installed, Opera will navigate to an error page. This makes it rather easy to detect with an iframe:
iframe.contentWindow.location = "randomprotocolstring://test/";
window.setTimeout(function () {
try {
alert(ifr.contentWindow.location);
} catch (e) { window.location = "/download/"; }
}, 0);
The setTimeout here is to make sure we check the location after navigation. It's important to note that if you try and access the page, Opera throws a ReferenceException (cross-domain security error). That doesn't matter, because all we need to know is that the location changed from about:blank, so a try...catch works just fine.
Chrome officially sucks with this regard. If a custom protocol handler fails, it does absolutely zip. If the handler works... you guessed it... it does absolutely zip. No way of differentiating between the two, I'm afraid.
I haven't tested Safari but I fear it would be the same as Chrome.
You're welcome to try the test code I wrote whilst investigating this (I had a vested interest in it myself). It's Opera and Firefox cross compatible but currently does nothing in IE and Chrome.
Here's an off-the-wall answer: Install an unusual font at the time you register your custom protocol. Then use javascript to check whether that font exists, using something like this.
Sure it's a hack, but unlike the other answers it would work across browsers and operating systems.
Just to chime in with our own experience, we used FireBreath to create a simple cross-platform plugin. Once installed this plugin registers a mime type which can be detected from the browser javascript after a page refresh. Detection of the mime type indicates that the protocol handler is installed.
if(IE) { //This bastard always needs special treatment
try {
var flash = new ActiveXObject("Plugin.Name");
} catch (e) {
//not installed
}
else { //firefox,chrome,opera
navigator.plugins.refresh(true);
var mimeTypes = navigator.mimeTypes;
var mime = navigator.mimeTypes['application/x-plugin-name'];
if(mime) {
//installed
} else {
//not installed
}
}
Internet Explorer 10 on Windows 8 introduced the very useful navigator.msLaunchUri method for launching a custom protocol URL and detecting the success or failure. For example:
if (typeof (navigator.msLaunchUri) == typeof (Function)) {
navigator.msLaunchUri(witchUrl,
function () { /* Success */ },
function () { /* Failure */ showError(); });
return;
}
Windows 7 / IE 9 and below support conditional comments as suggested by #mark-kahn.
For Internet Explorer, the best solution I've found is to use Conditionl comments & Version Vector (application must write something to registry while installing protocol, see http://msdn.microsoft.com/en-us/library/ms537512.aspx#Version_Vectors). protocolLong doesn't work for custom protocol.
On mobile you can use an embedded iframe to auto switch between the custom protocol and a known one (web or app store), see https://gist.github.com/2662899
I just want to explain more previous Mark's answer (some people did not understand for example user7892745).
1) When you launch you web-page or web-application it checks for an unusual font (something like Chinese Konfuciuz font http://www.fontspace.com/apostrophic-lab/konfuciuz).
Below is the code of sample web-page with function which checks the font (called isFontAvailable):
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script>
/**
* Checks if a font is available to be used on a web page.
*
* #param {String} fontName The name of the font to check
* #return {Boolean}
* #license MIT
* #copyright Sam Clarke 2013
* #author Sam Clarke <sam#samclarke.com>
*/
(function (document) {
var width;
var body = document.body;
var container = document.createElement('span');
container.innerHTML = Array(100).join('wi');
container.style.cssText = [
'position:absolute',
'width:auto',
'font-size:128px',
'left:-99999px'
].join(' !important;');
var getWidth = function (fontFamily) {
container.style.fontFamily = fontFamily;
body.appendChild(container);
width = container.clientWidth;
body.removeChild(container);
return width;
};
// Pre compute the widths of monospace, serif & sans-serif
// to improve performance.
var monoWidth = getWidth('monospace');
var serifWidth = getWidth('serif');
var sansWidth = getWidth('sans-serif');
window.isFontAvailable = function (font) {
return monoWidth !== getWidth(font + ',monospace') ||
sansWidth !== getWidth(font + ',sans-serif') ||
serifWidth !== getWidth(font + ',serif');
};
})(document);
function isProtocolAvailable()
{
if (isFontAvailable('Konfuciuz'))
{
return true;
}
else
{
return false;
}
}
function checkProtocolAvail()
{
if (isProtocolAvailable())
{
alert('Custom protocol is available!');
}
else
{
alert('Please run executable to install protocol!');
}
}
</script>
<h3>Check if custom protocol was installed or not</h3>
<pre>
<input type="button" value="Check if custom protocol was installed!" onclick="checkProtocolAvail()">
</body>
</html>
2) First time when user opens this page, font will not be installed so he will get a message saying "Please run executable to install custom protocol...".
3) He will run executable which will install the font. Your exe can just copy the font file (in my case it is KONFUC__.ttf) into C:\Windows directory or using a code like this (example on Delphi):
// Adding the font ..
AddFontResource(PChar('XXXFont.TTF'));
SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
4) After that, when user runs web app again, he gets "Custom protocol is available!" message because font was installed this time.
Tested on Google Chrome, Internet Explorer and Firefox - working great!
For Firefox, most of articles I googled, including Andy E 's answer here, and this gist Cross-browser implementation of navigator.msLaunchUri or https://github.com/ismailhabib/custom-protocol-detection using
iframe.contentWindow.location.href = uri
But it has stopped working since Firefox 64, e.g here https://github.com/ismailhabib/custom-protocol-detection/issues/37 also confirmed that.
So FF 64+ I found I can either using Chrome's method, blurHandler or using the post there https://github.com/ismailhabib/custom-protocol-detection/issues/37#issuecomment-617962659
try {
iframe.contentWindow.location.href = uri;
setTimeout(function () {
try {
if (iframe.contentWindow.location.protocol === "about:") {
successCb();
} else {
failCb();
}
} catch (e) {
if (e.name === "NS_ERROR_UNKNOWN_PROTOCOL" ||
e.name === "NS_ERROR_FAILURE" || e.name === "SecurityError") {
failCb();
}
}
}, 500);
} catch (e) {
if (e.name === "NS_ERROR_UNKNOWN_PROTOCOL" || e.name === "NS_ERROR_FAILURE"
|| e.name === "SecurityError") {
failCb();
}
}
For Chrome 86+ it also fails to work, check my answer for details Detect Custom Protocol handler in chrome 86
BTW, I find most of answers/articles are outdated in some cases.