我们正在使用注册自己协议的软件。我们可以从浏览器运行应用程序,然后通过以下链接运行:
customprotocol://do_this.
但有没有办法检查用户系统支持的自定义协议?如果不是,我们首先要求用户安装软件。
E.g:
if (canHandle ('customprotocol')) {
// run software
}
else {
// ask to install
}
修改 我知道protocolLong属性,但它只适用于IE。
答案 0 :(得分:45)
不幸的是,没有简单的方法来实现这一目标。当然没有预先确定是否安装协议处理程序的方法。
正如您所提到的, 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 :(得分: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
}
}
答案 2 :(得分:7)
Windows 8上的Internet Explorer 10引入了非常有用的navigator.msLaunchUri方法,用于启动自定义协议URL并检测成功或失败。例如:
if (typeof (navigator.msLaunchUri) == typeof (Function)) {
navigator.msLaunchUri(witchUrl,
function () { /* Success */ },
function () { /* Failure */ showError(); });
return;
}
Windows 7 / IE 9及更低版本支持@ mark-kahn建议的条件评论。
答案 3 :(得分:5)
这是一个非常简单的答案:在注册自定义协议时安装一个不寻常的字体。然后使用javascript来检查该字体是否存在,使用like this。
确定它是一个黑客,但与其他答案不同,它可以在浏览器和操作系统上运行。
答案 4 :(得分:4)
对于Internet Explorer,我发现的最佳解决方案是使用Conditionl评论&版本向量(应用程序必须在安装协议时向注册表写入内容,请参阅http://msdn.microsoft.com/en-us/library/ms537512.aspx#Version_Vectors)。 protocolLong不适用于自定义协议。
答案 5 :(得分:3)
在移动设备上,您可以使用嵌入式iframe在自定义协议和已知协议(网络或应用商店)之间自动切换,请参阅https://gist.github.com/2662899
答案 6 :(得分:2)
我只想解释Mark先前的答案(有些人不理解,例如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 <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)用户第一次打开此页面时,将不会安装字体,因此他会收到一条消息,说明&#34;请运行可执行文件以安装自定义协议...&#34;。
3)他将运行将安装该字体的可执行文件。您的exe只需将字体文件(在我的情况下是KONFUC __。ttf)复制到C:\ Windows目录或使用这样的代码(Delphi上的示例):
// Adding the font ..
AddFontResource(PChar('XXXFont.TTF'));
SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
4)之后,当用户再次运行Web应用程序时,他会获得“#34;自定义协议可用!”#34;消息,因为这次安装了字体。
在Google Chrome,Internet Explorer和Firefox上测试过 - 效果很好!
答案 7 :(得分:0)
关于Firefox,我搜索了大部分文章,包括 Andy E 在这里的答案,以及要点Cross-browser implementation of navigator.msLaunchUri或https://github.com/ismailhabib/custom-protocol-detection使用
iframe.contentWindow.location.href = uri
但是自Firefox 64起,它就停止了工作,例如此处https://github.com/ismailhabib/custom-protocol-detection/issues/37也证实了这一点。
所以FF 64+我发现我可以使用Chrome的方法blurHandler
或使用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();
}
}