How to check if a custom protocol supported
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.
Custom protocol detection across browsers
I found, but never used up to now, this:
https://github.com/ismailhabib/custom-protocol-detection
Custom Protocol Detection in Browser
Detect whether a custom protocol is available in browser (FF, Chrome,
IE8, IE9, IE10, IE11, and Edge)The implementation is different from one browser to another, sometimes
depend on which OS you are. Most of them are hacks, meaning that the
solution is not the prettiest.
How do I handle a custom protocol not being installed on Safari still triggering the onblur event?
I've used custom-protocol-detection in the past here, though my target was all browsers.
That being said - in digging through their source, it seems their strategy is to embed the content in a hidden frame with the javascript creates.
function openUriWithHiddenFrame(uri, failCb, successCb) {
var timeout = setTimeout(function () {
failCb();
handler.remove();
}, 1000);
var iframe = document.querySelector("#hiddenIframe");
if (!iframe) {
iframe = _createHiddenIframe(document.body, "about:blank");
}
var handler = _registerEvent(window, "blur", onBlur);
function onBlur() {
clearTimeout(timeout);
handler.remove();
successCb();
}
iframe.contentWindow.location.href = uri;
}
source
The source also contains strategies for all browsers.
Related Topics
How to Write Asynchronous Functions for Node.Js
How to Disable Browser Developer Tools
Ruby Array to JavaScript Array
Get Gps Location from the Web Browser
Get Number Days in a Specified Month Using JavaScript
Ruby on Rails 3.1 - Assets Pipeline - Assets Rendered Twice
JavaScript Equivalent of Rails Try Method
This' Different Between Repl and Script
Pure JavaScript Send Post Data Without a Form
Sort an Array of Object by a Property (With Custom Order, Not Alphabetically)
Es6 Template Literals VS. Concatenated Strings
Valueof() VS. Tostring() in JavaScript
Why Does "True" == True Show False in JavaScript
Understanding Service Worker Scope
How to Display PDF (Blob) on iOS Sent from My Angularjs App