Desarrollo de aplicaciones móviles con NativeScript.

De mi artículo para la revista SG, №53

Introducción

El mundo móvil ha venido cambiando drásticamente, haciendo sumamente difícil para los desarrolladores crear y mantener sus aplicaciones móviles. Para alcanzar la mayor audiencia posible, las aplicaciones desarrolladas necesitan mantenerse en muchas plataformas y dispositivos. Para seguir al ritmo de este mundo cambiante, los desarrolladores comenzaron a ubicar en un lugar preponderante un solo código base para escribir y mantener las aplicaciones.

En este contexto podemos incluir una larga lista de empresas y tecnologías alrededor de la creación y entrega de aplicaciones móviles de plataforma cruzada (cross-platform mobile apps), las cuales, en su mayoría plantean un solo código base para el desarrollo y entrega de aplicaciones móviles para diferentes plataformas: tecnologías como PhoneGap/Cordova, React Native, Appcelerator Titanium y Xamarin entre otras.

Asimismo, podemos mencionar que el mundo del desarrollo móvil se sustenta en 4 grandes categorías: nativo, híbrido, compilación cruzada y justo a tiempo (just in time JIT por sus siglas en inglés,).

Imagen 1. Tabla con los diferentes tipos de aplicaciones móviles y sus frameworks más populares.

Las aplicaciones JIT o compiladas justo a tiempo son aquellas aplicaciones que son compiladas en tiempo de ejecución (runtime) en oposición a aquellas que son compiladas antes de la ejecución de la aplicación. Por ejemplo, en una aplicación JIT, el código fuente no es compilado a código máquina nativo, sino hasta el último minuto, o inmediatamente antes de ejecutar cada sentencia. NativeScript es JIT, compila justo a tiempo.

Acerca de NativeScript

NativeScript es un entorno de trabajo de código abierto –open-source mobile framework– para construir aplicaciones móviles para las plataformas iOS, Android y próximamente Windows, con JavaScript, CSS y XML. De manera opcional, podemos utilizar TypeScript y Angular 2 para obtener un mejor desempeño, manejo y escalamiento de nuestras aplicaciones.

NativeScript es un entorno de trabajo de código abierto –open-source mobile framework– para construir aplicaciones móviles para las plataformas iOS, Android y próximamente Windows, con JavaScript, CSS y XML. De manera opcional, podemos utilizar TypeScript y Angular 2 para obtener un mejor desempeño, manejo y escalamiento de nuestras aplicaciones.

NativeScript fue creado y es mantenido por la empresa búlgara Telerik, la cual fue comprada por la empresa estadounidense Progress en 2014. Con aproximadamente 35 años de existencia, Progress mantiene un gran portafolio de aplicaciones y soluciones de integración empresarial, interoperabilidad de datos y desarrollo de aplicaciones, incluyendo la habilitación y entrega de software como servicio (SaaS).

Imagen 2. NativeScript Developer Day 2016 celebrado por primera vez el pasado mes de septiembre 2016 en Boston, Massachussets.

¿Por qué NativeScript ?

NativeScript difiere de otros entornos de desarrollo de muchas maneras. La más importante es que se trata de un entorno de trabajo que verdaderamente permite escribir una sola vez y entregar a todas las plataformas. Con Nativescript podemos:

  • Aprovechar el conocimiento existente (no tienes que saber Objective C, Swift o Java). NativeScript ha sido diseñado para ser aprovechado por desarrolladores con diferentes formaciones.
  • Implementación de hojas de estilo CSS. Podemos cambiar la apariencia y estilo de vistas y elementos en una aplicación NativeScript de manera similar a como lo hacemos en una aplicación web, usando hojas de estilo en cascada o cambiando el estilo del objeto de los elementos en JavaScript. Sin embargo, sólo un subconjunto del lenguaje CSS es soportado.
  • Acceso a las APIS nativas (de lo cual hablaremos a detalle un poco más adelante). Si el framework de Nativescript no expone una API nativa que necesitemos, podemos implementar plugins con NativeScript, los cuales son paquetes npm –publicados o no– que exponen estas APIs vía JavaScript.
  • Tu código se escribe una vez. En experiencias pasadas, trabajando con otros frameworks, hemos visto la existencia de mucho código de cuña (shim) o de apoyo que necesita ser escrito. Este código actúa de manera similar a una pieza de madera o de papel usada para nivelar las patas de una mesa. En muchos casos podría funcionar muy bien, pero a veces es necesario añadir o quitar un poco para que se ajuste de manera adecuada y trabaje correctamente. Justo como se hace cuando se escribe código en otros frameworks, puede que necesitemos agregar un poco de código para desplegar un botón sólo en la versión de Android o, tal vez, necesitamos escribir código adicional para hacer que un menú de lista se vea bien en iOS.

