¿Cómo detectar los controladores de protocolo del navegador?


82

He creado un controlador de protocolo de URL personalizado.

http://

mailto://

custom://

He registrado una aplicación WinForms para responder en consecuencia. Todo esto funciona muy bien.

Pero me gustaría poder manejar con gracia el caso en el que el usuario aún no tiene instalado el controlador de protocolo de URL personalizado.

Para poder hacer esto, necesito poder detectar los controladores de protocolo registrados del navegador, supongo que de JavaScript. Pero no he podido encontrar una manera de sondear la información. Espero encontrar una solución a este problema.

Gracias por cualquier idea que pueda compartir.


5
Creo que esto solo sería posible en el código Chrome (es decir, XPCOM, ActiveX, etc.). De lo contrario, sería un problema de privacidad ("Hemos detectado que usa Eudora. ¡Cambie a FooMail hoy!"). Pero aclare en qué navegador (s) / SO (s) está interesado.
Matthew Flaschen

1
Buen punto, pero me alegrará saber que algo está registrado para manejar mi protocolo propietario acsfs: // Windows IE, FireFox e idealmente Safari
Chris Craft

¿Has solucionado ya este problema?
jstuardo

Respuestas:


35

Esta sería una forma muy , muy peligrosa de hacer esto ... pero ¿funcionaría?

  • Pon el enlace como de costumbre ...
  • Pero adjunte un controlador onclick, que establece un temporizador y agrega un controlador onblur para la ventana
  • (en teoría) si el navegador maneja el enlace (aplicación X) se cargará robando el foco de la ventana ...
  • Si se activa el evento onblur, borre el temporizador ...
  • De lo contrario, en 3-5 segundos, deje que se active el tiempo de espera ... y notifique al usuario "Mmm, parece que no tiene instalada la aplicación Mega Uber Cool ... ¿le gustaría instalarla ahora? (Ok) (Cancelar)"

Lejos de ser a prueba de balas ... ¿pero podría ayudar?


1
: D Es una idea inteligente. Parece que habría una forma porque parece una necesidad común.
Chris Craft

2
En Firefox en Mac (tal vez más navegadores), la ventana pierde el foco y onblur se activa aunque la aplicación con el protocolo personalizado no se inicie.
quano

Esta es una solución decente para Chrome, ya que no tiene ningún tipo de manejo de errores para los protocolos. Esto se ha utilizado junto con la detección de otros navegadores aquí: rajeshsegu.com/2012/09/browser-detect-custom-protocols/…
Fillip Peyton

La detección de protocolos ha sido un gran dolor de cabeza últimamente. ;) El método anterior parece funcionar un poco ... usando el ejemplo en vivo de rajesh que se encuentra en rajeshsegu.com/fun/code/browser/detect.html Me estoy volviendo "verdadero" en Chrome. Pero si refactorizo ​​para que no haya una función results () (que a su vez usa un cuadro de alerta, una llamada de bloqueo) y dejo que devuelva un booleano, obtengo falso. De alguna manera siento que la alerta de bloqueo también es una forma hacky de forzar el tiempo de alguna manera ... ¿alguna idea, @scunliffe?
Greg Pettit

Este método sí funciona en Chrome, excepto en el caso de que el usuario haya seleccionado recordar su respuesta, usando Win8 y no tenga la aplicación. En este caso, el evento de desenfoque ocurre aunque la aplicación no se pueda iniciar
Paul Haggo

18

No existe una forma excelente de hacerlo en varios navegadores. En IE10 + en Win8 +, una nueva msLaunchUriapi le permite lanzar un protocolo, así:

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

Si el protocolo no está instalado, se activará la devolución de llamada de falla. De lo contrario, el protocolo se iniciará y se activará la devolución de llamada exitosa.

Discuto este tema un poco más aquí: http://blogs.msdn.com/b/ieinternals/archive/2011/07/14/url-protocols-application-protocols-and-asynchronous-pluggable-protocols-oh-my .aspx


NO FUNCIONA - probado en Windows 7, navegadores IE

6
msLaunchUri es solo para Windows 8+.
EricLaw

El vínculo estaba muerto.
Qiulang

16

HTML5 define esquemas personalizados y manejadores de contenido (que yo sepa, Firefox es el único implementador hasta ahora), pero desafortunadamente actualmente no hay forma de verificar si ya existe un manejador; se ha propuesto , pero no hubo seguimiento. Esto parece una característica fundamental para usar los controladores personalizados de manera efectiva y nosotros, como desarrolladores, debemos prestar atención a este problema para implementarlo.


