Как определить обработчики протоколов браузера?

Я создал собственный обработчик протокола URL.

http://

mailto://

custom://

Я зарегистрировал приложение WinForms, чтобы ответить соответственно. Это все прекрасно работает.

Но я хотел бы иметь возможность корректно обрабатывать случай, когда у пользователя еще не установлен обработчик пользовательского протокола URL.

Для того, чтобы сделать это, мне нужно иметь возможность обнаруживать зарегистрированные обработчики протокола браузера, я бы предположил из JavaScript. Но я не смог найти способ опроса информации. Я надеюсь найти решение этой проблемы.

Спасибо за любые идеи, которыми вы могли бы поделиться.

15 ответов

Это был бы очень, очень хакерский способ сделать это... но будет ли это работать?

  • Поставь ссылку как обычно...
  • Но присоедините к нему обработчик onclick, который устанавливает таймер и добавляет обработчик onblur для окна
  • (теоретически), если браузер обрабатывает ссылку (приложение X) загрузит кражу фокуса из окна...
  • Если происходит событие onblur, очистите таймер...
  • В противном случае в течение 3-5 секунд дайте своему таймауту сработать... и уведомите пользователя "Хм, похоже, у вас не установлено приложение Mega Uber Cool... вы хотите установить его сейчас? (ОК) (Отмена)"

Далеко не пуленепробиваемый... но это может помочь?

HTML5 определяет пользовательскую схему и обработчики контента (насколько мне известно, Firefox пока является единственным разработчиком), но, к сожалению, в настоящее время нет способа проверить, существует ли обработчик - он был предложен, но не было никаких последующих действий. Это кажется критически важным для эффективного использования пользовательских обработчиков, и мы, как разработчики, должны обратить внимание на эту проблему, чтобы реализовать ее.

Там нет большой кросс-браузерный способ сделать это. В IE10+ на Win8+ новый 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

Вы можете использовать встроенный iframe для автоматического переключения между пользовательским протоколом и известным (интернет-магазин или магазин приложений), см. https://gist.github.com/2662899

Похоже, что через 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/'

Если у вас есть контроль над программой, которую вы пытаетесь запустить (код), один из способов проверить, успешно ли пользователь запустил приложение:

  1. Прежде чем пытаться открыть пользовательский протокол, сделайте AJAX-запрос к серверному сценарию, который сохраняет намерение пользователя в базе данных (например, сохраните идентификатор пользователя и то, что он хотел сделать).

  2. Попробуйте открыть программу и передать данные о намерениях.

  3. Попросите программу сделать запрос на сервер, чтобы удалить запись в базе данных (используя данные намерения, чтобы найти правильную строку).

  4. Заставьте javascript опрашивать сервер на некоторое время, чтобы увидеть, не исчезла ли запись базы данных Если запись пропала, вы узнаете, что пользователь успешно открыл приложение, в противном случае запись останется (вы можете удалить ее позже с помощью cronjob).

Я не пробовал этот метод, просто подумал.

Я создал универсальную библиотеку для этой проблемы, исходя из предположения, что обработчик пользовательского протокола вызовет новое окно, чтобы вывести фокус из браузера.

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

Мне наконец удалось получить кросс-браузерное решение (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:// что-то. Вместо того, чтобы просто создать ссылку на него, создайте ссылку на другую HTML-страницу, доступ к которой осуществляется через HTTP. Затем на этой странице скажите, что вы пытаетесь открыть приложение для них. Если это не работает, им нужно установить ваше приложение, что они могут сделать, нажав на ссылку, которую вы предоставите. Если это работает, то все готово.

Это был рекомендуемый подход для IE при поддержке Microsoft

http://msdn.microsoft.com/en-us/library/ms537503%28VS.85%29.aspx

"Если у вас есть некоторый контроль над двоичными файлами, устанавливаемыми на компьютере пользователя, проверка UA в сценарии выглядит подходящим способом: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\5.0\User Agent\Post Platform " - При поддержке M$

Каждая веб-страница имеет доступ к строке userAgent, и если вы укажете значение пользовательской платформы, определить его в javascript с помощью navigator.userAgent довольно просто.

К счастью, другие крупные браузеры, такие как Firefox и Chrome (за исключением Safari:(), не выдают ошибки "страница не найдена", когда щелкают ссылку с пользовательским протоколом, а протокол не установлен на компьютере пользователя. IE здесь очень простителен любой трюк, чтобы щелкнуть в невидимом фрейме или перехватить ошибки javascript, не работает и заканчивается уродливой ошибкой "веб-страница не может быть отображена". Уловка, которую мы используем в нашем случае, состоит в том, чтобы информировать пользователей с изображениями, специфичными для браузера, которые нажимают на пользовательский протокол ссылка откроет приложение. И если они не обнаружат, что приложение открывается, они могут щелкнуть "страницу установки". С точки зрения XD этот wprks намного лучше, чем подход ActiveX для IE. Для 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>

Это немного глупо, но это работает. К сожалению, в версии Firefox по-прежнему появляется предупреждение по умолчанию, которое появляется при попытке перейти по ссылке с неизвестным протоколом, но оно будет запускать ваш код после того, как предупреждение будет отклонено.

Вот еще один хакерский ответ, который потребует (надеюсь, легкой) модификации вашего приложения, чтобы "позвонить домой" при запуске.

  1. Пользователь нажимает на ссылку, которая пытается запустить приложение. В ссылку помещается уникальный идентификатор, который передается приложению при запуске. Веб-приложение показывает спиннер или что-то в этом роде.
  2. Затем веб-страница начинает проверку на наличие события "домашний телефон приложения" из приложения с таким же уникальным идентификатором.
  3. При запуске ваше приложение отправляет HTTP-сообщение в ваше веб-приложение с уникальным идентификатором, чтобы указать наличие.
  4. Либо веб-страница видит, что приложение, в конце концов, запущено, либо переходит со страницы "пожалуйста, загрузите".

Это не тривиальная задача; Одним из вариантов может быть использование подписанного кода, который вы можете использовать для доступа к реестру и / или файловой системе (обратите внимание, что это очень дорогой вариант). Также нет унифицированного API или спецификации для подписи кода, поэтому вам потребуется сгенерировать определенный код для каждого целевого браузера. Кошмар поддержки.

Кроме того, я знаю, что Steam, система доставки игрового контента, похоже, тоже не решила эту проблему.

Другие вопросы по тегам