*In computer programming, a shim is a small library that transparently intercepts an API, changing the parameters passed, handling the operation itself, or redirecting the operation elsewhere. Shims typically come about when the behaviour of an API changes, thereby causing compatibility issues for older applications that still rely on the older functionality. In these cases, the older API can still be supported by a thin compatibility layer on top of the newer code. Shims can also be used to run programs on different software platforms than they were developed for.

Imagen 3. Diagrama que ilustra el concepto de código de cuña (shim code) . Con NativeScript escribe una sola vez entrega a donde sea.

¿Cómo funciona NativeScript ?

Tal vez la característica más importante de NativeScript es su mecanismo para brindar acceso directo a las APIs nativas de cada plataforma. Pero, ¿cómo funciona? Examinemos el siguiente código de una aplicación NativeScript para Android.

var time = new android.text.format.Time();
time.set( 12, 12, 2016 );
console.log( time.format( “%D” ) );

Te preguntarás: ¿es código JavaScript creando una instancia de un objeto Java? Sí, JavaScript crea una instancia del objeto, android.text.format.Time(), llama su método set() y luego manda al log de la consola el valor de retorno de su método format, el cual es la cadena “12/12/16”.

Imagen 5. Cuando corremos la app en iOS veríamos la alerta que se muestra en la imagen.

Veamos un ejemplo de una aplicación NativeScript para iOS.

var alert = new UIAlertView();
alert.message = “Hello world!”;
alert.addButtonWithTitle( “OK” );
alert.show();

Este código JavaScript crea una instancia de una clase de Objective-C llamada UIAlertView, establece su propiedad message y luego llama a sus métodos addButtonWithTitle() y show().

Una cosa que debemos aclarar es que, sólo porque tenemos acceso a las APIs nativas de iOS y Android, no significa que las apps en NativeScript solo contengan Objective-C y Java Javascriptficado (valga la expresión).

NativeScript incluye muchos módulos, para ambas plataformas, para tareas comunes, como hacer una petición HTTP, construir componentes UI, etc. Sin embargo, a veces las aplicaciones necesitan acceso a las APIs, y el runtime de NativeScript hace este acceso muy sencillo cuando se requiere.

NativeScript Runtime

El motor en tiempo de ejecución de NativeScript (runtime) es donde se hace la magia. Todo comienza con las máquinas virtuales (VMs) de JavaScript que utiliza NativeScript para ejecutar comandos JavaScript, específicamente NativeScript usa V8 en Android y JavaScriptCore en iOS. Debido a que JavaScript utiliza las VMs de JavaScript, todo el código que escribimos para tener acceso a las APIs nativas necesitan las construcciones y sintaxis de JavaScript que V8 y JavaScriptCore entienden.

Esta es la primera parte del proceso, regresemos a nuestra primera línea de código:

var time = new android.text.format.Time();

En el runtime de NativeScript en Android, este código es compilado (técnicamente, compilado justo a tiempo –JIT compiled–) y ejecutado por V8. Pero ¿cómo sabe V8 qué es android.text.format.Time()?

V8 sabe que es Android porque el runtime de NativeScript lo inyecta, porque resulta que V8 tiene una tonelada de APIs que nos permiten configurar muchas cosas acerca del ambiente JavaScript. Podemos insertar nuestro propio código C++ para perfilar el uso del CPU de JavaScript, manejar la recolección de basura y cambiar cómo trabajan las variables internas, entre otras cosas.

Entre estas APIs existen algunas clases de “Contexto” que permiten manipular el alcance global, haciendo posible a NativeScript inyectar un objeto android global. Este es, de hecho, el mismo mecanismo que usa Node.js para hacer públicas sus APIs globales –por ejemplo, require( )– y NativeScript lo usa para inyectar APis que permiten el acceso al código nativo.

JavaScriptCore tiene un mecanismo similar que hace la misma técnica posible para iOS.

Regresemos a nuestro ejemplo:

var time = new android.text.format.Time();

Sabemos que nuestro código corre en V8 y que éste sabe qué es android.text.format.Time() porque NativeScript inyecta los objetos necesarios en el alcance global. Ahora bien, ¿cómo sabe NativeScript qué APIs inyectar o qué hacer cuando la llamada a Time() sea realizada?

MetaData

