Cuando hablamos de geolocalización nos referimos a la capacidad de un dispositivo de obtener la posición geográfica en la que se encuentra. Para ello, puede hacer uso del punto de acceso WiFi al que está conectado, de la torre de telefonía móvil al que está enlazado, (en el caso de los teléfonos u otros dispositivos móviles que cuente con una tarjeta SIM) o a través de la tecnología GPS cuando dispone de la misma. Incluso estas diferentes opciones se pueden combinar entre sí para mejorar la precisión que nos ofrece cada una de ellas por separado.
En los dispositivos móviles esta capacidad de obtener la geolocalización abre mucho el abanico de aplicaciones que se pueden desarrollar. Algunos ejemplos pueden ser la creación de Apps para inventariar información (que incluya la posición geográfica de cada elemento), almacenar rutas o recorridos realizados, obtener información sobre lo que tenemos cerca, etc. Las posibilidades son casi infinitas.
Recientemente tuvimos la necesidad de desarrollar una aplicación móvil con la que recopilar información sobre la ruta seguida para la recolección de setas silvestres. Apostamos por desarrollar dicha aplicación haciendo uso de tecnologías web adaptadas para crear aplicaciones móviles, en concreto haciendo uso del framework Ionic con ReactJS. En este proyecto teníamos alguna necesidad particular relacionada con la precisión y la posibilidad de recoger los puntos de la ruta, aunque la aplicación estuviese en segundo plano y el dispositivo se estuviese usando para otra cosa. Eso nos hizo analizar diferentes plugins de geolocalización disponibles para Ionic. En este artículo queremos compartir este análisis, así como algunas de las conclusiones y aprendizajes por el camino.
Al trabajar con tecnologías para desarrollar una aplicación móvil, por defecto podemos usar la API de geolocalización del W3C que implementan los navegadores. Sin embargo, es recomendable el uso de algún plugin específico de geolocalización, que podemos activar si usamos Cordova para empaquetar la aplicación para el móvil, o en nuestro caso particular Capacitor, la herramienta que suministra Ionic. Es una buena práctica en general, ya que así nos aseguramos que tendremos la funcionalidad disponible independientemente de la versión del navegador que tenga el móvil. Recordemos que al usar este tipo de tecnologías al final nuestra aplicación, en el móvil, se está ejecutando dentro de un navegador web. Pero es que además, en nuestro caso particular era obligatorio, porque necesitábamos funcionalidades a mayores, que no ofrece la API de geolocalización, como por ejemplo soporte para seguir obteniendo la localización cuando la aplicación está en segundo plano.
Cordova vs Capacitor
Antes de entrar en el análisis de los plugins de geolocalización es bueno pararse a revisar las dos principales alternativas para empaquetar aplicación móviles, cuando trabajamos con tecnologías web para su desarrollo.
Apache Cordova fue uno de los primeros entornos de desarrollo de aplicaciones móviles usando tecnologías web, CSS, HTML y JavaScript, en lugar de usar las APIs específicas para cada plataforma. Esto tiene sus ventajas y sus inconvenientes, de los cuales no vamos a hablar ahora aquí, ya que daría para varios posts. El proyecto Ionic empezó usando también Cordova como herramienta para empaquetar las aplicaciones, pero más recientemente sacó la suya propia, Capacitor. En web del proyecto nos cuentan el porqué de este cambio y que ventajas aporta Capacitor.
Una de las ventajas de Capacitor es que es totalmente compatible con Cordova, y por tanto podemos usar plugins que estén disponibles para este último aunque no existan en Capacitor. Incluso aunque exista una versión equivalente podemos usar la de Cordova si nos interesa por algún motivo. Esto por ejemplo nos hizo poder ampliar el abanico de plugins a revisar.
Precisamente porque Cordova lleva mucho más tiempo disponible, la cantidad de plugins que podemos encontrar tanto oficiales como desarrollados por la comunidad es mucho mayor a día de hoy que en el caso de Capacitor, que a pesar de contar también con bastantes plugins desarrollados por su comunidad, además de los oficiales, por su juventud todavía son menos.
Plugins de Geolocalización
Tanto Cordova como Capacitor disponen de un plugin de geolocalización por defecto, basados en la API del navegador. Son plugins de uso sencillo, que están disponibles sin tener que añadir nada y que básicamente nos permiten obtener las coordenadas de la posición en la que se encuentra el móvil. Su API nos da dos funciones:
- getCurrentPosition: Nos da las coordenadas cuando la llamamos.
- watchPosition: Nos permite conectarnos a un watcher que nos devuelve las coordenadas de la posición cada vez que hay un cambio, es decir cada vez que nos movemos.
En ninguno de los casos se pueden obtener coordenadas cuando la aplicación está en background, uno de los requisitos que por ejemplo sí tenía nuestra aplicación, ya que al recolectar una ruta larga, era necesario que se pudiese usar el teléfono al mismo tiempo para otras tareas, sin que se dejase de registrar la ruta.
Por suerte, gracias a la comunidad tenemos más opciones disponibles. En nuestro caso probamos otros dos plugins que permiten el funcionamiento de la geolocalización en background.
- BackgroundGeolocation de Capacitor-community: Es el plugin más reciente con soporte para trabajar con la geolocalización en background, específico para Capacitor y con soporte para TypeScript.
- Cordova Plugin Background Geolocation: El plugin clásico que se usaba en entornos Cordova cuando hace falta geolocalización en segundo plano. La última release es de hace 3 años, aunque sigue funcionando bien en versiones recientes de Android.
Dentro de las pruebas que hicimos con estos dos plugins, en ambos conseguimos una precisión suficiente para las necesidades del proyecto, en la mayoría de los casos de unos pocos metros. Las opciones de los plugins nos permiten jugar con varios parámetros para optimizar las necesidades de precisión de las coordenadas que se obtienen con la duración de la batería del dispositivo, por ejemplo.
A pesar de que el plugin para Capacitor es más actual, la realidad, al menos en nuestro caso, es que tuvimos problemas con móviles más modernos, a partir de Android 10, sin embargo parecía funcionar sin problema en versiones más antiguas. El plugin de Cordova sin embargo se comportó bien desde el principio tanto en móviles más antiguos como en los más modernos. Por esto y otros pequeños detalles terminamos por decidirnos por este último para nuestro proyecto.
Algunos problemas detectados por el camino
Una vez seleccionado el plugin y a pesar de haber hecho un análisis bastante exhaustivo y pruebas varias, durante el desarrollo aún tuvimos que resolver algunos problemas. El primero de ellos tiene que ver con las capas de abstracción que algunos fabricantes introducen sobre Android para personalizar sus dispositivos. Es un tema bastante conocido y está bien documentado en Internet. Los problemas suelen estar relacionados con la gestión de la batería, buscando su ahorro, que hacen algunas de estas personalizaciones y que hacían que nuestro servicio en background se detuviese. En la web Don’t kill my app! están documentados la mayoría de estos casos y como configurar el dispositivo para evitar que la gestión de ahorro de la batería cancele este tipo de procesos.
Otro problema que tuvimos y que no fue tan sencillo de identificar y solucionar tiene que ver con la versión 10 de Android. Lo que ocurría es que una vez que se ponía la aplicación en background se seguían recogiendo puntos, pero pasado un determinado tiempo dejaban de recopilarse, aproximadamente unos 30 segundos. Al volver a recuperar la aplicación y pasar a tener el foco principal en el sistema, entonces la recolección de puntos continuaba como si nada.
Estaba claro que este problema no era el mismo que el anterior, ya que la aplicación no moría por gestión de batería. El problema real está relacionado con la nueva gestión de permisos que se introdujo en Android 10 y que permite elegir si se otorga un permiso siempre o sólo cuando la aplicación está en uso. Esta segunda opción es la que genera problemas, ya que ese sólo cuando la aplicación está en uso en realidad significa cuando la aplicación esté visible en la pantalla, en primer plano, y no cuando se está ejecutando en background.
Nuestra solución consistió en agregar de forma explícita en el AndroidManifest.xml la opción andorid:foregroundServiceType=»location». De esa forma le indicamos que nuestra app es un servicio de localización y necesita acceso siempre al GPS. La línea completa en el AndroidManifest.xml quedaría tal que así:
< service android:enabled="true" android:exported="false" android:foregroundServiceType="location" android:name="com.marianhello.bgloc.service.LocationServiceImpl" />
También es necesario conceder explícitamente el permiso ACCESS_BACKGROUND_LOCATION tal y como se detalla en la documentación.
Consideraciones finales
En la elección de un plugin, así como en general de cualquier software o librería de desarrollo, tiene tanta importancia las funcionalidades que nos ofrece como su evolución y mantenimiento. En nuestro caso apostamos por un plugin que llevan tiempo sin actividad en su repositorio, esto implica que no tienen mantenimiento ni se esperan mejoras futuras. Por contrapartida el que sí cumplía estos criterios, no nos ofrecía la funcionalidad que necesitábamos. Quizás es un caso extremo el que encontramos y por eso tomamos esa decisión. En cualquier caso nuestra recomendación es siempre tener en cuenta la actividad del repositorio de una solución, viendo que está y seguirá estando mantenido en el tiempo, que hay comunidad a su alrededor y que es una apuesta segura. Cuando esto no es posible hay que ponderar otras cosas para realizar la elección e incluso si fuese posible tratar de crear nuestra propia solución.