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

IT技术 javascript
2021-02-05 00:40:52

我们正在使用注册自己协议的软件。我们可以从浏览器然后通过链接运行应用程序,如:

customprotocol://do_this.

但是有没有办法检查用户系统是否支持这种自定义协议?如果没有,我们想请用户先安装软件。

例如:

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

编辑 我知道 protocolLong 属性,但它仅适用于 IE。

6个回答

不幸的是,没有简单的方法可以实现这一目标。当然没有任何方法可以预先确定是否安装了协议处理程序。

正如您所提到的,Internet Explorer具有该protocolLong属性,但我无法让它为所有自定义协议处理程序返回“未知协议”以外的任何内容——如果有人知道如何让 IE 返回正确的值,请告诉我所以我可以更新这个部分。我在 IE 中找到的最佳解决方案是附加到用户代理字符串或安装浏览器扩展以及您的应用程序,以公开 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,所以 atry...catch工作得很好。

Chrome官方在这方面很糟糕。如果自定义协议处理程序失败,它绝对会压缩。如果处理程序有效……您猜对了……它确实可以压缩。恐怕没有办法区分这两者。

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

欢迎您尝试在调查时编写测试代码(我自己对它有既得利益)。它与 Opera 和 Firefox 交叉兼容,但目前在 IE 和 Chrome 中没有任何作用。

@BrianCannard 这至少在 Chrome 中不再有效
2021-03-22 00:40:52
由于这个答案是在 2010 年写的,我应该为 Google 员工提一下,在更新版本的 Firefox 中,try/catch 方法似乎不再有任何效果。(iframe 仍然避免了错误页面)
2021-03-25 00:40:52
@mix3d 谢谢你让我知道,我删除了链接
2021-03-27 00:40:52
@d512 太糟糕了,链接现在坏了。
2021-04-02 00:40:52
如果处理程序打开,Chrome 和 Safari 会失去焦点(可以使用 window.onblur)。
2021-04-12 00:40:52

为了配合我们自己的经验,我们使用 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——虽然不是“隐形”检测方法(IE 会要求用户允许运行 ActiveXObjects),但这仍然是一个聪明的方法。特别是对于没有其他解决方法的 Chrome,浏览器插件可能是某些人的唯一选择。
2021-03-17 00:40:52
FireBreath 是解决这个问题的一个很好的方法,如果这就是你所需要的,它真的很简单。我已经为此使用了它(在尝试找到相同问题的解决方案之后)。
2021-03-17 00:40:52
众所周知,Mozilla 和 Google 认为插件是一种传统技术,Chrome 开始逐步淘汰 NPAPI,developer.chrome.com/ extensions/npapi
2021-04-08 00:40:52
嗨 Gearoid,你能描述一下你是如何使用 FireBreath 创建你的插件的吗?
2021-04-08 00:40:52

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

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

并不是说我会永远使用它,而是开箱即用,认为我必须给你 +1
2021-03-15 00:40:52
我同意这是一个黑客,但它也是一个聪明的解决方法。+1
2021-03-19 00:40:52
非常好的答案!+1
2021-04-03 00:40:52
我不明白
2021-04-09 00:40:52

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 建议的条件注释。

msLaunchUri 仅存在于 +win8 上
2021-03-14 00:40:52
@aaronk6。我不确定这是否正确,因为我在 Windows 7 上使用了这种方法。
2021-03-17 00:40:52
我在 Windows 7 上检查了 IE 10 和 IE 11。在这两种情况下,typeof navigator.msLaunchUri返回"undefined". 此外,Microsoft 已确认此 API 尚未添加到 Windows 7:Windows 7 中不存在记录的 API 函数“navigator.msLaunchUri”(请参阅 2014 年 5 月 5 日下午 12:27 的评论)
2021-03-28 00:40:52
请注意,该msLaunchUri方法仅存在于Windows 8 上的IE >= 10 中
2021-04-01 00:40:52
感谢@aaronk6 的详细信息。我一定从未注意到它实际上并没有使用这个调用(并回退到替代方法)。我会更新我的答案。
2021-04-10 00:40:52

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

+1,这是 IE 9 及更低版本的一个很好的解决方法,马克。不幸的是,IE 10 不再支持条件注释,但也许他们解决了这个protocolLong问题。
2021-03-25 00:40:52
对于 Chrome,也许可以在安装过程中注册一个 MIME 时间,并使用window.navigator.mimeTypes[i]. 我找不到一种简单的方法来做到这一点。
2021-03-27 00:40:52