Recientemente, volví a sujetar. Vivo en Europa, y aquí, en lugar de multas por estacionamiento incorrecto y grúas de "amarre", encadenan la rueda de su automóvil. Para salir, debe hacer una llamada telefónica, pagar una suma redonda y esperar a que el tipo con las llaves levante la cadena. Es largo, humillante y a veces (dependiendo del área) depredador caro.
Ese día llegué tarde a todas partes. Mientras esperaba que el trabajador sonara con las llaves, me preguntaba cuán estúpidamente me puse. Entré corriendo, dejé el automóvil durante media hora en lugar de los 20 minutos máximos libres, exactamente en el minuto 21 y me atraparon. Desafortunadamente, la camioneta rayada del estacionamiento no estaba muy lejos, e instantáneamente reaccionaron. Solían atraparme antes, por varias razones: me olvidé, el plazo pagado venció, y a veces simplemente no podía encontrar mi auto en el laberinto de calles.
"Debe haber una aplicación para todo", pensé, y comencé a profundizar en la tienda de aplicaciones. Después de un montón de resultados dudosos, mi confianza disminuyó y decidí aclarar: "debe haber una aplicación de Android para todo". Luego encontró su huavei y se metió en las entrañas de la tienda de juegos. A partir de ahí, se derramaron más escombros sobre mí y, ahogado en torpes embarcaciones, escupí. O estoy buscando algo mal, o no hay un rastreador de estacionamiento conveniente y comprensible. La conclusión es simple: si no tenemos algo, hagámoslo nosotros mismos.
En el contexto, ya estaba cortando una
construcción a largo plazo , quitándome casi todo mi tiempo libre. Decidí tomar un descanso y en el intervalo para recoger otra proyección. Habiendo estimado la funcionalidad deseada, imaginé un período de un mes y medio y, mirando hacia el futuro, diré que, en principio, resultó aún más rápido. El resultado fue una
aplicación compacta y limpia en ambas plataformas, muy conveniente. Ahora lo uso yo mismo y le sugiero que lo pruebe.

