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

时间:2009-05-07 20:10:20

标签: javascript browser protocols moniker

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

http://

mailto://

custom://

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

但我希望能够优雅地处理用户尚未安装自定义URL协议处理程序的情况。

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

感谢您提供的任何想法。

15 个答案:

答案 0 :(得分:32)

这将是非常非常 hacky 这样做的方式...但这会有效?

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

远非防弹...但它可能会有所帮助?

答案 1 :(得分:17)

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

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

如果未安装协议,则会触发故障回调。否则,协议将启动,并且将触发成功回调。

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

答案 2 :(得分:16)

HTML5定义Custom scheme and content handlers(据我所知,Firefox是迄今为止唯一的implementor),但不幸的是,目前无法检查处理程序是否已经存在 - 它已经proposed ,但没有后续行动。这似乎是有效使用自定义处理程序的关键功能,我们作为开发人员应该关注此问题以实现它。

答案 3 :(得分:13)

似乎没有简单的方法通过javascript来检测已注册协议处理程序的已安装应用程序的存在。

在iTunes模型中,Apple为其服务器提供了网址,然后提供运行某些javascript的网页:

http://ax.itunes.apple.com/detection/itmsCheck.js

因此,iTunes安装程序显然会为主要浏览器部署插件,然后可以检测到它们的存在。

如果您的插件已安装,那么您可以合理地确定重定向到特定于应用的网址会成功。

答案 4 :(得分:13)

您可以使用嵌入式iframe在自定义协议和已知协议(网络应用商店或应用商店)之间自动切换,请参阅https://gist.github.com/2662899

答案 5 :(得分:9)

最简单的解决方案是第一次询问用户。

每个示例使用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/'

答案 6 :(得分:5)

如果您可以控制正在尝试运行的程序(代码),那么查看用户是否成功运行应用程序的一种方法是:

  1. 在尝试打开自定义协议之前,请向服务器脚本发出AJAX请求,该脚本将用户的意图保存在数据库中(例如,保存用户ID以及他想要做的事情)。

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

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

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

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

答案 7 :(得分:5)

我根据自定义协议处理程序将触发一个新窗口将焦点从浏览器中删除的假设,为此问题创建了一个通用库。

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

答案 8 :(得分:4)

您可以尝试这样的事情:

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

答案 9 :(得分:4)

我终于可以使用this和超简单的Safari扩展程序组合使用跨浏览器(Chrome 32,Firefox 27,IE 11,Safari 6)解决方案。在这个和other question中已经以这种或那种方式提到了大部分解决方案。

这是脚本:

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);

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

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

答案 10 :(得分:3)

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

如果您执行类似于从sourceforge下载文件时发生的情况,该怎么办?假设您要打开myapp://某事。不是简单地创建指向它的链接,而是创建指向通过HTTP访问的另一个HTML页面的链接。然后,在该页面上,说您正在尝试为它们打开应用程序。如果它不起作用,他们需要安装您的应用程序,他们可以通过单击您将提供的链接来完成。如果它确实有效,那么你就完全了。

答案 11 :(得分:1)

我正在尝试做类似的事情,我刚刚发现了一个适用于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>

有点hacky但它​​确实有效。不幸的是,Firefox版本仍会弹出当您尝试访问具有未知协议的链接时出现的默认警报,但它会在警报解除后运行您的代码。

答案 12 :(得分:1)

这是Microsoft支持的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 $支持

每个网页都可以访问userAgent字符串,如果您删除自定义帖子平台值,则使用navigator.userAgent在javascript中检测到这一点非常简单。

幸运的是,Firefox和Chrome等其他主流浏览器(限制Safari :())在单击自定义协议的链接并且用户计算机上未安装协议时,不会抛出“找不到页面”错误.IE是在这里非常无情,在隐形框架中点击或陷入javascript错误的任何技巧都不起作用并最终导致丑陋的“网页无法显示”错误。我们在我们的案例中使用的技巧是通过浏览器特定图像通知用户点击自定义协议链接将打开一个应用程序。如果他们没有找到应用程序打开,他们可以点击“安装”页面。就XD而言,这种方式比IE的ActiveX方法更好。 对于FF和Chrome,只需继续并启动自定义协议,无需任何检测。让用户告诉你他看到了什么。 对于Safari,:(暂无答案

答案 13 :(得分:0)

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

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

答案 14 :(得分:0)

这是另一个苛刻的答案,需要(希望是轻微的)修改您的应用程序到电话之家&#39;在发布会上。

  1. 用户点击链接,尝试启动该应用程序。一个特别的 标识符放在链接中,以便将其传递给 应用程序启动时。 Web应用程序显示了一个微调器或类似的东西。
  2. 网页然后开始检查a &#39;应用手机回家&#39;来自具有相同唯一ID的应用的活动。
  3. 启动时,您的应用程序会在您的网络应用中发布HTTP帖子 使用唯一标识符来表示存在。
  4. 网页会看到应用程序最终启动,或继续下载&#39;请下载&#39;页。