NativeScript usa la técnica reflection* para construir la lista de APIs que están disponibles en la plataforma en que corre. Si eres desarrollador JavaScript puede ser que no estés familiarizado con el concepto, debido a la naturaleza permisiva del lenguaje, la cual hace que reflection sea innecesario.

En muchos otros lenguajes, notablemente Java, reflection es la única técnica que podemos usar para examinar el runtime o tiempo de ejecución por sí mismo.

Para los propósitos de NativeScript, reflection es la técnica que le permite construir una lista exhaustiva de las APIs de cada plataforma, incluyendo en este caso android.text.format.Time.

Generar esta información no es trivial desde una perspectiva de desempeño, es por eso que NativeScript lo hace antes de tiempo y embebe los metadatos generados previamente durante el paso de construcción en Android/iOS.

*Reflection is the ability of a computer program to examine, introspect, and modify its own structure and behavior at runtime.[1]

Invocando código nativo

La respuesta a cómo NativeScript invoca código nativo nuevamente recae en las APIs de las máquinas virtuales JavaScript. En esta ocasión, veremos una serie de llamadas que nos permiten ejecutar código C++ en puntos determinados durante la ejecución de JavaScript.

Por ejemplo, el código:

new android.text.format.Time( ) invoca una función JavaScript, para la cual V8 tiene una devolución de la llamada o callback.

Así es como V8 tiene un callback que permite que NativeScript intercepte la llamada a la función, ejecutar ciertas acciones en un código C++ personalizado y proveer un nuevo resultado.

En el caso de Android, el código del runtime de NativeScript en C++ no puede acceder directamente a las APIs de Java como android.text.format.Time. Sin embargo, Android JNI o Java Native Interface, provee la habilidad para hacer el puente entre C++ y Java, así que NativeScript utiliza JNI para hacer el salto. En iOS este puente extra no es necesario ya que el código C++ puede invocar directamente las APIs de Objective-C.

Dicho lo anterior regresemos a nuestra línea de código.

var time = new android.text.format.Time();

Sabemos que este código corre en V8 y que éste conoce qué es android.text.format.Time porque NativeScript inyecta dicho objeto, posteriormente, NativeScript corre un proceso para la generación de los metadatos para obtener esas APis y sabemos que cuando Time() se ejecuta, lo siguiente ocurre:

  1. La función callback de V8 se ejecuta.
  2. El runtime de NativeScript usa los metadatos para saber qué significa Time() y qué necesita para crear una instancia del objeto android.text.format.Time.
  3. El runtime de NativeScript usa JNI para crear una instancia del objeto android.text.format.Time y guarda un referencia a éste.
  4. El runtime de NativeScript regresa un objeto JavaScript que provee una interfaz (proxies) al objeto Java Time.
  5. El control regresa a JavaScript donde el objeto proxy se almacena como una variable local time.

El objeto proxy es la manera como NativeScript mantiene un mapeo entre los objetos JavaScript y los objetos nativos.

Veamos la siguientes líneas de código de nuestro ejemplo anterior:

var time = new android.text.format.Time();
time.set( 1, 0, 2015 );

Debido a los metadatos generados, NativeScript sabe todos los métodos que tiene que poner en el objeto proxy. En este caso, el código invoca el método del objeto Time set(). Cuando este método corre, V8 nuevamente invoca su función callback. NativeScript detecta que ésta es una llamada al método y luego NativeScript utiliza el Android JNI para hacer la correspondiente llamada al método en el objeto Time de Java.

Bastante bueno, ¿no? De manera general, así trabaja NativeScript, porque convertir Objective-C y objetos Java en objetos JavaScript puede ser complejo, especialmente cuando consideramos los diferentes modelos de herencia que cada lenguaje usa.

NativeScript CLI (command line interface).

La línea de comandos de NativeScript o CLI es el pegamento que mantiene todo el desarrollo unido. Esta línea de comandos está involucrada en todas las etapas del desarrollo, desde los andamios hasta la entrega de una aplicación en un emulador o en un dispositivo físico.

Para resumir y desde una vista a 10,000 pies: la CLI de NativeScript abstrae la complejidad de las herramientas nativas y SDKs, brindando al desarrollador un conjunto de comandos agnósticos a la plataforma para construir, mantener y entregar sus aplicaciones móviles.

Imagen 4. En la imagen se muestran los componentes que son utilizados por la línea de comandos de NativeScript para producir una aplicación nativa.

TypeScript

Los desarrolladores NativeScript que prefieran la programación orientada a objetos pueden utilizar TypeScript.

