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


82

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

http://

mailto://

custom://

Я зарегистрировал приложение WinForms, чтобы ответить соответствующим образом. Все это отлично работает.

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

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

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


5
Я думаю, что это возможно только в коде Chrome (например, XPCOM, ActiveX и т. Д.). В противном случае это было бы проблемой конфиденциальности («Мы обнаружили, что вы используете Eudora. Перейдите на FooMail сегодня!»). Но, пожалуйста, уточните, какие браузеры / ОС вас интересуют.
Мэтью Флашен,

1
Хороший замечание, но я был бы рад узнать, что что-то зарегистрировано для обработки моего проприетарного протокола acsfs: // Windows IE, FireFox и, в идеале, Safari
Крис Крафт,

Вы уже решили эту проблему?
jstuardo

Ответы:


35

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

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

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


1
: D Замечательная идея. Похоже, что есть способ, потому что это обычная потребность.
Chris Craft

2
В Firefox на Mac (возможно, в других браузерах) окно теряет фокус и запускается onblur, даже если приложение с пользовательским протоколом не запускается.
quano

Это достойное решение для Chrome, поскольку в нем нет обработки ошибок для протоколов. Это использовалось в сочетании с обнаружением других браузеров здесь: rajeshsegu.com/2012/09/browser-detect-custom-protocols/…
Peyton

В последнее время обнаружение протокола было большой головной болью. ;) Вышеупомянутый метод, кажется, несколько работает ... используя живой пример rajesh, найденный на rajeshsegu.com/fun/code/browser/detect.html, я получаю "true" в Chrome. Но если я проведу рефакторинг так, чтобы не было функции results () (которая, в свою очередь, использует окно предупреждения - блокирующий вызов) и позволю ей просто вернуть логическое значение, я получу false. Я каким-то образом чувствую, что предупреждение о блокировке - это также хакерский способ каким-то образом принудительно установить время ... Любое понимание, @scunliffe?
Грег Петтит

Этот метод работает в Chrome, за исключением случая, когда пользователь выбрал запоминание своего ответа, используя Win8 и не имеет приложения. В этом случае событие размытия происходит, даже если приложение не запускается
Пол Хагго

18

Нет отличного кросс-браузерного способа сделать это. В IE10 + на Win8 + новый msLaunchUriapi позволяет запускать протокол, например:

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


ЭТО НЕ РАБОТАЕТ - протестировано в браузерах Windows 7, IE

6
msLaunchUri работает только в Windows 8+.
EricLaw 07

Ссылка была мертва.
Qiulang

16

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


13

Кажется, нет простого способа через javascript обнаружить наличие установленного приложения, которое зарегистрировало обработчик протокола.

В модели iTunes Apple предоставляет URL-адреса своим серверам, которые затем предоставляют страницы, на которых выполняется некоторый javascript:

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

Таким образом, установщик iTunes, по-видимому, развертывает плагины для основных браузеров, присутствие которых затем можно обнаружить.

Если ваш плагин установлен, вы можете быть уверены, что перенаправление на URL-адрес вашего приложения будет успешным.


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

Почему бы не использовать FireBreath, как упоминалось здесь? stackoverflow.com/a/14758085/427793
swdev 08

11

Самое простое решение - спросить пользователя с первого раза.

Пример использования диалогового окна подтверждения 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/'

Файлы cookie можно чистить ежедневно. Нет ли лучшего способа сделать cookie на основе Flash?

Что ж, если файл cookie будет удален, пользователю снова будет предложено.
Натим

Я думаю, что vscode использует этот метод, проверьте их сайт marketplace.visualstudio.com
Qiulang

5

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

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

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

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

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

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


4

