Javascript 如何检查是否支持自定义协议

Javascript 如何检查是否支持自定义协议,javascript,Javascript,我们使用的是注册自己协议的软件。我们可以通过以下链接从浏览器运行应用程序: customprotocol://do_this. 但有没有办法检查用户系统是否支持这种定制协议?如果不是,我们想让用户先安装软件 例如: 编辑 我知道protocolLong属性,但它只在IE中起作用。不幸的是,实现这一点并不容易。当然没有预先确定是否安装了协议处理程序的方法 Internet Explorer,如您所述,具有protocolLong属性,但我很难让它为所有自定义协议处理程序返回除“未知协议”以外的任

我们使用的是注册自己协议的软件。我们可以通过以下链接从浏览器运行应用程序:

customprotocol://do_this.
但有没有办法检查用户系统是否支持这种定制协议?如果不是,我们想让用户先安装软件

例如:

编辑
我知道protocolLong属性,但它只在IE中起作用。

不幸的是,实现这一点并不容易。当然没有预先确定是否安装了协议处理程序的方法

Internet Explorer,如您所述,具有
protocolLong
属性,但我很难让它为所有自定义协议处理程序返回除“未知协议”以外的任何内容--如果有人知道如何让IE返回正确值,请告诉我,以便我可以更新此部分。我发现IE最好的解决方案是在你的应用程序中安装一个浏览器扩展,它公开了一个Javascript可访问的属性

Firefox是目前为止最简单的主流浏览器,因为它允许您尝试并捕获失败的导航尝试。返回的错误对象包含一个
name
属性,其值为
NS\u error\u UNKNOWN\u PROTOCOL

try {
    iframe.contentWindow.location.href = "randomprotocolstring://test/";
} catch(e) {
    if (e.name == "NS_ERROR_UNKNOWN_PROTOCOL")
        window.location = "/download/";
}
Firefox将弹出自己的警报框:

Firefox不知道如何打开此地址,因为协议(randomprotocolstring)与任何程序都没有关联

关闭此框后,将执行
catch
块,您将有一个工作回退

第二个是Opera,它允许您使用可预测性法则来检测自定义协议链接的成功。如果自定义协议单击起作用,页面将保持不变。如果未安装处理程序,Opera将导航到错误页面。这使得使用iframe进行检测变得相当容易:

   iframe.contentWindow.location = "randomprotocolstring://test/";
   window.setTimeout(function () {
       try {
           alert(ifr.contentWindow.location); 
       } catch (e) { window.location = "/download/"; }
   }, 0);
这里的
setTimeout
是为了确保我们在导航后检查位置。需要注意的是,如果您尝试访问该页面,Opera会抛出ReferenceException(跨域安全错误)。这无关紧要,因为我们需要知道的是位置已从
about:blank
更改,因此
try…catch
可以正常工作

Chrome在这方面正式表现不佳。如果一个自定义协议处理程序失败,它绝对不会执行。如果处理器工作。。。你猜对了。。。它绝对是拉链。恐怕无法区分这两者

我还没有测试过Safari,但我担心它会和Chrome一样


欢迎您在调查这件事的同时尝试一下(我自己也有既得利益)。它与Opera和Firefox交叉兼容,但目前在IE和Chrome中没有任何功能。

对于Internet Explorer,我找到的最佳解决方案是使用条件注释和版本向量(应用程序在安装协议时必须向注册表写入内容,请参阅)。protocolLong不适用于自定义协议。

在移动设备上,您可以使用嵌入式iframe在自定义协议和已知协议(web或app store)之间自动切换,请参见

为了配合我们自己的体验,我们使用FireSpreat创建了一个简单的跨平台插件。一旦安装了这个插件,就会注册一个mime类型,在页面刷新后可以从浏览器javascript中检测到该类型。检测到mime类型表示已安装协议处理程序

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

Windows 8上的Internet Explorer 10介绍了一种非常有用的方法,用于启动自定义协议URL并检测成功或失败。例如:

        if (typeof (navigator.msLaunchUri) == typeof (Function)) {
            navigator.msLaunchUri(witchUrl,
                function () { /* Success */ },
                function () { /* Failure */ showError(); });

            return;
        }

Windows 7/IE 9及以下版本支持@mark kahn建议的条件注释。

这里有一个现成的答案:在注册自定义协议时安装一种不寻常的字体。然后使用javascript检查该字体是否存在,并使用一些东西


当然,这是一个黑客攻击,但与其他答案不同,它可以跨浏览器和操作系统工作。

我只想解释更多Mark之前的答案(有些人不理解,例如用户7892745)

1) 当您启动网页或web应用程序时,它会检查是否有不寻常的字体(如中文Konfuciuz字体)

下面是带有检查字体功能的示例网页的代码(称为isFontAvailable):

4) 之后,当用户再次运行web应用程序时,他会收到“自定义协议可用!”消息,因为这次安装了字体


在Google Chrome、Internet Explorer和Firefox上进行了测试-效果非常好

对于Firefox,我在谷歌上搜索的大部分文章,包括Andy E在这里的答案,以及本文的要点或用法

但是自从Firefox64之后,它就停止了工作,例如这里也证实了这一点

所以FF 64+我发现我可以使用Chrome的方法,
blurHandler
或者使用那里的帖子

对于Chrome 86+它也无法工作,请查看我的答案以了解详细信息


顺便说一句,我发现大多数答案/文章在某些情况下已经过时。

您可能想了解Thx,已经尝试了其中描述的大多数方法。在所有流行浏览器中,如果没有警报或其他问题,似乎没有很好的方法来实现这一点。对于Chrome,可能可以在安装过程中注册MIME时间,并使用
window.navigator.mimeTypes[i]
进行检查。我找不到一个简单的方法来做它。+1,这是IE 9和更低版本的一个很好的解决方法,马克。不幸的是,IE 10不再支持条件注释,但可能它们修复了
protocolLong
问题。+1―虽然不是一种“隐藏”的检测方法(IE将要求用户允许运行ActiveXObject),但这仍然是一种聪明的方法。特别是对于没有其他解决办法的Chrome,浏览器插件可能是一些人的唯一选择。FireBreath是解决这一问题的一个非常好的方法,而且是一种真正的解决方法
        if (typeof (navigator.msLaunchUri) == typeof (Function)) {
            navigator.msLaunchUri(witchUrl,
                function () { /* Success */ },
                function () { /* Failure */ showError(); });

            return;
        }
<!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>
// Adding the font ..

AddFontResource(PChar('XXXFont.TTF'));
SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
iframe.contentWindow.location.href = uri
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();
   }
}