13

Parece que no hay una forma sencilla a través de JavaScript para detectar la presencia de una aplicación instalada que haya registrado un controlador de protocolo.

En el modelo de iTunes, Apple proporciona direcciones URL a sus servidores, que luego proporcionan páginas que ejecutan algunos javascript:

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

Entonces, el instalador de iTunes aparentemente implementa complementos para los principales navegadores, cuya presencia puede detectarse.

Si su complemento está instalado, puede estar razonablemente seguro de que la redirección a la URL específica de su aplicación se realizará correctamente.


2
Esta debería ser la solución más confiable. Pero quiero decir que necesitas instalar y también crear un complemento para la mayor parte del navegador y eso es un poco complicado. Podría ser más fácil para el usuario poder redirigir al usuario a la página de descarga.
Natim

¿Por qué no usar FireBreath como se menciona aquí? stackoverflow.com/a/14758085/427793
swdev

10

Lo que parece la solución más fácil es preguntarle al usuario la primera vez.

Usando un cuadro de diálogo de confirmación de Javascript por ejemplo:

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/'

Las cookies se pueden eliminar limpias a diario. ¿No hay mejor manera de hacer una cookie basada en Flash?

Bueno, si se eliminan las cookies, se volverá a preguntar al usuario.
Natim

5

Si tiene el control del programa que está tratando de ejecutar (el código), una forma de ver si el usuario tuvo éxito al ejecutar la aplicación sería:

  1. Antes de intentar abrir el protocolo personalizado, realice una solicitud AJAX a un script del servidor que guarde la intención del usuario en una base de datos (por ejemplo, guarde el ID de usuario y lo que quería hacer).

  2. Intente abrir el programa y transmita los datos de la intención.

  3. Haga que el programa haga una solicitud al servidor para eliminar la entrada de la base de datos (utilizando los datos de la intención para encontrar la fila correcta).

  4. Haga que javascript sondee el servidor por un tiempo para ver si la entrada de la base de datos se ha ido. Si la entrada desaparece, sabrá que el usuario logró abrir la aplicación; de lo contrario, la entrada permanecerá (puede eliminarla más tarde con cronjob).

No he probado este método, solo lo pensé.


4

Finalmente pude obtener una solución de navegador cruzado (Chrome 32, Firefox 27, IE 11, Safari 6) que funciona con una combinación de esto y una extensión de Safari súper simple. Gran parte de esta solución se ha mencionado de una forma u otra en esta y otra pregunta .

Aquí está el guión:

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

La extensión de Safari fue fácil de implementar. Consistía en una sola línea de script de inyección:

myinject.js:

window.postMessage("myappinstalled", window.location.origin);

Luego, en la página web JavaScript, primero debe registrar el evento del mensaje y establecer una bandera si se recibe el mensaje:

window.addEventListener('message', function (msg) {
    if (msg.data === "myappinstalled") {
        myappinstalledflag = true;
    }
}, false);

Esto supone que la aplicación que está asociada con el protocolo personalizado administrará la instalación de la extensión de Safari.

En todos los casos, si la devolución de llamada devuelve falso, sabrá informar al usuario que la aplicación (es decir, su protocolo personalizado) no está instalada.


No funciona para IE. Como se supone que funciona? ¿Cuál es la conexión entre un myWindow.location.href;iframe srcdefinido dentro de esa ventana? ¿Se supone que debe lanzar una excepción? No lo hace independientemente de si el protocolo personalizado es compatible o no.
Burjua

3

Dice que necesita detectar los controladores de protocolo del navegador, ¿de verdad?

¿Qué pasa si hiciste algo como lo que sucede cuando descargas un archivo de sourceforge? Digamos que quieres abrir myapp: // algo. En lugar de simplemente crear un enlace, cree un enlace a otra página HTML a la que se acceda a través de HTTP. Luego, en esa página, diga que está intentando abrir la aplicación para ellos. Si no funciona, deben instalar su aplicación, lo que pueden hacer haciendo clic en el enlace que proporcionará. Si funciona, entonces está todo listo.


4
Es inútil sugerir que esto no sería útil. Me parece obvio que poder mostrar condicionalmente un enlace de inicio o descarga, o incluso iniciar o descargar condicionalmente al hacer clic en un enlace, sería una experiencia de usuario superior a decirle al usuario que necesita instalar primero.
StuartQ

