Как проверить, поддерживается ли пользовательский протокол
Мы используем программное обеспечение, которое регистрирует собственный протокол. Мы можем запустить приложение из браузера, затем по ссылке, например:
customprotocol://do_this.
но есть ли способ проверить, поддерживается ли такой пользовательский протокол системой пользователя? Если нет, мы хотели бы попросить пользователя сначала установить программное обеспечение.
Например:
if (canHandle ('customprotocol')) {
// run software
}
else {
// ask to install
}
Edit Я знаю о свойстве protocolLong, но оно работает только в IE.
7 ответов
К сожалению, нет простого способа достичь этого. Конечно, нет способа заранее определить, установлен ли обработчик протокола.
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
так try...catch
работает просто отлично.
Хром официально отстой в этом отношении. Если обработчик пользовательского протокола завершается неудачно, он делает абсолютно zip. Если обработчик работает... как вы уже догадались... он делает абсолютно zip. Боюсь, нет никакой разницы между ними.
Я не тестировал Safari, но боюсь, он будет таким же, как Chrome.
Вы можете попробовать тестовый код, который я написал, исследуя это (я лично был заинтересован в нем). Он совместим с Opera и Firefox, но в настоящее время ничего не делает в IE и Chrome.
Вот стандартный ответ: установите необычный шрифт во время регистрации своего пользовательского протокола. Затем используйте JavaScript, чтобы проверить, существует ли этот шрифт, используя что-то вроде этого.
Конечно, это взлом, но в отличие от других ответов, он будет работать в разных браузерах и операционных системах.
Просто чтобы поделиться своим собственным опытом, мы использовали 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
}
}
Internet Explorer 10 в Windows 8 представил очень полезный метод navigator.msLaunchUri для запуска URL-адреса настраиваемого протокола и определения успеха или неудачи. Например:
if (typeof (navigator.msLaunchUri) == typeof (Function)) {
navigator.msLaunchUri(witchUrl,
function () { /* Success */ },
function () { /* Failure */ showError(); });
return;
}
Windows 7 / IE 9 и ниже поддерживают условные комментарии, как предложено @mark-kahn.
Для Internet Explorer лучшее решение, которое я нашел, это использовать условные комментарии и версию вектора (приложение должно что-то записывать в реестр при установке протокола, см. http://msdn.microsoft.com/en-us/library/ms537512.aspx). protocolLong не работает для пользовательского протокола.
На мобильном устройстве вы можете использовать встроенный iframe для автоматического переключения между пользовательским протоколом и известным (интернет-магазин или магазин приложений), см. https://gist.github.com/2662899
Я просто хочу объяснить больше предыдущего ответа Марка (некоторые люди не поняли, например, 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) Когда пользователь впервые открывает эту страницу, шрифт не будет установлен, поэтому он получит сообщение "Пожалуйста, запустите исполняемый файл, чтобы установить собственный протокол...".
3) Он запустит исполняемый файл, который установит шрифт. Ваш exe-файл может просто скопировать файл шрифта (в моем случае это KONFUC__. Ttf) в каталог C:\Windows или использовать такой код (пример на Delphi):
// Adding the font ..
AddFontResource(PChar('XXXFont.TTF'));
SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
4) После этого, когда пользователь снова запускает веб-приложение, он получает "Пользовательский протокол доступен!" сообщение, потому что шрифт был установлен на этот раз.
Протестировано на Google Chrome, Internet Explorer и Firefox - отлично работает!
О Firefox, большинство статей, которые я искал в Google, включая ответ Энди Э. здесь, и эта суть Кроссбраузерная реализация 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();
}
}