2010-05-20 104 views
48

我们正在使用注册自己的协议的软件。我们可以通过再像链接运行从浏览器应用程序:如何检查是否支持自定义协议

customprotocol://do_this. 

但有没有办法来检查是这样的定制协议由user`s系统支持?如果没有,我们想要求用户先安装软件。

E.g:

if (canHandle ('customprotocol')) { 
    // run software 
} 
else { 
    // ask to install 
} 

编辑 我知道protocolLong属性,但它只能在IE浏览器。

+4

您可能想要阅读http://stackoverflow.com/questions/836777/how-to-detect-browsers-protocol-handlers – 2010-05-20 08:39:42

+1

Thx,已经尝试过大部分描述的方法。似乎没有好的方法可以在所有流行的浏览器中实现此功能,而无需警报或其他问题。 – 2010-05-20 08:50:07

回答

44

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

的Internet Explorer,正如你所说,有protocolLong属性,但我无法得到它的收益高于“未知协议”以外的其他所有自定义协议处理程序 - 如果有谁知道如何让IE浏览器返回正确的值请让我知道,所以我可以更新此部分。我在IE中找到的最佳解决方案是append to the user agent string,或者安装一个浏览器扩展程序以及暴露Javascript可访问属性的应用程序。

Firefox是迄今为止最简单的主流浏览器,因为它将允许您尝试并捕获失败的导航尝试。返回的错误对象包含name属性,其值是NS_ERROR_UNKNOWN_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一样。

欢迎您在调查此事时尝试test code I wrote(我自己有一个既得利益)。它与Opera和Firefox交叉兼容,但目前在IE和Chrome中没有任何作用。

+1

你可能想检查一下。 http://www.rajeshsegu.com/2012/09/browser-detect-custom-protocols/comment-page-1/这是一个脚本,应该适用于所有浏览器(但不适用于IE)。它有一个hacky,但功能正常,适用于Chrome。 – d512 2014-01-07 20:19:22

+2

因为这个答案是在2010年编写的,所以我应该提到Google员工,在更新版本的Firefox中,try/catch方法不再有任何效果。 (iframe仍然避免错误页面) – Katana314 2014-05-02 14:55:48

+0

如果处理程序打开,则Chrome和Safare失去焦点(可以使用window.onblur)。 – 2017-02-20 22:59:39

4

对于Internet Explorer,我发现的最佳解决方案是使用Conditionl注释&版本向量(应用程序必须在安装协议时向注册表写入内容,请参阅http://msdn.microsoft.com/en-us/library/ms537512.aspx#Version_Vectors)。 protocolLong不适用于自定义协议。

+1

对于Chrome,也许可以在安装过程中注册MIME时间,并使用'window.navigator.mimeTypes [i]'进行检查。我找不到一个简单的方法来做到这一点。 – 2012-02-08 14:57:15

+1

+1,对于IE 9及更低版本,这是一个很好的解决方法,Mark。不幸的是,IE 10不再支持条件注释,但也许他们修正了'protocolLong'问题。 – 2013-04-02 19:36:04

3

在移动设备上,你可以使用嵌入式iframe来定制协议和已知的一个(网络或应用程序商店)之间自动切换,见https://gist.github.com/2662899

11

只是为了我们自己的经验帮腔,我们使用FireBreath创建一个简单的跨平台插件。一旦安装这个插件注册一个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 
    } 
} 
+1

+ 1 - 虽然不是“隐形”检测方法(IE会要求用户允许运行ActiveXObjects),但这仍然是一个聪明的方法。特别是对于没有其他解决方法的Chrome,浏览器插件可能是某些人的唯一选择。 – 2013-04-02 19:33:11

+0

FireBreath是解决这个问题的一个非常好的方法,如果这是您所需要的,非常简单。我已经使用它(尝试找到同样问题的解决方案之后)。 – 2014-04-19 23:32:41

+1

为了让人们意识到,Mozilla和Google认为插件是一项传统技术,Chrome开始逐步淘汰NPAPI,https://developer.chrome.com/extensions/npapi – Burjua 2015-03-23 16:07:33

7

在Windows 8的Internet Explorer 10中引入用于启动自定义协议的URL和检测的成功或失败的非常有益的方法navigator.msLaunchUri。例如:

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

      return; 
     } 

Windows 7/IE 9及以下版本支持条件注释,如@ mark-kahn所示。

+1

请注意,'msLaunchUri'方法仅在Windows 8 **的IE> = 10 **中存在。 – aaronk6 2015-01-05 13:46:07

+0

@ aaronk6。我不确定这是否正确,因为我在Windows 7上使用此方法。 – antmeehan 2015-01-20 06:53:47

+1

我在Windows 7上检查了IE 10和IE 11。在这两种情况下,'typeof navigator.msLaunchUri'都返回'“undefined”'。此外,Microsoft已确认此API尚未添加到Windows 7中:[Windows 7中不存在有文档记录的API函数'navigator.msLaunchUri'](https://connect.microsoft.com/IE/feedback/details/864863 /文档化的api-function-navigator-mslaunchuri-not-present-in-windows-7)(请参阅2014年5月5日下午12:27评论) – aaronk6 2015-01-20 08:50:25

1

下面是一个非常流行的答案:在注册自定义协议时安装不寻常的字体。然后使用javascript检查该字体是否存在,使用like this

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

+0

非常好的答案! +1 – 2017-01-23 23:43:19

+0

我不承认 – 2017-05-03 18:12:48

1

我只是想解释更多以前的马克的答案(有些人不明白,例如user7892745)。

1)当你启动你的网页或网页应用程序时,它会检查一个不寻常的字体(如中文Konfuciuz字体http://www.fontspace.com/apostrophic-lab/konfuciuz)。

下面是样本网页与功能的代码检查字体(称为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 <[email protected]> 
*/ 
(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)当用户打开该网页第一次,字体将不会被安装,所以他会得到一条消息说“请运行可执行文件以安装自定义协议...”。

3)他将运行将安装字体的可执行文件。你的EXE可以直接将字体文件复制(在我的情况下,它是KONFUC __ TTF)到C:\ Windows目录或使用这样的代码(Delphi的例子):

// Adding the font .. 

AddFontResource(PChar('XXXFont.TTF')); 
SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0); 

4)之后,当用户再次运行Web应用程序,他得到“自定义协议可用!”消息,因为这次是安装字体。

在Google Chrome,Internet Explorer和Firefox上测试 - 效果很好!