Nuestra experiencia usando MotionLayout en los pagos por NFC

En Mercado Libre estamos en beta continuo constantemente, este principio cultural lo vemos reflejado en nuestros pagos con NFC, donde exploramos un componente nuevo de Android para crear una experiencia única.

Rodrigo Dominguez
Mercado Libre Tech
Published in
9 min readOct 15, 2021

--

Leer esta historia en inglés.

Comencemos desde donde hemos comenzado los Android Devs del equipo encargado de la experiencia de pagos por NFC en Mercado Pago.

La experiencia que hemos creado junto al equipo de UX.

En este video podemos ver la propuesta completa del flujo para realizar un pago por NFC que nos trajo el equipo de UX.

Flujo completo de la experiencia de pago por NFC para Brasil.

Y como Android Devs al ver esta animación nos surgieron las siguientes preguntas:

¿Cómo hacemos esto? 😅
— No lo se Rick!

¿Alguien dentro de Mercado Libre hizo algo así? 🤔
— No

¿UX’s, se podría hacer más simple? 🥺
— Hmm.. no.

Luego de las primeras preguntas, surgieron otras, un poco más técnicas..

¿Qué componente podemos usar?
— MotionLayout (by Rodrigo Dominguez, tal vez me conozcan de mis contribuciones en ConstraintLayout y algunas charlas sobre MotionLayout 1, charla 2 y charla 3)

¿Existe algo nativo que nos ayude a crear esta experiencia?
— MotionLayout, MotionLayout (IT Team)

¿Con ObjectAnimator, ValueAnimator, etc. podríamos crear esa experiencia?
— No, MotionLayout, MotionLayout, MotionLayout (IT Team)

¿Las animaciones con ConstraintLayout nos pueden ayudar?
— Tal vez, pero , MotionLayout, MotionLayout, MotionLayout (IT Team)

En Mercado Libre ya usamos Lottie que nos da una Developer Experience común para ambas plataformas, ¿Qué pasaría si usamos eso?
— Con Lottie no podríamos tener la información de labels de forma dinámica, no podríamos manejar los estados de nuestras transiciones e interacciones del usuario con la animación.

Ok Rodri, pero, ¿qué es MotionLayout?
— Es un nuevo componente de Android, para animar widgets entre diferentes estados, justo lo que necesitamos 😁

Estado A _____________________________________________ Estado B

Transición

En nuestra experiencia usamos los estados como les mostramos a continuación..

Estado A _____________________________________________ Estado B

Transición

Más desafíos en la experiencia

Nuestra experiencia de pago requiere un primer “tap” con el POS Terminal para iniciar la comunicación vía NFC, y luego un segundo tap donde confirmamos la operación.
Además requiere poder pagar con un solo tap, una vez terminado el pago se debe mostrar información de la transacción exitosa, es decir, en este flujo no se muestran las transiciones del segundo tap, lo cual requiere que nuestra animación viaje de un estado A, a un estado D, sin pasar por estado B y estado C.
En el siguiente ejemplo, podremos ver como con un tap aprobamos una transacción (estado B), pero al no tener internet mostramos una estado D al finalizar la animación.

También poder abrir nuestro flujo desde cualquier parte de la aplicación con el primer “tap” al POS, esto implicaba diferentes puntos de entradas y diferentes estados de nuestra animación.

Otro de los desafíos es soportar pagos sin acceso a internet, y que la animación comunicara el pago exitoso, pero con transiciones diferentes.
Debido a todas estos diferentes puntos de entrada, pagos sin internet, uno o dos taps para pagar exitosamente, entendimos que Lottie no podría soportar diferentes estados y comunicar al usuario cuando comienza y finaliza una transición.

MotionLayout nos provee “listeners” para conocer los estados de nuestras transiciones, iniciar una nueva transición, reiniciarla y setear el progreso.
Luego de estas cartas sobre la mesa, concluimos que MotionLayout era la mejor opción para toda la experiencia de pago por NFC. Sin embargo, nos surgió una nueva duda:

