Cómo acceder a recursos nativos desde una aplicación web

Hoy en día es cada vez más habitual utilizar tecnologías propias de la web para desarrollar interfaces de usuario. Ya no son sólo aplicaciones web, sino que aplicaciones que tradicionalmente se desarrollaban como aplicaciones de escritorio acaban siendo desarrolladas usando HTML y Javascript (o algún lenguaje transpilado a él).

Que eso sea algo bueno o malo es bastante discutible, y de hecho no faltan las quejas ante el elevador consumo de recursos de estas aplicaciones, como el consumo de memoria y CPU de Slack o de Visual Studio Code.

Si bien es cierto que la potencia de HTML y CSS ha crecido mucho y permite crear interfaces muy vistosos y usables (dejando de lado ese consumo de recursos), también es cierto que cuando llega el momento de interactuar con la plataforma en que se ejecutan estas aplicaciones “web” la cosa se complica.

No hay que olvidar que todas estas tecnologías están diseñadas para ser ejecutadas en el contexto de un navegador, limitando el acceso a la plataforma subyacente por motivos de seguridad, y eso hace que utilizar determinadas APIs o dispositivos hardware sea complicado. Muy complicado. Aunque las APIs de HTML continúan avanzando, a corto plazo siempre encontraremos cosas que no podemos hacer desde él y hay que buscar soluciones más imaginativas para poder salir del paso.

En este post vamos a ver algunas alternativas que podemos utilizar. No son las únicas alternativas existentes, y si alguien conoce más y las añade a los comentarios se lo agradeceré eternamente.

Olvidarnos de HTML

Si necesitamos acceder a APIs que están disponibles para aplicaciones nativas pero no para aplicaciones web, lo primero que deberíamos plantearnos es si realmente tiene sentido hacer una aplicación web.

Puede que nos resulte cómodo desarrollar el interfaz de usuario como una aplicación web porque estemos acostumbrados a ello. O que queramos aprovechar las ventajas de despliegue y ubicuidad que supone una aplicación web. Pero, seamos realistas, si tu aplicación web tiene que estar usando un montón de APIs que no están disponibles para ella, tal vez nos hayamos equivocado de tecnología y sea mejor recurrir a una aplicación nativa en lugar de estar luchando contra la tecnología que estas usando.

Tendrás que buscar soluciones para la parte de despliegue, actualización, etc., pero existen vías para ello y quizá sea más sencillo (y productivo) eso, en lugar de estar buscando atajos para saltarte las limitaciones de una aplicación web.

Plugin del navegador

Una opción que se ha utilizado tradicionalmente para evitar las limitaciones de las aplicaciones web es recurrir a un plugin del navegador. Desde los controles ActiveX y los applets de Java hasta Silverlight (¿alguién se acuerda de él?), pasando por Flash y otro montón de plugins que se instalaban en el navegador para ralentizarlo, añadirle agujeros de seguridad y, de paso, ofrecer alguna funcionalidad extra, como acceso al portapapeles o a los almacenes de certificados digitales.

Hoy en día me atrevería a decir que este tipo de soluciones han caído en desuso y han sido sustituidos por una variante: las extensiones de los navegadores, que muchas veces acaban cumpliendo una función similar a los plugins clásicos.

La principal pega que tienen los plugins es que implica desarrollar para cada navegador, con las APIs propias del navegador, y además necesitamos que el usuario se las instale. Además, el soporte para plugins en los navegadores es cada vez más restringido. Incluso el soporte para las extensiones es relativamente limitado (por ejemplo en dispositivos móviles) y la distribución de extensiones a veces implica pasar por plataformas concretas de publicación.

Plugin de PhoneGap/Electron

Si hemos optado por empaquetar nuestra aplicación con PhoneGap, Electron o similar, podemos utilizar los puntos de extensión que nos brindan los propios frameworks.

Normalmente todas estas herramientas nos permiten crear plugins con parte nativa y parte Javascript. Lo bueno de esto es que podemos tener un API uniforme accesible desde nuestra aplicación web, y luego desarrollar distintas implementaciones nativas de ese API para cada plataforma que queramos soportar.

Otra ventaja de este enfoque es que, puesto que estamos empaquetando nuestra aplicación con el navegador, ya partimos de la base de que el usuario se tiene que instalar algo (ya no accede por una URL, sino que ejecuta una aplicación), por lo que utilizar o no un plugin no supone un esfuerzo adicional para él, como sí ocurre con los plugins del navegador.

Como contrapartida, perdemos parte de las ventajas de una aplicación web “pura” y será necesario pensar en una estrategia de despliegue y actualización apropiada para nuestra aplicación. Además, a la hora de desarrollar el plugin podemos encontrar ciertas limitaciones (que no suelen ser graves) en las posibilidades que nos ofrece PhoneGap o Electron.

Comunicación con aplicación nativa

