De webapp a mobile app con React-native

Javier Anaya
Finizens Engineering
7 min readOct 25, 2017

En el departamento de desarrollo de Finizens intentamos buscar siempre el balance entre desarrollo y negocio. Tratamos de aportar cosas que ayuden a la empresa a seguir creciendo, a nuestros clientes a entender mejor qué es finizens, cómo le puede ayudar y darles un mejor servicio. Y todo esto sin olvidar que sea sostenible y mantenible técnicamente.

La búsqueda de ese balance explica por qué hasta casi pasados siete meses desde el lanzamiento todavía no habíamos lanzado una app móvil. En este post os contamos cómo la hemos desarrollado y el por qué decidimos hacerlo de este modo. Esperemos que os guste y como siempre, cualquier comentario al respecto es bienvenido.

El truco

yarn install

El backlog en Finizens es, como en la mayoría de empresas, largo. Muchas son las funcionalidades que tenemos que implementar y cosas donde podemos mejorar. Y a veces, esa búsqueda de equilibrio entre negocio y desarrollo es difícil de encontrar e incluso de medir. Y aquí se planteaba la duda: Nativo VS Híbrido.

No es el objetivo de este post abrir aquí debate o pros y contras de qué ofrece mejor rendimiento o cuál sería mejor a nivel técnico. Cada empresa tiene unas necesidades y/o áreas de negocio. Unas irán 100% móvil y otras pensarán que no tienen por qué hacerlo.

Quien haya usado Finizens sabe que intentamos poner el máximo cariño en nuestra webapp, hemos apostado desde el principio por mobile-first, no vamos a decir que la apariencia es 100% mobile, pero intentamos que se asemeje al máximo posible.

Así que crear una aplicación desde cero, ya fuera en Swift/Java, ionic, cordova, react-native o similares, nos parecía invertirle tiempo a algo muy bonito para los que nos gusta la tecnología, pero que implicaba no lanzar la app en varios meses, con lo que durante este tiempo estaríamos sin aplicación móvil.

Así que el truco no es más que crear una aplicación que usara nuestra webapp, nos lo podíamos permitir ya que, como hemos explicado, habíamos apostado por mobile-first. Sí, implica muchas concesiones, hoy venimos a contaros un poco qué hicimos.

La solución

Headqueaters de finizens: Haciendo el mvp

Nuestras decisiones se basaban en dos premisas:

1. No queremos invertir el tiempo en desarrollar apps nativas 100%

2. No queremos mantener dos bases de código diferentes aunque usara nuestra webapp internamente.

Para solucionar estos dos puntos a la vez hay varios frameworks que están funcionando muy bien cómo Ionic o React-native (entre otras) donde puedes trabajar sobre solo una base de código y generar el paquete para iOS o para Android.

Hicimos una prueba de concepto y nos funcionó bien, vimos que era factible usarlo para abrir Finizens en una webview. Así que decidimos implementarlo con React-native. ¿por qué no intentarlo?

La implementación

headquarters de finizens: Probado react-native

Primera prueba de concepto fue realmente sencilla. Componentes:

- Splash: Tanto en Xcode como en Android Studio es bastante sencillo añadir imágenes por cada tamaño de dispositivo. Luego desde react-native utilizamos el módulo react-native-splash-screen.

- Loading: Es un componente tipo modal al cual su padre le pasa una propiedad que indica cuando tiene que ser visible y cuando no. Este componente de react-native (a.k.a. RN) es muy facilito de utilizar. Con la propiedad “visible” se le puede decir cuándo tiene que aparecer y cuándo quitarlo.

- Sin conexión: Pantalla que aparecerá cuando el dispositivo pierde la conexión. En RN hay un módulo muy sencillo de utilizar que se llama: NetInfo que te dice si el dispositivo está conectado o no. En iOS no va del todo fino, nos topamos con algunos problemas, pero que pudimos solucionar fácilmente

- Webview: Componente que carga nuestra webapp en una webview, el método render tiene una pinta tal que:

Este es el componente webview y las propiedades más relevantes de la webview.

Source: Url que se va a abrir.

onLoadEnd: Termina de cargar la webview, quitamos el loading.

onNavigationStateChange: Lo usamos para saber cuando la webview cambia de pantalla.

onMessage: Escuchamos eventos emitidos por la webview. React-native implementa su propio onMessage, que por cierto, es muy curioso como hace la comunicación. Para quien le pueda interesar dejo aquí los links a github: iOS, android.

injectedJavaScript: Javascript que le queremos meter a la webview. Nuestra versión más primitiva le decía a la webview que estaba en nativo (con un “window.isNative = true;”), ya explicaremos más adelante que en determinadas ocasiones la webview se comporta de manera diferente si este es el caso.

Esto no nos funcionaba correctamente, ya que la inserción de ese JS no respondía a un evento en concreto. ¿Qué queremos decir con esto? RN no puede inyectar el JS antes de que la página cargue. Eso quiere decir que en el onLoad todavía no estaba ese JS y que pronto aparecerá. ¿Cuándo? Realmente no lo sabes a no ser que tu propio JS te notifique (el JS de Schrodinger).

Optamos por pasar el parámetro por url y no inyectando el JS. Una solución mucho más limpia y simple.