¿Qué cambios implicaría dejar disponible este componente para todos los equipos de Mercado Libre?

A continuación le contamos brevemente cómo actualizamos nuestras bibliotecas de terceros dentro de Mercado Libre. Para este caso, MotionLayout es un componente que se incluye en la última versión de la biblioteca de ConstraintLayout.

Update ConstraintLayout

Actualizar nuestras librerías no es simplemente modificar una version en las dependencias de gradle, “buildear”, y compilar. En Mercado Libre trabajamos con la plataforma Android decenas de equipos y cientos de developers. Todas las bibliotecas de terceros con sus respectivas versiones, se encuentran centralizadas y en una allowlist, para no tener un caos de versiones, bibliotecas innecesarias, y todos los problemas que podrían surgir al tener distintas versiones en diferentes módulos.

Al momento de comenzar a crear la experiencia de NFC, nuestra versión de ContraintLayout se encontraba en su versión 1.1.3, para poder utilizar MotionLayout, necesitábamos actualizar a la versión 2.0.

Así es como actualizamos nuestras dependencias dentro de Mercado Libre, comunicamos a todos nuestros equipos que en X versión de nuestra App actualizaremos a la versión x.y.z una determinada biblioteca. Cada equipo es responsable de probar, y actualizar su proyecto para subir al release train 🚃 indicado.

Construyendo nuestra animación para el pago con NFC

Luego de actualizar nuestra versión de ConstraintLayout a la 2.0, les mostramos paso a paso cómo hemos construido toda nuestra experiencia completa.

Antes de comenzar, hagamos una aclaración, en MotionLayout los diferentes estados se llaman ConstraintSet, este ConstraintSet va a agrupar las diferentes restricciones y atributos que van a tener nuestras diferentes vistas. Desde aquí en adelante a nuestros ConstraintSet le llamaremos state (stateA, stateB,.. etc). y para representar una transición de un constraintSet hacia otro, lo llamaremos de la siguiente manera stateA -> stateB.

Transición 1: Preparando nuestra animación antes del primer tap

En nuestro stateA vemos que tenemos la imagen del POS (imagen izquierda) y la imagen del celular (imagen derecha) en los laterales de nuestra pantalla, en el stateB ambas imágenes se corren hacia el centro de nuestra pantalla, es allí donde termina nuestra transición 1 (stateA -> stateB). Aquí es donde indicamos al usuario que debe acercar su celular al POS para la primer comunicación.

Transición 2: Listos para el primer tap

Luego de finalizar la transición 1, nuestra experiencia debe comunicar al usuario que acerque su celular al POS terminal, aquí es donde utilizamos una de las ventajas que nos da MotionLayout de poder ejecutar las transiciones en el momento que nosotros queremos. Entonces, al finalizar nuestra transición 1, ejecutamos automáticamente la transición 2 (stateB -> stateC).

Transición 3: Esperando la comunicación con el POS

Al finalizar nuestra transición 2, debemos esperar que el usuario acerque su celular al POS y lograr una comunicación exitosa para poder ejecutar el pago (aquí viajamos desde stateC -> stateD).

Mientras esperamos, debemos mostrar un efecto circular sobre nuestra tarjeta principal de la siguiente manera:

Y es allí donde nos surge otra pregunta..

¿Podríamos utilizar Lottie para algunas partes de la experiencia?

Si, hemos podido mezclar Lottie con MotionLayout sin problemas, para animaciones estáticas como por ejemplo los círculos celestes para esperar la comunicación con el POS en nuestra Transición 3.

Otro momento de la experiencia donde aprovechamos la sinergia de estas 2 tools (Lottie + MotionLayout) fue al realizar un pago con éxito:

Y para un pago sin internet el cual no podemos obtener información de la transacción, también jugamos con la visibilidad y play de una animación Lottie.

Continuemos con nuestra animación completa…

Transición 4: Comunicando un mensaje de conexión exitosa con el POS