Idea
Entonces, ¿qué me gustaría de un rastreador de estacionamiento? ¿Qué extraño siempre cuando recibo una multa? Después de pensar, formulé la siguiente introducción:
- Simple Idealmente, un botón. Un mínimo de funciones de distracción: sin perfiles, historial de estacionamiento, soporte para múltiples autos al mismo tiempo, etc.
- Con notificaciones. No me olvidaría del auto, si la aplicación me lo recordara: hermano, por cierto tienes un estacionamiento allí, y está a punto de caducar.
- Considere el tiempo de caminata. Este es el pensamiento más simple que no he visto encarnado en ninguna parte. No necesito saber que el estacionamiento caducará en 5 minutos si estoy a media hora de distancia. Necesito que me lo recuerden para poder llegar al auto unos minutos antes del final y salir.
- Ruta y navegación al estacionamiento. Navegación, por supuesto, a través de Google o Apple Maps, pero la ruta se puede mostrar en su aplicación. Esto ayudará si dejaste el auto en un área desconocida, el temporizador funciona y corres en círculos por las mismas calles.
Elegí Flutter como la base tecnológica, ya que he estado trabajando con él durante algún tiempo y lo considero bueno. Para las rutas, decidí usar la API AQUÍ, también no por primera vez, sino para el mapa: Mapbox. Esbocé varias opciones para la interfaz, elegí la más minimalista y me involucré en el trabajo.
Desarrollo
En principio, no hay mucho que contar sobre el proceso de desarrollo en sí. Aquí no hay ninguna parte del servidor, el cliente más simple, que consiste esencialmente en una vista grande en diferentes estados. En la primera página, puede seleccionar un preset (1, 2, 4, 6 horas) o usar el control deslizante para ajustar su período de estacionamiento. Después de haberlo probado en vivo, me di cuenta de que el control deslizante era lo suficientemente grosero y le agregué los botones "+" y "-". Un matiz divertido y bastante obvio aquí fue que mientras eliges, el tiempo continúa. Por lo tanto, debe actualizar esta vista en tiempo real. Después de elegir el término, haga clic en el único botón a continuación, y se guardan los datos de ubicación y hora, y comienza el estacionamiento. Es importante tener en cuenta que básicamente almaceno todos los datos a bordo, nada se transfiere a ningún servidor. En el futuro, esto, por cierto, creará dificultades para mí, pero más sobre eso más adelante.
La segunda página es, de hecho, el temporizador de estacionamiento. Probé un montón de opciones aquí: comencé con prototipos de información muy sobrecargados, luego los eliminé de manera iterativa y los simplifiqué hasta el límite. Realmente quería que el estado del estacionamiento se mostrara visualmente, en lugar de números secos, por lo que el elemento principal de esta página junto con el mapa era un gráfico de anillos. Muestra el tiempo transcurrido, el tiempo de caminata y el tiempo restante. Si no está cerca del automóvil y el tiempo de caminata no es cero, aparece un botón de inicio de navegación y el mapa muestra una ruta aproximada al estacionamiento. Eso, de hecho, es todo.
A pesar de la simplicidad visual, esta pantalla alborotó mis nervios. Debe entenderse que mientras el estacionamiento está activo, varios procesos ocurren simultáneamente:
- pasa el tiempo y se acaba el tiempo
- te mueves y el tiempo de viaje cambia
Todo esto sucede en tiempo real y debe mostrarse instantáneamente en la interfaz. La carta debe reconstruirse sin problemas, el mapa debe moverse y volver a dibujar la ruta, si existe el riesgo de llegar tarde o de que caduque el estacionamiento, también debe aparecer la advertencia correspondiente. Además: cuando cierra y abre la aplicación, debe restaurar todo esto correctamente. Y finalmente, lo aterrador: toda la funcionalidad debería poder funcionar en segundo plano, porque la aplicación pasará la mayor parte de su vida en segundo plano. Tales cosas
No describiré la implementación en detalle, solo puedo decir que el trabajo de aleteo con los estados es muy valioso. Donde en un androide puro resultaría un diseño orientado a objetos sobrecargado, resultó simple y elegante. Estados comprensibles normales, unión sensata de vistas a modelos, en tareas como esta, el aleteo brilla. Sin embargo, no fue sin jambas típicas: por ejemplo, la biblioteca local de trabajar con mapas no tiene una transición animada a nuevas coordenadas. Tenía que entrar en su código, sacar algunos métodos privados y agregar mi muleta. Es posible que esta funcionalidad se agregue pronto, pero este es todo el aleteo: con todo su atractivo, prepárese para tales descubrimientos.
Todo lo demás parecía funcionar sin problemas. En realidad, no había mucho más: un par de diálogos y una página de introducción para la cual mi novia (ella era una
artista ) dibujó buenas animaciones. Finalmente, traduje toda la aplicación al ruso, incluido el mapa. Pero entonces comenzó el dolor: notificaciones.
Notificaciones
Para mí, la capacidad de enviar notificaciones inteligentes fue clave para la aplicación; sin ella, no hay nada de qué preocuparse. Sin embargo, cuando comencé a trabajar en esta función, me di cuenta de que había pisado mi propio pie. En realidad hubo dos problemas. El primero es flutter, que no sabe cómo trabajar con dispositivos api de bajo nivel listos para usar: debe escribir una junta en forma de complemento que contenga dos códigos nativos y una abstracción en el dardo. El segundo problema es mi posición fundamental de que todo debe llevarse a cabo a bordo. Entonces, resumimos lo que se necesita. Es necesario que la aplicación
en segundo plano :
- Controlando constantemente su geolocalización,
- Comprobado cuántos minutos a pie hasta el estacionamiento
- Comprobado con temporizador que expira
- Si existe el riesgo de no tener tiempo para regresar, una inyección de notificación
Siente la magnitud de la tragedia? Está claro que no hay capacidad técnica para hacer esto si la aplicación se cierra por completo. Pero supongamos que simplemente se minimiza y la pantalla está apagada. AQUÍ api me da la ruta y la estimación del tiempo de caminata, ¿significa esto que la aplicación enviará solicitudes de spam en segundo plano? ¿Cuánto código se ejecutará en absoluto? ¿Cómo estamos con la memoria y el consumo de energía?
Me senté a pensar. Comenzó con uno pequeño: técnicamente, flutter recientemente ha tenido la capacidad de ejecutar código en segundo plano, se llama aislar. Si todo está escrito correctamente, entonces puede construir la lógica de una manera específica para que no todo se ejecute en segundo plano, sino algunas funcionalidades específicas. De hecho, en modo minimizado, no necesitamos dibujar interfaces o actualizar estados: estamos interesados en la lógica simple de calcular el tiempo, y esta lógica es bastante compacta y barata. Al mismo tiempo, no debería ser provocado por un cambio en la geolocalización, como lo hice en la versión original, sino por algún temporizador interno. Porque la notificación debería volar, incluso si no te mueves, pero siéntate quieto.
Bueno, escribimos un código liviano que puede ejecutarse en segundo plano y es controlado por un temporizador. ¿Cómo podemos activarlo dentro del marco de aplicaciones nativas y transmitir datos de geolocalización allí? Resultó diferente.
La lógica de Android y iPhone en materia de ejecución de código en segundo plano es radicalmente diferente. Para un iPhone, está ausente como tal: el código de fondo solo puede desencadenar un evento del sistema de cierto tipo, por ejemplo, reproducir audio en streaming o, afortunadamente para mí, actualizar la ubicación. Para hacer esto, solo solicite permisos y en la parte nativa del complemento Flater suscríbase al evento. Desde allí, a través de un canal de comunicación específico (MethodChannel), llamamos a la devolución de llamada en un dardo, le pasamos los geodatos y comenzamos el fondo con la lógica que necesitamos. Belleza
Android funciona de manera diferente. Técnicamente, tiene la capacidad de ejecutar código en segundo plano sin estar atado a eventos del sistema; para esto, debe describir el servicio. Se cuelga por separado de la aplicación, ya sea completamente en segundo plano o en el fondo (allí se hace sentir por un mensaje adjunto en la persiana). Parece que el problema se ha resuelto: en la parte nativa del complemento, describimos un servicio en segundo plano que rastrea la ubicación y extrae el código Darth. Sin embargo, hay un matiz. Desde la versión 8.0 de Android, la actitud hacia tales servicios ha cambiado: ahora, si la aplicación se minimiza en este momento, sus servicios en segundo plano se cortan infernalmente por el eje para ahorrar energía. Y, si su código realiza, por ejemplo, una copia de seguridad de datos, entonces, en principio, no le importa en qué momento exacto el eje lo dejará funcionar; lo principal es que funciona. Pero en mi caso, necesitamos rastrear el cambio de ubicación casi en tiempo real, y el momento es crítico aquí. Por lo tanto, la única forma de salir es comenzar el servicio de antemano. Describimos una pequeña notificación adjunta en la cortina, nos suscribimos a la ubicación, la enviamos al dardo a través del MethodChannel. Todo parece funcionar.
Por cierto, volviendo a los problemas de memoria, consumo de energía y cantidad de solicitudes: el código se ejecuta cuando la ubicación se desplaza a 50 metros o por temporizador. Además, él mismo es muy ligero, y las solicitudes no pasan por mí, sino que van directamente a la API AQUÍ. Yo mismo no recibo ningún dato y no lo guardo en ningún lado. En general, esta implementación se describe muy bien
aquí , este es el blog de uno de los ingenieros de flutter: el código también se adjunta allí. Su ejemplo es algo diferente, pero el enfoque general es claro, por lo que recomiendo leerlo.
Resultado
Eso, de hecho, es todo. Durante un mes de tiempo libre, obtuve una aplicación que resuelve perfectamente un problema específico. Espero que este artículo sea interesante para alguien y que la aplicación lo salve de multas y estrés. Puedes mirar y regañar aquí:
Android ,
iOS .
Gracias a todos por su atención.