3

Puedes probar algo como esto:

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

No, no funciona en Firefox 27 (no lo probé en otros navegadores)
Blaise

1
NO FUNCIONA - probado en Windows 7, IE, Firefox, Opera, Chrome

1

Estoy tratando de hacer algo similar y acabo de descubrir un truco que funciona con Firefox. Si lo combina con el truco para IE, puede tener uno que funcione en ambos navegadores principales (no estoy seguro de si funciona en Safari y sé que no funciona en 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");
        }
    }
}

Para que esto funcione, también debe tener un enlace oculto en algún lugar de la página, como este:

<a id="testprotocollink" href="custom://testprotocol" style="display: none;">testprotocollink</a>

Es un poco hacky pero funciona. Desafortunadamente, la versión de Firefox todavía muestra la alerta predeterminada que aparece cuando intenta visitar un enlace con un protocolo desconocido, pero ejecutará su código después de que se descarte la alerta.


1
Descubrí que todavía tengo el mensaje "Firefox no sabe cómo abrir esta dirección, porque el protocolo (tel) no está asociado con ningún programa". mensaje antes del bloque de captura
Deebster

6
protocolLong solo devuelve resultados para protocolos "conocidos" (archivo:, mailto:, gopher:, ftp:, http:, https:, noticias :) y no para otros protocolos de aplicación.
EricLaw

1

Este fue un enfoque recomendado para IE por el soporte de Microsoft

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

"Si tiene cierto control sobre los archivos binarios que se instalan en la máquina de un usuario, verificar el UA en el script parece un enfoque relevante: HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Internet Settings \ 5.0 \ User Agent \ Post Platform" - Por soporte de M $

Cada página web tiene acceso a la cadena userAgent y si suelta un valor de plataforma de publicación personalizada, detectar esto en javascript usando navigator.userAgent es bastante simple.

Afortunadamente, otros navegadores importantes como Firefox y Chrome (salvo Safari :(), no arrojan errores de "página no encontrada" cuando se hace clic en un enlace con un protocolo personalizado y el protocolo no está instalado en la máquina del usuario. IE es muy implacable aquí , cualquier truco para hacer clic en un marco invisible o capturar errores de javascript no funciona y termina con un feo error "no se puede mostrar la página web". El truco que usamos en nuestro caso es informar a los usuarios con imágenes específicas del navegador que hacen clic en el protocolo personalizado El enlace abrirá una aplicación. Y si no encuentran la aplicación que se abre, pueden hacer clic en una página de "instalación". En términos de XD, esto funciona mucho mejor que el enfoque ActiveX para IE. Para FF y Chrome, simplemente adelante e inicie el protocolo personalizado sin ninguna detección. Deje que el usuario le diga lo que ve. Para Safari,:(aún no hay respuestas


La extensión User-Agent es un enfoque común, pero problemático. blogs.msdn.com/b/ieinternals/archive/2009/10/08/…
EricLaw

0

Ésta no es una tarea trivial; una opción podría ser utilizar código firmado, que podría aprovechar para acceder al registro y / o al sistema de archivos (tenga en cuenta que esta es una opción muy cara ). Tampoco existe una API o especificación unificada para la firma de código, por lo que se le pedirá que genere un código específico para cada navegador de destino. Una pesadilla de apoyo.

Además, sé que Steam , el sistema de entrega de contenido de juegos, tampoco parece tener este problema resuelto.


2
El código firmado debe estar firmado por un certificado que se instala junto con la aplicación que maneja custom: // para que no haya necesidad de un certificado de aplicación realmente costoso firmado por alguien como verisign.
WhyNotHugo

0

Aquí hay otra respuesta hacky que requeriría (con suerte, una ligera) modificación de su aplicación para 'llamar a casa' en el lanzamiento.

  1. El usuario hace clic en el enlace, que intenta iniciar la aplicación. Se coloca un identificador único en el enlace, de modo que se pasa a la aplicación cuando se inicia. La aplicación web muestra una ruleta o algo por el estilo.
  2. Luego, la página web comienza a buscar un evento de "aplicación de teléfono de inicio" desde una aplicación con este mismo ID único.
  3. Cuando se inicia, su aplicación realiza una publicación HTTP en su aplicación web con el identificador único, para indicar presencia.
  4. O la página web ve que la aplicación se inició, eventualmente, o continúa con una página de "descarga".
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.