Otra alternativa, más laboriosa pero muy potente, es desarrollar una aplicación nativa y dejar que nuestra aplicación web se comunique con ella a través de algún protocolo estándar, como HTTP o WebSockets.

De esta forma, podemos desarrollar una aplicación completamente independiente que use cualquier cosa existente en la plataforma host, sin ningún tipo de restricción, y con el lenguaje y las herramientas que más nos gusten. Esta aplicación deberá exponer un API que pueda ser invocado desde nuestra aplicación web, generalmente mediante peticiones HTTP o, si nos vemos ganas y lo necesitamos, con WebSockets.

La ventaja de esta idea es que nos da máxima flexibilidad a la hora de implementar la interacción con la plataforma, pero a cambio nuestra aplicación nativa deberá preocuparse no sólo de implementar la funcionalidad que necesitamos, sino también de mantener un servidor web al que se conecta nuesta aplicación web y lidiar con temas como CORS y certificados SSL.

Igual que en el caso de los plugins del navegador, nuestros usuarios deberán descargar, instalar, actualizar y mantener esta aplicación nativa, lo que supone un handicap adicional.

Esquema de URI personalizado

Exite otra opción, quizá menos glamurosa pero que puede ser muy efectiva, que es la de recurrir a esquemas de URIs personalizados. Quizá a muchos os suenen enlaces con esta pinta:

ed2k://|file|Random_Pr0n.avi|149504|9691ee246d63d45ea71954c4d|/

Son los enlaces que usaba edonkey y que heredaron sus sucesores para localizar identificar ficheros en las redes p2p. Los enlaces constan del esquema, este caso ed2k://, y la información asociada. En la configuración del sistema operativo es posible asociar cada esquema con una aplicación, y el sistema se encargará de invocar esa aplicación al pulsar en URIs que se ajusten a ese esquema, indicándole el contenido de la URI.

Aunque esto es dependiente tanto del sistema operativo como del navegador, prácticamente todos los sistemas operativos y navegadores modernos, tanto móviles como de escritorio, lo soportan. La manera de configurarlo en cada uno es diferente, por ejemplo en Windows se usa el registro o en Android se usan intents.

La ventaja frente a la alternativa anterior es que nos ahorramos tener que implementar un servidor web en nuestra aplicación nativa, pero a cambio la manera de comunicar ambas aplicaciones es más restringida, ya que no podremos devolver fácilmente resultados desde la parte nativa a la parte web, y el tipo de parámetros a pasar hacia la parte nativa está limitado por la longitud máxima de las URLs que soporte el navegador. Además, el despliegue puede ser algo más complicado ya que tenemos que registrar nuestro esquema de URI personalizado y, por supuesto, seguimos con la limitación de tener que obligar al usuario a instalar una aplicación adicional.

Resumen

Cuando tienes cierta soltura desarrollando interfaces de usuario basados en HTML y Javascript es muy tentador recurrir a ellos para cualquier tipo de aplicación, y la verdad es que el rango de aplicaciones para los que son una solución perfectamente válida es cada vez mayor.

No obstante, hay momentos en los que, por el propio diseño de las tecnologías web, no podemos acceder a recursos nativos que son necesarios para nuestra aplicación. Llegado ese punto, es razonable preguntarse si no sería mejor hacer directamente una aplicación nativa y olvidarse del mundo web, y probablemente haya casos en los que sea así.

Si la interacción entre la parte web y nativa es lo suficientemente pequeña y acotada, utilizar alguna de las técnicas expuestas en este post nos puede ayudar a salvar el escollo y seguir aprovechando las ventajas de desarrollar un interfaz de usuario con HTML y Javascript.


3 comentarios en “Cómo acceder a recursos nativos desde una aplicación web

  1. Hola Juanma!

    Yo he necesitado hacer esto en una aplicación, en concreto tenía que comunicarme con la impresora de tickets y con un cajón monedero para la apertura.

    En mi caso la aplicación web mira la existencia de una API propia, si no existe desactiva la funcionalidad de impresión de ticket y apertura del cajón. Para que la aplicación web pueda usar dicha API hay que ejecutar una aplicación WinForm que muestra el navegador embebido, en concreto uso CefSharp, el cual te permite publicar código C# como API en su browser, así que la aplicación solo tiene que ver que “window.myApi” está definida, si lo está la usa y si no pues nada.

    Supongo que este caso encajaría con PhoneGap o Electron, solo que con C#.

    Saludos,

  2. Gracias Javi, justo ese escenario (impresora + cajón) lo he tenido hace poco y al final optamos por usar un esquema personalizado.

    No conocía CefSharp, pero me parece una buena alternativa a los Electron de turno.

  3. Yo deseché el esquema personalizado por que no sabes si alguien te escucha… no puedes ocultar la funcionalidad.

    CefSharp es básicamente Chromium embebido, tiene sus cosas también pero ahí está funcionando tres años y ni un problema.

    ;)

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *

*

Puedes usar las siguientes etiquetas y atributos HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>