如何检测浏览器的协议处理程序?

我创build了一个自定义URL协议处理程序。

http://

mailto://

custom://

我已经注册了一个WinForms应用程序来做出相应的回应。 这一切都很好。

但我希望能够正常处理用户没有安装自定义URL协议处理程序的情况。

为了能够做到这一点,我需要能够检测浏览器的注册协议处理程序,我会从JavaScript假设。 但我一直无法find一个方法来查询信息。 我希望find解决这个问题的办法。

感谢您可以分享的任何想法。

这将是一个非常非常 hacky的方式来做到这一点…但会这样工作?

  • 把链接正常…
  • 但附加一个onclick处理程序,它设置一个计时器,并添加窗口的onblur处理程序
  • (理论上)如果浏览器处理链接(应用程序X)将加载从窗口偷窃焦点…
  • 如果onblur事件触发,清除计时器…
  • 否则,在3-5秒,让你的超时火灾…并通知用户“嗯,看起来像你没有安装兆丰Uber酷应用程序…你想现在安装吗?(好的)(取消)”

远没有防弹…但它可能有帮助吗?

没有很好的跨浏览器的方式来做到这一点。 在Win8 +上的IE10 +中,新的msLaunchUri api使您可以启动协议,如下所示:

 navigator.msLaunchUri('skype:123456', function() { alert('success'); }, function() { alert('failed'); } ); 

如果协议没有安装,失败callback将被触发。 否则,协议将启动,成功callback将触发。

我在这里进一步讨论这个话题: http : //blogs.msdn.com/b/ieinternals/archive/2011/07/14/url-protocols-application-protocols-and-asynchronous-pluggable-protocols-ohmy的.aspx

HTML5定义了自定义scheme和内容处理程序 (就我所知,Firefox是迄今为止唯一的实现者 ),但不幸的是,目前还没有办法检查处理程序是否已经存在 – 已经提出 ,但没有后续。 这似乎是有效使用自定义处理程序的一个重要function,我们作为开发人员应该注意这个问题以实现它。

似乎没有通过JavaScript直接的方式来检测已注册协议处理程序的已安装的应用程序的存在。

在iTunes模型中,苹果公司向他们的服务器提供了URL,然后提供运行一些javascript的页面:

detection/itmsCheck.js

所以iTunes安装程序显然是为主要浏览器部署插件,然后可以检测其存在。

如果您的插件已安装,那么您可以合理确定redirect到您的应用程序特定的url将会成功。

您可以使用embedded式iframe在自定义协议和已知的协议(networking或app store)之间自动切换,请参阅https://gist.github.com/2662899

接缝最简单的解决方法是首次询问用户。

每个示例使用Javascript确认对话框:

 You need this software to be able to read this link. Did you install it ? if yes: create a cookie to not ask next time; return false and the link applies if false: window.location.href = '/downloadpage/' 

如果您对要运行的程序(代码)有控制权,那么查看用户是否成功运行该应用程序的一种方法是:

  1. 在尝试打开自定义协议之前,请向服务器脚本发出一个AJAX请求,以便将用户的意图保存在数据库中(例如,保存用户标识以及他想要执行的操作)。

  2. 尝试打开程序,并传递意图数据。

  3. 让程序向服务器发出请求以删除数据库条目(使用意向数据查找正确的行)。

  4. 让JavaScript轮询服务器一段时间,看看数据库条目是否消失了。 如果条目不存在,您将知道用户已成功打开该应用程序,否则该条目将保留(您可以稍后使用cronjob将其删除)。

我还没有尝试过这种方法,只是想到了。