Después de esto, teníamos una app funcionando lista para llevarla a producción y tardamos apenas una semana en implementarla. Para nosotros un éxito. Conseguir rebajar el tiempo de desarrollo de meses con varias personas involucradas a una semana de una persona es algo que hay que valorar muy positivamente.

Comunicación entre webview y react-native ¿Qué enviamos?

Botón compartir:

Cuando un usuario quiere compartir su enlace de invitación (por ejemplo vía Whatsapp).

Al hacer clic en el botón “Compartir” se envía un evento a RN para que le muestre la funcionalidad nativa de compartir (utilizando el módulo Share)

Descargar archivos:

Necesitamos interceptar la descarga de archivos en iOS. Como es una webview, si no lo hacíamos, abre el propio pdf en esa misma vista, lo que inutilizaba la app.

En este caso detectamos que el usuario quiere bajarse un documento y lo abrimos con el módulo Linking en una nueva página.

Trackear los eventos que pasan en la webapp:

Para el tracking de eventos nativos usamos Firebase y Adjust. En esta plataforma nos interesa tener los eventos más importantes que puede producir un usuario, como darse de alta o hacerse cliente. Cuando ocurre uno de estos eventos lo pasamos desde la webview a RN, y desde ahí lo emitimos a nuestras plataformas de tracking.

¿Cómo emitimos eventos desde webapp?

RN sobreescribe la función “window.postMessage”. Usando esa función realmente es RN quién está interceptando el mensaje y emitiéndolo para que nosotros podamos leerlo desde nuestro código nativo.

Para nosotros es tan fácil como hacer esto en la webapp.

window.postMessage(JSON.stringify(object), '*');

Definimos un contrato entre nuestra webapp y RN con dos propiedades: ‘type’ y ‘payload’, donde ‘type’ es el tipo de evento y cada evento tiene su ‘payload’.

En la parte de RN solo tenemos que escuchar los eventos que llegan a la función onMessage como hemos explicado cuando hemos hablado de la webview.

No todo es bonito. ¿Qué ha ido mal?

¿Reescribir la webview de android nativa de react-native?

Para quien no lo sepa en nuestro proceso de contratación te pedimos que le hagas una foto a tu DNI, o si lo prefieres puedes subir un archivo. Considerábamos muy importante que esa funcionalidad estuviera en la aplicación móvil de android. No funcionaba por defecto abrir la cámara pero tampoco funcionaba subir fichero correctamente dependiendo de la versión de android.

¿Cómo lo solucionamos?

1. Para solucionar la subida de fichero utilizamos este módulo:

2. Para solucionar la apertura de la cámara no era suficiente con ese módulo y tuvimos que reescribir parte de la webview nativa de android como citan aquí para poder pedir los permisos:

Mención especial aquí a nuestro compañero y programador-todoterreno @pedropalmero que arrimó el hombro y solucionó el problema.

¿Qué nos queda por hacer?

headquarters de finizens: Viendo que nuevas features hacer

Tenemos algunas ideas y muchas cosas que mejorar, pero principalmente seguir investigando react-native y ver qué posibilidades nos ofrece.

Además en nuestro equipo nos gusta mucho quitarnos de enmedio tareas que puedan llegar a ser repetitivas. Y una de ellas es empaquetar y subir las apps a las stores. Una cosa que tenemos en la cabeza es automatizar eso. No hemos investigado mucho, así que si alguno de vosotros ya lo hacéis estaríamos encantados de escucharos y hablar con vosotros. Nosotros, investigando un poco, hemos encontrado esta herramienta que parece que puede funcionar bien. Si la usamos o hacemos este proceso, tened por seguro que os lo comentaremos con un post.

Conclusión

Cargar una webview usando RN nos ha dado la posibilidad de tener nuestras apps en las stores en un tiempo récord. La estrategia ha sido hacer lo mínimo y reutilizar el máximo. Y si bien hay cosas que podrían funcionar mejor, no nos hemos topado con ningún problema que no pudiéramos solucionar de manera rápida. Por otro lado dar las gracias a que la comunidad está ahí para ayudarnos y los proyectos open source que aquí hemos citado.

¿Se va a quedar así de por vida? Eso hoy no lo sabemos, si tenemos el músculo necesario para poder tener un equipo dedicado a las aplicaciones móviles y vemos desde negocio que hay una necesidad, entonces bienvenido sea abrir el debate.

A día de hoy si estás pensando en probar, iterar y no invertir varios meses de tu equipo en un desarrollo nativo nosotros te recomendamos probar lo que hemos hecho. En unas horas puedes tener algo funcionando y juzgar con más datos tu mismo.

Mientras pensamos de qué vamos a escribir en el próximo post te invitamos a bajarte nuestras apps hechas en react-native y una webview. Dinos qué te parece, cualquier consejo, recomendación o insulto es bienvenido.

iOS: https://itunes.apple.com/es/app/finizens/id1243555874

Android: https://play.google.com/store/apps/details?id=com.finizens.app

Muchas gracias por vuestro tiempo.

Nos vemos en el siguiente.

--

--

Javier Anaya
Finizens Engineering

Software developer at @iobuilders, prev: @finizens, @traviangames @dokify, @netgamix.