TypeScript fue liberado por Microsoft en octubre de 2012 (con la versión 0.8), después de dos años de desarrollo en los laboratorios de Microsoft. Cabe mencionar que Anders Hejlsberg arquitecto líder de C#, creador de Delphi y Turbo Pascal trabajó en el desarrollo. Cuando el lenguaje recién salió a la luz, la opinión general fue que era un buen lenguaje, pero que en esencia sólo tenía soporte para Visual Studio.

TypeScript se originó a partir de las deficiencias “percibidas” de JavaScript para el desarrollo de aplicaciones grandes, tanto por parte de Microsoft, como entre los clientes externos. Los retos de lidiar con código JavaScript complejo conduce a una demanda de herramientas específicas para facilitar el desarrollo de componentes en el lenguaje.

TypeScript actualmente es transcompilado, es decir Typescript es un superconjunto tipado de JavaScript que compila a JavaScript plano, pero se espera que eventualmente no sea así a medida de que las máquinas virtuales JS y navegadores den soporte el estándar ES6.

Angular 2

Angular 2 es la nueva versión del popular MV* framework de Google para construir aplicaciones complejas en el navegador (y más allá).

De ser una herramienta para la creación de aplicaciones web, ha evolucionado como motor de una enorme cantidad de proyectos en el ámbito emprendedor y, posteriormente, en el empresarial, llevando la tecnología al límite de sus posibilidades.

Podemos decir que Angular 2 ha mutado de ser un framework a una plataforma y no simplemente una nueva versión. Angular 2 es una solución completa. Incluye rendering, compilación, vinculación, comunicación a servidor y pruebas unitarias, todo junto. Sin preocupaciones de escoger entre 20 librerías diferentes cuando solamente se necesita hacer una llamada HTTP.

Google liberó Angular 2 en septiembre de este año y ya tiene planeado liberar Angular 3 en marzo de 2017. Actualmente NativeScript se integra con Angular 2 y se espera una mayor integración y soporte para la nueva versión. Los equipos de desarrollo de ambas empresas han trabajado juntos para lograr esto. De tal forma que, si ya conoces Angular 2, estás listo para desarrollar aplicaciones móviles con NativeScript con un poder y desempeño 100% nativo.

NativeScript 2.4

Actualmente NativeScript se encuentra en la versión 2.4, la cual ha tenido importantes y significativas mejoras, además de más de 360 plugins, lo cual es un claro indicador de que la comunidad está produciendo mucho más código que el equipo que lleva el núcleo. Esto es un gran logro para cualquier proyecto de código abierto.

Flexbox layouts, web workers, soporte a Angular 2.2 y a Node 6 LTS, además del soporte a ECMAScript 2015(ES6) y ES7 son algunas de las mejoras y nuevas funcionalidades incluidas en esta nueva versión.

La versión 2.5 se planea estará lista para enero de 2017.

Componentes UI para NativeScript

Se estima que un gran porcentaje del tiempo de un proyecto de desarrollo móvil se invierte en la creación de componentes de la interfaz de usuario y, en general, en la interfaz de usuario. De ahí que, en vez de desarrollar los componentes uno a uno, resulta mejor en términos de productividad utilizar componentes prediseñados. Como ejemplo, podemos citar el caso de KiZAN Technologies, que reporta haber reducido el tiempo de desarrollo de una aplicación multiplataforma hasta en 60% usando Telerik® Platform y Telerik® NativeScript™.

En este sentido, la ya mencionada Telerik desarrolla Telerik UI el cual es un conjunto de componentes nativos de interfaz de usuario, que agrega muchas características avanzadas por encima de la capa de componentes por defecto que se entregan en el framework de NativeScript.

Telerik como compañía tiene una larga historia desarrollando componentes UI que van desde listas, botones, componentes de visualización de datos como gráficas, calendarios, etc. y, por supuesto, también componentes para la entrada de información en las aplicaciones. Telerik incluso ofrece estos componentes para otras plataformas de desarrollo (PHP, ASP, Node, etc.).

Si quieres aprender más acerca de NativeScript, el mejor lugar para empezar son las guías y entrenamientos oficiales que puedes encontrar en www.nativescript.org y en www.telerik.com

En KMMX también se ofrece un curso presencial de NativeScript por si alguien esta interesado.

Si estás en la Ciudad de México, puedes suscribirte a las reuniones mensuales que llevamos a cabo a través de Meetup.

¡Feliz NativeScript-ing!

Y aquí dejo un vinculo a la revista SG donde fue publicado el articulo por si gustan descargarla, pag.14. https://drive.google.com/file/d/0B_fgmbWsaKAZMmhTcXR3YUFqZ3NLbWJLa0phY1RMYy10RnJJ/view?usp=sharing

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.