你可以尝试这样的事情:

 function OpenCustomLink(link) { var w = window.open(link, 'xyz', 'status=0,toolbar=0,menubar=0,height=0,width=0,top=-10,left=-10'); if(w == null) { //Work Fine } else { w.close(); if (confirm('You Need a Custom Program. Do you want to install?')) { window.location = 'SetupCustomProtocol.exe'; //URL for installer } } } 

你说你需要检测浏览器的协议处理程序 – 你真的吗?

如果你做了类似从Sourceforge下载文件时发生的事情呢? 假设你想打开myapp://东西。 而不是简单地创build一个链接,创build一个链接到另一个通过HTTP访问的HTML页面。 然后,在那个页面上,说你正试图为他们打开应用程序。 如果它不起作用,他们需要安装你的应用程序,他们可以通过点击你提供的链接来完成。 如果确实有效,那么你就全部设置好了。

我终于得到了一个跨浏览器(Chrome 32,Firefox 27,IE 11,Safari 6)的解决scheme,并结合使用这个超级简单的Safari扩展。 在这个和这个另外的问题中 ,这个解决scheme的大部分都以某种方式被提及。

这是脚本:

 function launchCustomProtocol(elem, url, callback) { var iframe, myWindow, success = false; if (Browser.name === "Internet Explorer") { myWindow = window.open('', '', 'width=0,height=0'); myWindow.document.write("<iframe src='" + url + "'></iframe>"); setTimeout(function () { try { myWindow.location.href; success = true; } catch (ex) { console.log(ex); } if (success) { myWindow.setTimeout('window.close()', 100); } else { myWindow.close(); } callback(success); }, 100); } else if (Browser.name === "Firefox") { try { iframe = $("<iframe />"); iframe.css({"display": "none"}); iframe.appendTo("body"); iframe[0].contentWindow.location.href = url; success = true; } catch (ex) { success = false; } iframe.remove(); callback(success); } else if (Browser.name === "Chrome") { elem.css({"outline": 0}); elem.attr("tabindex", "1"); elem.focus(); elem.blur(function () { success = true; callback(true); // true }); location.href = url; setTimeout(function () { elem.off('blur'); elem.removeAttr("tabindex"); if (!success) { callback(false); // false } }, 1000); } else if (Browser.name === "Safari") { if (myappinstalledflag) { location.href = url; success = true; } else { success = false; } callback(success); } } 

Safari的扩展很容易实现。 它由一行注入脚本组成:

myinject.js:

 window.postMessage("myappinstalled", window.location.origin); 

然后在网页JavaScript中,您需要先注册消息事件,并在收到消息时设置一个标志:

 window.addEventListener('message', function (msg) { if (msg.data === "myappinstalled") { myappinstalledflag = true; } }, false); 

这假设与自定义协议相关联的应用程序将pipe理Safari扩展的安装。

在所有情况下,如果callback返回false,则知道通知用户应用程序(即自定义协议)未安装。

我为这个问题build立了一个通用的库,这个假设是自定义协议处理程序会触发一个新的窗口将焦点从浏览器中移出。

https://github.com/ismailhabib/custom-protocol-detection

我试图做类似的事情,我只是发现了一个与Firefox的作​​品。 如果你把它与IE的技巧结合起来,你可以在两个主要的浏览器上使用它(我不确定它是否在Safari中工作,我知道它在Chrome中不起作用)

 if (navigator.appName=="Microsoft Internet Explorer" && document.getElementById("testprotocollink").protocolLong=="Unknown Protocol") { alert("No handler registered"); } else { try { window.location = "custom://stuff"; } catch(err) { if (err.toString().search("NS_ERROR_UNKNOWN_PROTOCOL") != -1) { alert("No handler registered"); } } } 

为了这个工作,你还需要在页面的某个地方有一个隐藏的链接,就像这样:

 <a id="testprotocollink" href="custom://testprotocol" style="display: none;">testprotocollink</a> 

这有点哈克,但它的作品。 不幸的是Firefox版本仍然popup当您尝试访问未知协议的链接时出现的默认警报,但警报解除后将运行您的代码。

这是微软支持的IE推荐方法

http://msdn.microsoft.com/en-us/library/ms537503%28VS.85%29.aspx#related_topics

“如果你对用户机器上安装的二进制文件有一定的控制,检查脚本中的UA就像是一种相关的方法:HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Internet Settings \ 5.0 \ User Agent \ Post Platform” – 由M $支持

每个网页都可以访问userAgentstring,并且如果您放弃自定义发布平台值,那么使用navigator.userAgent在javascript中检测这个值非常简单。

幸运的是,其他主stream浏览器如Firefox和Chrome(禁止Safari :),当点击一个自定义协议的链接并且协议未安装在用户机器上时,请不要抛出“页面未find”错误。 ,任何窍门点击一个不可见的框架或陷阱的JavaScript错误不起作用,并最终丑陋的“网页无法显示”的错误我们在这种情况下使用的诀窍是通知用户浏览器特定的图像,点击自定义协议链接将打开一个应用程序,如果他们没有find应用程序的开放,他们可以点击一个“安装”页面在XD方面,这个方法比IE的ActiveX方法更好,对于FF和Chrome,只要继续并启动自定义协议没有任何检测。让用户告诉你他看到的。对于Safari,:(没有答案呢

这不是一个微不足道的任务; 一个选项可能是使用签名代码,您可以利用它来访问registry和/或文件系统(请注意,这是一个非常昂贵的选项)。 代码签名也没有统一的API或规范,因此您需要为每个目标浏览器生成特定的代码。 支持噩梦。

另外,我知道游戏内容传送系统Steam似乎也没有解决这个问题。

这是另一个黑客的答案,将需要(希望轻)修改您的应用程序的“电话回家”发射。

  1. 用户点击链接,试图启动应用程序。 一个唯一的标识符放在链接中,以便它在启动时传递给应用程序。 Web应用程序显示一个微调或这种性质的东西。
  2. 网页然后开始检查具有相同唯一ID的应用的“应用电话家庭”事件。
  3. 启动后,您的应用程序将使用唯一标识符向您的Web应用程序发送一个HTTPpost,以指示是否存在。
  4. 无论是网页看到,应用程序最终启动,或继续与“请下载”页面。