Saltar navegación

Activa JavaScript para disfrutar de los vídeos de la Mediateca.

MyPilot TFG Herrera

Ajuste de pantalla

El ajuste de pantalla se aprecia al ver el vídeo en pantalla completa. Elige la presentación que más te guste:

Subido el 18 de mayo de 2026 por Juan José H.

9 visualizaciones

Explicación y demo de mi TFG - MyPilot y MyPilotDriver

Descargar la transcripción

Hola, mi nombre es Juan Herrera y soy el desarrollador de MyPilot. 00:00:02
MyPilot es una aplicación hecha para Android que es mi trabajo de fin de grado. 00:00:08
La idea es bastante simple. Hay situaciones en las que uno tiene un coche, 00:00:13
pero en ese momento no quiere o no puede manejarlo, ya sea porque ha bebido de más, 00:00:19
porque tiene una incapacidad física temporal, por lo que sea. 00:00:24
MyPilot es donde entra en ese momento. 00:00:28
La aplicación te permite pedir un conductor que se acerca a donde estás y te lleva a ti en tu vehículo hacia donde quieras 00:00:30
Es parecido a Uber o a Cabify, pero al revés 00:00:37
En esas aplicaciones el conductor llega en su propio vehículo, te recoge y te lleva 00:00:40
Aquí el conductor llegaría o en transporte público, o en bicicleta, o en algún otro medio de transporte o a pie 00:00:45
Y utiliza tu vehículo para llevarte a sitios 00:00:52
El sistema está compuesto por tres partes 00:00:56
El backend, que es el cerebro de todo, que es un API restricado. 00:00:59
Y las otras dos aplicaciones, que son las que van en el teléfono. 00:01:03
MyPilot, que va en el teléfono del viajero o el consumidor final. 00:01:06
Y MyPilotDriver, que es la app que va a manejar el conductor. 00:01:10
Las tres están conectadas entre sí y funcionan en tiempo real. 00:01:14
La arquitectura del sistema es de cliente-servidor. 00:01:18
Las dos aplicaciones en Kotlin se comunican con la API a través de dos canales principales de comunicación. 00:01:21
que son REST, para llamadas que no tienen necesidad de que sean inmediatas, ni que sean de respuesta bidireccional, 00:01:29
como hacer un rating, por ejemplo, que después de terminar un viaje se le pone una calificación a la otra persona, 00:01:38
y a través de WebSockets para las actividades o eventos que tienen que aparecer en tiempo real. 00:01:45
El uso de WebSockets y protocolos Storm permiten que la aplicación sea mucho más eficiente 00:01:51
a la hora de mantener un contacto en vivo con una API, porque en vez de estar llamando 00:01:59
constantemente o periódicamente a la API diciendo ocurrió algo, ocurrió algo, ocurrió 00:02:06
algo, la API no tiene ningún evento nuevo, simplemente espera a que la API cuando ocurra 00:02:12
algo realmente, le notifique. Eso lo hace mucho más eficiente en tiempo de ejecución 00:02:19
y en batería, en uso de batería. 00:02:24
El objetivo del proyecto era construir todo desde cero. El backend, la frontend, las aplicaciones 00:02:28
en Android, la comunicación en tiempo real y el funcionamiento entre sí, especialmente 00:02:34
conectado. Vamos a verlo. 00:02:42
Para el backend utilicé Java con Springwood, que es el framework estándar para APIs REST 00:02:44
en Java. La base de datos es MySQL gestionada con JPA e Hibernate, que me permiten saltarme 00:02:49
a escribir el SQL a mano y simplemente trabajar directamente con los objetos Java. Esto lo 00:02:56
podemos ver en los entities, más que nada, con estas anotaciones, las importaciones del 00:03:04
on-book para además saltarme a hacer los gets y sets, y a las transformaciones de algunos 00:03:08
elementos de la tabla de bases de datos a DTOS, porque no utilizaba todos los elementos de la tabla. 00:03:15
El motivo de la implementación de MGSQL como motor de bases de datos tiene que ver con la 00:03:25
cualidad de relacional que tiene el propio motor. Son varias tablas que tienen relaciones de foreign 00:03:30
key entre ellas y además es uno de los motores de base de datos que se integra mejor con API REST y con Spring Boot. 00:03:36
y con Spring Boot 00:03:42
para la autenticación utilicé 00:03:43
JWT o JSON Web Tokens 00:03:46
a grandes rasgos 00:03:48
esta clase lo que hace es 00:03:50
el gestor de autenticación 00:03:52
mediante JWT en la aplicación 00:03:54
su función principal sería generar 00:03:56
los tokens de acceso 00:03:58
cuando el usuario 00:03:59
inicia sesión correctamente 00:04:02
y posteriormente verificar que esos tokens sean válidos 00:04:03
en cada petición 00:04:06
para que nadie sin haber 00:04:07
que ha hecho el inicio de sesión pueda acceder a la base de datos ni a la lógica de negocio. 00:04:10
Además, se puede extraer información del usuario almacenada dentro del token, como el email o el rol. 00:04:16
Esta clase centraliza toda la lógica relacionada con JWT dentro de la API. 00:04:24
Se utiliza para implementar la autenticación stateless en Spring Boot. 00:04:29
Cuando un usuario inicia sesión, la clase genera un token firmado digitalmente que contiene su identidad y permisos. 00:04:32
Posteriormente, en la petición protegida, el sistema valida el token 00:04:39
y recupera la información del usuario sin necesidad de mantener sesiones en el servidor. 00:04:42
Este sistema utiliza la firma HMAC SHA-256 00:04:49
y expiración temporal para garantizar la seguridad en la arquitectura REST stateless. 00:04:54
Para la comunicación en tiempo real, utilicé WebSockets con el protocolo STOMP 00:05:03
que es el Spring que tiene integrado de forma nativa. 00:05:08
Básicamente es un canal persistente entre el servidor y cada aplicación por donde viajan los eventos. 00:05:11
Que el conductor aceptó, que el viaje empezó, que el viaje terminó y demás. 00:05:16
La mayor parte de lógica detrás del protocolo STOMP están en las aplicaciones. 00:05:23
Por ejemplo, aquí en MyPilotDriver tenemos un método que construye el canal 00:05:29
por el que va a estar escuchando todos los mensajes que manda la API, y cómo se desconecta. 00:05:36
Y en clases como el LoginViewModel es que tenemos la implementación de los métodos, 00:05:46
por ejemplo, que tenemos en SocketManager, en los que espera la respuesta de la API con 00:05:54
respecto al token del login, y si es exitoso pues true, y si no, pues dar la advertencia correspondiente. 00:06:04
Para los mapas y las rutas, utilicé la Google Maps Platform, el SDK de mapas, la Direction 00:06:16
SAPI para calcular las rutas, y la Place SAPI para el autocompletado de direcciones. 00:06:23
las llamadas http las hago con retrofit y el cliente stomp en android es una librería que 00:06:29
se llama crossfit, podemos ver retrofit como se usa por ejemplo aquí en api service 00:06:37
o en el propio repositorio de mapas o en el de viajes 00:06:45
Compose, Boot, Pack, eso simplemente conecta lo que es la aplicación con los endpoints de la API. 00:06:52
Las dos aplicaciones están escritas en Kotlin, las aplicaciones de Android, 00:07:09
están escritas en Kotlin y utilizan Jetpack Compose, que es el sistema de UI moderno de Android. 00:07:15
Este sistema permite generar componentes, animaciones, cambios de color, cambios de estado en cada uno de los componentes de la UI de una forma muy directa y muy sencilla. 00:07:19
El proyecto lo desarrollé en fases. Primero te debe construir el backend completo, las entidades de la base de datos, de la lógica de API REST y toda la lógica de estados de viaje. 00:07:38
Como podemos ver aquí, son cinco. 00:07:49
Solicitado, conductor en camino, en curso, finalizado y cancelado. 00:07:53
Las transiciones entre estados están validadas en el servidor, así que no podés pasar directamente de solicitado a finalizado, por ejemplo. 00:07:58
Se puede pasar de solicitado a cancelado. 00:08:05
Esto lo validamos en el service. 00:08:08
En el método de cambiar de estado en un momento se llama a Extransición Válida 00:08:09
Que es otro método que verifica efectivamente de que se cambie el estado de forma natural 00:08:23
Después desarrollé la app del viajero 00:08:29
Todo lo que es el mapa, la búsqueda del destino, el flujo de la solicitud 00:08:37
Recién después de eso, integré los WebSockets para que todo fuera en tiempo real 00:08:41
Y finalmente agregué la autentificación con cota WT 00:08:46
Ya para terminar, desarrollé MyPilotDriver 00:08:52
La disponibilidad, la cola de conductores, el flujo de aceptación y la gestión del viaje 00:08:57
El proyecto simplemente me parecía más sencillo y más lógico 00:09:01
Empezar por el backend y probar con Postman antes de tener apps 00:09:11
Porque el hecho de tener otra aplicación 00:09:15
Añadía otra capa de debugueo 00:09:18
Antes de que las cosas estuvieran realmente bien programadas 00:09:20
Obviamente del dicho al hecho hay un trecho 00:09:22
Realmente me había tomado conciencia 00:09:28
De la magnitud del proyecto 00:09:30
Teniendo en cuenta que son tres aplicaciones distintas 00:09:32
Si bien sí tiene mucho en común actuar en conjunto 00:09:35
Pero son tres aplicaciones 00:09:38
Y evidentemente siendo un solo integrante 00:09:40
el plan sufrió muchos cambios y yo pensaba que la API ya estaba terminada y el backend estaba 00:09:43
completo y funcionaba perfecto y al pensar en una nueva funcionalidad o una funcionalidad necesaria 00:09:52
que se me había olvidado al desarrollar algunas aplicaciones de las aplicaciones Kotlin teníamos 00:10:00
que teníamos. Tenía que volver a desarrollar el backend de otra forma, teniendo en cuenta 00:10:06
otros parámetros en pos de otra idea. Así que fue un vaivén bastante importante de 00:10:13
bastantes veces el proyecto. 00:10:20
Si tuviera que destacar tres cosas técnicas del proyecto serían las siguientes. Una de 00:10:24
ellas es la cola de conductores en la memoria. Cuando un viajero solicita un viaje, el sistema 00:10:30
notifica a los primeros 10 conductores disponibles, ordenados por tiempo de espera. El primero 00:10:35
en aceptar se le asigna el viaje y sale de la cola. Si lo rechaza, el sistema ofrece 00:10:40
el viaje al siguiente y cuando el viaje termina, el conductor vuelve automáticamente al final 00:10:44
de la cola. Inicializa la lista a partir de la base de datos y si en algún momento 00:10:49
un conductor se da de alta, o sea, activa el Available dentro de la aplicación, lo 00:10:56
mete a esperar en la cola. Una vez se le asigna el viaje se llama al 00:11:02
método eliminar para sacarlo de la cola e incorporar si es que 00:11:08
reincorporar es básicamente lo mismo que registrar. 00:11:18
La segunda y la tercera serían la implementación de la API de Google en la 00:11:23
aplicación de MyPilot y MyPilotDriver 00:11:29
porque el hecho 00:11:31
de contar con una API de Google 00:11:33
ya tenía aparte 00:11:35
otro proceso de trabajo 00:11:37
tu quedar de alta en una 00:11:38
cuenta 00:11:41
generar la API key secreta 00:11:42
de Google, generar una cuota 00:11:45
de uso máxima 00:11:47
para la API para que el proyecto 00:11:49
siga siendo gratis y 00:11:51
académicamente viable 00:11:53
y la tercera 00:11:54
cosa sería la implementación de esta 00:11:57
API de Google en conjunto 00:11:59
con la arquitectura 00:12:02
de las apps, el ModelViewViewModel 00:12:04
donde ViewModel 00:12:06
expone el estado de forma reactiva 00:12:08
y Compose redibuja 00:12:10
la UI automáticamente cuando algo 00:12:12
cambia. Además 00:12:14
destacó Datastore para persistir 00:12:16
la sesión ante reinicios de la app 00:12:18
teniendo en cuenta las tokens. 00:12:20
Durante el desarrollo del 00:12:26
proyecto hubo varios problemas interesantes 00:12:27
el principal fue de hardware 00:12:29
que no podía correr dos emuladores al mismo tiempo en la computadora 00:12:31
y además tener IntelliJ abierto con el backend corriendo para probarlo. 00:12:36
La solución que encontré fue simplemente exportarlo como HA al backend 00:12:41
y ejecutarlo directamente desde el terminal. 00:12:45
Consumía muchísimo menos memoria. 00:12:48
Además, durante gran parte del desarrollo utilicé Postman 00:12:50
con las solicitudes que haría el segundo emulador. 00:12:53
si tenía el MyPilot abierto, emulaba MyPilotDriver y viceversa. 00:13:00
El segundo problema fue con los WebSockets. 00:13:06
Al tratar de probarlo desde Android me tiraba al 400. 00:13:08
No me había dado cuenta de que por defecto Spring activa SockJS, 00:13:12
que es una capa de compatibilidad que choca con Android. 00:13:17
La solución fue simplemente deshabilitar SockJS y utilizar WebSocket puro. 00:13:22
El último problema que tuve, que parece ser un clásico de Android, fue que los mensajes 00:13:27
de WebSocket llegaban bien a la aplicación, los veía en el log, pero no se actualizaba 00:13:34
la UI. El problema principal era que el callback se estaba ejecutando en el hilo de I.O. y 00:13:38
no en el principal. La solución fue forzar que se ejecute en el hilo principal con Dispatches 00:13:46
Main. 00:13:51
Tenemos a la derecha la aplicación MyPilot, a la izquierda Postman y una terminal ejecutando la API 00:13:52
Iniciamos la sesión como James Walker que es un viajero que tenemos en la base de datos 00:14:00
Vemos que hace realmente la petición 00:14:05
Esperamos que cargue la pantalla 00:14:07
Permitimos el uso de la ubicación en el teléfono 00:14:10
Esto ya es una cosa del emulador 00:14:15
Por defecto define la ubicación como la oficina central de Google 00:14:18
Yo no estoy en California. 00:14:22
Podemos seleccionar cualquier parte del mapa o simplemente apretar el botón Take Me Home. 00:14:24
Ese botón carga de la base de datos al mapa la ubicación del hogar de la persona que está en sesión. 00:14:29
Todas las solicitudes que estamos haciendo las estamos haciendo en Postman utilizando el token de Login como una variable alojada en el entorno Collection de Postman. 00:14:36
Así podemos emular una autenticación válida para el Get que estamos haciendo. 00:14:44
Hacemos este Get para verificar que realmente se está creando un nuevo viaje. 00:14:48
creamos la solicitud del viaje con viajar ahora 00:14:52
y podemos ver en la API que realmente se hace la petición 00:14:57
ahí vemos el viaje nuevo creado con su nuevo ID 00:15:02
y ahora lo que vamos a hacer es cambiar la petición a post 00:15:13
para asignar el conductor a este viaje solicitado 00:15:17
en este caso evidentemente el token que estamos usando 00:15:21
es de un login de un rol conductor, más específicamente el conductor con los datos de nombre Carlos Ramírez. 00:15:24
Y ahí podemos ver efectivamente cómo sin tocar nada cambia el banner de la app de MyPilot 00:15:35
y efectivamente cambia el estado del viaje a conductor en camino. 00:15:43
Hacemos el cambio a PUT para cambiar el estado del viaje a iniciar. 00:15:48
y ahí vemos que tanto en la UI como en la base de datos 00:16:02
el estado del viaje ha cambiado en curso 00:16:08
cambiamos el estado de viaje finalizado y nos sale el banner de calificar al conductor 00:16:10
y guardamos 00:16:22
y ese sería todo el ciclo de vida de un viaje de MyPilot 00:16:25
esencialmente MyPilotDriver es muy parecido 00:16:28
simplemente cambia un poco la UI porque no tiene la barra de búsqueda 00:16:32
sino que tiene un switch que al activarlo empieza a escuchar viajes nuevos en la API 00:16:35
usamos aquí un post de un viaje que yo tenía ya preparado 00:16:40
y vemos como de nuevo sin tocar nada 00:16:43
el banner cambia y el estado del viaje aparece 00:16:46
porque es un viaje nuevo 00:16:49
apretamos aceptar, esperamos que cargue 00:16:51
y podemos ver como el estado cambia a ongoing trip 00:16:54
lo que pasa es que realmente el estado del viaje cambió a conductor en camino 00:16:57
en la pantalla podemos ver como se trazan las líneas de directions 00:17:00
hacia el punto de inicio del viaje solicitado 00:17:03
porque tiene que ir a buscar al pasajero 00:17:07
Una vez suponiendo que hayamos llegado ya a buscar al pasajero 00:17:10
Apretamos el botón de Let's Pilot 00:17:15
Que inicia el viaje 00:17:18
Y podemos ver como el mapa se limpia 00:17:20
Y marca la ubicación del destino del viajero 00:17:23
Google Directions carga desde la ubicación del propio teléfono 00:17:26
O el emulador en este caso 00:17:29
Por eso es que está marcándolo desde tan lejos 00:17:31
Una vez apretamos el botón de finalizar viaje 00:17:33
O End Trip o End Journey 00:17:37
damos por terminado el flujo 00:17:38
natural de 00:17:40
MyPilotDriver 00:17:42
En conclusión, si bien este 00:17:43
proyecto fue un reto, fue algo desafiante 00:17:46
fue muy entretenido 00:17:49
me enseñó muchísimo 00:17:50
y me dieron muchas ganas 00:17:52
de seguir desarrollando la app 00:17:54
incluso después de terminar el TFG 00:17:56
y entregarlo, porque creo que realmente 00:17:58
tiene futuro, es una app que 00:18:00
es 1. monetizable 00:18:02
2. resolvió un problema 00:18:04
real y específico 00:18:06
y cotidiano en la vida 00:18:08
de cualquier persona 00:18:10
y tiene mucho potencial 00:18:11
pero en lo que al TFG respecta 00:18:13
ya estaríamos llegando al final 00:18:16
muchísimas gracias por ver 00:18:18
hasta luego, un saludo 00:18:19
Idioma/s:
es
Etiquetas:
Aprendizaje Basado en Proyectos, Pensamiento Computacional
Autor/es:
Juan Herrera
Subido por:
Juan José H.
Moderado por el profesor:
Lucia San Miguel López (lucia.sanmiguel)
Licencia:
Reconocimiento - Compartir igual
Visualizaciones:
9
Fecha:
18 de mayo de 2026 - 23:28
Visibilidad:
Público
Centro:
IES FRANCISCO DE QUEVEDO
Duración:
18′ 25″
Relación de aspecto:
1.78:1
Resolución:
1920x1080 píxeles
Tamaño:
718.10 MBytes

Del mismo autor…

Ver más del mismo autor


EducaMadrid, Plataforma Educativa de la Comunidad de Madrid

Plataforma Educativa EducaMadrid