Я наконец смог получить кроссбраузерное решение (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, вы знаете, что нужно сообщить пользователю, что приложение (т. Е. Его собственный протокол) не установлено.


Это не работает для IE. Как это должно работать? какая связь между myWindow.location.href;iframe и iframe srcопределена внутри этого окна? Это должно вызывать исключение? Это не зависит от того, поддерживается ли специальный протокол или нет.
Burjua 05

3

Вы говорите, что вам нужно обнаружить обработчики протоколов браузера - правда?

Что, если бы вы сделали что-то вроде того, что происходит при загрузке файла из sourceforge? Допустим, вы хотите открыть myapp: // something. Вместо того, чтобы просто создавать ссылку на нее, создайте ссылку на другую HTML-страницу, доступ к которой осуществляется через HTTP. Затем на этой странице скажите, что вы пытаетесь открыть для них приложение. Если это не сработает, им необходимо установить ваше приложение, что они могут сделать, щелкнув ссылку, которую вы предоставите. Если это сработает, то все готово.


4
Бесполезно предполагать, что это бесполезно. Мне кажется очевидным, что возможность условно показать ссылку для запуска или загрузки - или даже условно запустить или загрузить при нажатии на ссылку - будет лучшим UX, чем сообщить пользователю, что сначала нужно установить.
StuartQ

3

Вы можете попробовать что-то вроде этого:

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

Нет, не работает в Firefox 27. (Не тестировал в других браузерах)
Blaise

1
НЕ РАБОТАЕТ - протестировано в Windows 7, IE, Firefox, Opera, Chrome

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>

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


1
Я обнаружил, что все еще получаю сообщение «Firefox не знает, как открыть этот адрес, потому что протокол (tel) не связан с какой-либо программой». сообщение перед блоком catch
Дибстер,

6
protocolLong возвращает результаты только для «известных» протоколов (file:, mailto:, gopher:, ftp:, http:, https:, news :), но не для других протоколов приложений.
EricLaw

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, и если вы отбрасываете пользовательское значение платформы публикации, обнаружить это в javascript с помощью navigator.userAgent довольно просто.

К счастью, другие основные браузеры, такие как Firefox и Chrome (за исключением Safari :(), не выдают ошибки «страница не найдена» при нажатии ссылки с настраиваемым протоколом, а протокол не установлен на компьютере пользователя. IE здесь очень неумолимый , любой трюк, чтобы щелкнуть невидимый фрейм или перехватить ошибки JavaScript, не работает и заканчивается уродливой ошибкой «веб-страница не может быть отображена». В нашем случае мы используем уловку для информирования пользователей с помощью изображений, специфичных для браузера, которые нажимают на пользовательский протокол ссылка откроет приложение. И если они не обнаружат, что приложение открывается, они могут щелкнуть страницу «установить». С точки зрения XD это wprks намного лучше, чем подход ActiveX для IE. Для FF и Chrome просто продолжайте и запустить собственный протокол без какого-либо обнаружения. Позвольте пользователю рассказать вам, что он видит. Для Safari:(ответов пока нет


Расширение User-Agent - распространенный, но проблемный подход. blogs.msdn.com/b/ieinternals/archive/2009/10/08/…
EricLaw

0

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

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


2
Подписанный код должен быть подписан сертификатом, который устанавливается вместе с приложением, обрабатывающим custom: //, чтобы не было необходимости в действительно дорогом сертификате приложения, подписанном кем-то вроде verisign.
WhyNotHugo

0

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

  1. Пользователь нажимает на ссылку, которая пытается запустить приложение. В ссылку помещается уникальный идентификатор, который передается приложению при запуске. Веб-приложение показывает спиннер или что-то в этом роде.
  2. Затем веб-страница начинает проверку на наличие события «приложение телефона домой» из приложения с тем же уникальным идентификатором.
  3. При запуске ваше приложение отправляет HTTP-сообщение в ваше веб-приложение с уникальным идентификатором, чтобы указать присутствие.
  4. Либо веб-страница видит, что приложение в конечном итоге запущено, либо переходит на страницу «Загрузите».
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.