En esta animación debemos comunicar al usuario que hemos comunicado correctamente el celular con el POS, viajamos de nuestro estado actual stateD a nuestro stateE, simplemente cambiamos la visibilidad de algunos textos, y también escondemos nuestra animación de Lottie de los círculos celestes (en nuestro visor de Android Studio no se pueden reproducir las animaciones de Lottie).

Transición 5: Comunicando que el pago fue exitoso

En esta animación debemos comunicar al usuario que hemos pagado con exito luego del segundo tap con el POS (viajamos desde stateE -> stateF), cambiamos la visibilidad de algunos textos, y mostramos nuestros círculos verdes de Lottie como mencionamos arriba.

Transición 6: Mostrando información del pago

Luego de finalizar nuestro pago exitoso, debemos esperar la información del pago desde nuestro backend, en caso de no tener internet, transicionamos hacia un stateH para comunicar que finalizo la transacción, en caso de tener internet y obtener la información de la operación debemos ejecutar una transición hacia un stateG.

Transición 7: Mostrando información del pago exitoso

Última transición de nuestra experiencia, aquí mostramos la información de nuestra operación exitosa (viajamos desde stateI). Jugamos con la ubicación de nuestra tarjeta principal, y mostramos el bloque de vistas que contiene toda la información de la transacción.

Hemos utilizado todo el potencial de MotionLayout, desde sus multiples estados, KeyFrames para dar efectos de movimientos en nuestra tarjeta principal, y hasta su listeners para conocer cuándo termina una transición, hemos logrado replicar la animación casi idéntica a la propuesta por nuestro equipo de UX.

Lecciones aprendidas

  1. MotionLayout nos da potencial para crear animaciones, que con otras herramientas eran muy difíciles de lograr.
  2. Al tener más de 5 estados, tener las siguientes consideraciones:
  • Manejo del estado en curso de las transiciones.
  • Tamaño del XML (motionScene).

Tener XML con muchas transiciones complejiza la lectura del mismo, por lo tanto es más complejo también mantenerlo y más propenso a errores.

  • Nombres claros para los diferentes ConstraintSets (states).

3. Usar MotionLayout cuando el usuario tiene interacción con la animación.

4. No mezclar manejo de animaciones propias (ej: visibility, rotation, scale, etc) con las de MotionLayout.

Al intentar cambiar mismos atributos desde el código, y también desde los states de MotionLayout, hemos visto comportamientos inesperados, por ejemplo, al querer cambiar la visibilidad por codigo de algunas vistas, y también manejarlo desde MotionLayout, al cambiar de un state a otro state, la visibilidad no se ejecutaba como esperábamos.

5. Usar navegación lineal entre transiciones

stateA -> stateB, stateB -> stateC ✅
stateA -> stateC ❌

Hemos encontrado comportamientos no esperados cuando hemos transicionado de stateA -> StateC sin pasar por el StateB, cuando nuestras vistas viajan de un stateA -> stateB ambos state conocen los atributos iniciales y finales de todas las vistas que hemos declarado en ambos states, pero cuando realizamos un stateA -> stateC puede que algunas vistas no las hemos declarado en alguno de nuestros states y genere transiciones diferentes a las esperadas.

6. Es posible combinar MotionLayout con Lottie sin problemas.

Experiencia en producción 🚀

Luego de un intenso testing interno, iteraciones, y muchos pagos mockeados, el feature salió a la luz en Brasil durante el Q1 de 2021.

Nos llena de orgullo ver cómo se puede pagar exitosamente con NFC en el subte de Río de Janeiro, Brasil.

Animación donde mostramos una prueba real de pago por NFC en el subte de Rio de Janeiro, Brasil.
En este video mostramos una prueba real de pago por NFC en el subte de Rio de Janeiro, Brasil.
Por medio de una animación mostramos una prueba real de pago por NFC en uno de nuestros dispositivos POS.
En este video mostramos una prueba real de pago por NFC en POS.

…y vos? ¿Cuál fue tu experiencia usando MotionLayout? ¿Te animas a compartirla en los comentarios?

--

--

Rodrigo Dominguez
Mercado Libre Tech

Android Tech Lead @ Uala | Previously MercadoLibre, Despegar, Kavak.com