我创建了一个自定义 URL 协议处理程序。
http://
mailto://
custom://
我已经注册了一个 WinForms 应用程序来做出相应的响应。这一切都很好。
但我希望能够优雅地处理用户尚未安装自定义 URL 协议处理程序的情况。
为了能够做到这一点,我需要能够检测浏览器的注册协议处理程序,我会假设来自 JavaScript。但我一直无法找到一种方法来轮询信息。我希望找到解决这个问题的方法。
感谢您可以分享的任何想法。
我创建了一个自定义 URL 协议处理程序。
http://
mailto://
custom://
我已经注册了一个 WinForms 应用程序来做出相应的响应。这一切都很好。
但我希望能够优雅地处理用户尚未安装自定义 URL 协议处理程序的情况。
为了能够做到这一点,我需要能够检测浏览器的注册协议处理程序,我会假设来自 JavaScript。但我一直无法找到一种方法来轮询信息。我希望找到解决这个问题的方法。
感谢您可以分享的任何想法。
这将是一种非常非常 老套的方法......但这会奏效吗?
远非防弹......但它可能会有所帮助?
没有很好的跨浏览器方法可以做到这一点。在 Win8+ 上的 IE10+ 中,一个新的msLaunchUri
api 使您能够启动一个协议,如下所示:
navigator.msLaunchUri('skype:123456',
function()
{
alert('success');
},
function()
{
alert('failed');
}
);
如果未安装协议,将触发失败回调。否则,协议将启动并触发成功回调。
我在这里进一步讨论这个话题: https ://web.archive.org/web/20180308105244/https://blogs.msdn.microsoft.com/ieinternals/2011/07/13/understanding-protocols/
这个话题是最近(2021 年)感兴趣的;请参阅https://github.com/fingerprintjs/external-protocol-flooding进行讨论。
HTML5 定义了自定义方案和内容处理程序(据我所知,Firefox 是目前唯一的实现者),但不幸的是,目前无法检查处理程序是否已经存在——它已经被提出,但没有后续行动。这似乎是有效使用自定义处理程序的关键特性,我们作为开发人员应该注意这个问题,以便实现它。
似乎没有直接的方法通过 javascript 来检测是否存在已注册协议处理程序的已安装应用程序。
在 iTunes 模型中,Apple 为其服务器提供 url,然后提供运行一些 javascript 的页面:
http://ax.itunes.apple.com/detection/itmsCheck.js
因此,iTunes 安装程序显然为主要浏览器部署了插件,然后可以检测到它们的存在。
如果您的插件已安装,那么您可以合理地确定重定向到您的应用程序特定的 url 会成功。
最简单的解决方案是在第一时间询问用户。
每个示例使用 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/'
如果您可以控制您尝试运行的程序(代码),那么查看用户是否成功运行应用程序的一种方法是:
在尝试打开自定义协议之前,向服务器脚本发出 AJAX 请求,该脚本将用户的意图保存在数据库中(例如,保存用户 ID 和他想要做什么)。
尝试打开程序,并传递意图数据。
让程序向服务器发出请求以删除数据库条目(使用意图数据查找正确的行)。
让 javascript 轮询服务器一段时间以查看数据库条目是否消失。如果条目消失了,您将知道用户已成功打开应用程序,否则条目将保留(您可以稍后使用 cronjob 将其删除)。
这个方法我没试过,只是想。
我终于得到了一个跨浏览器(Chrome 32、Firefox 27、IE 11、Safari 6)的解决方案,它结合了这个和一个超级简单的 Safari 扩展。在这个和另一个问题中以一种或另一种方式提到了这个解决方案的大部分。
这是脚本:
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,您就知道通知用户应用程序(即,它的自定义协议)未安装。
你可以尝试这样的事情:
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://something。与其简单地创建指向它的链接,不如创建指向通过 HTTP 访问的另一个 HTML 页面的链接。然后,在该页面上,假设您正在尝试为他们打开应用程序。如果它不起作用,他们需要安装您的应用程序,他们可以通过单击您提供的链接来完成。如果它确实有效,那么你就准备好了。
这是 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 而言,此 wprks 比 IE 的 ActiveX 方法更好。对于 FF 和 Chrome,请继续并在没有任何检测的情况下启动自定义协议。让用户告诉你他看到了什么。对于 Safari,:(还没有答案
我正在尝试做类似的事情,我刚刚发现了一个适用于 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 版本仍然会在您尝试访问具有未知协议的链接时弹出默认警报,但它会在警报解除后运行您的代码。
这是另一个 hacky 答案,需要(希望是轻量)修改您的应用程序以在启动时“打电话回家”。