
Hola a todos! Hace unos seis meses lanzamos una de las características más emocionantes de Badoo:
transmisión en vivo . Una de sus principales funcionalidades es que los espectadores pueden enviar regalos a sus serpentinas favoritas para expresar su agradecimiento. Queríamos hacer los regalos lo más elegantes y atractivos posible, por lo que se decidió hacer que algunos de ellos fueran realmente animados, y con esto quiero decir animados. Y para involucrar aún más a las personas, nosotros, el equipo de Badoo, planeamos actualizar esos regalos y animaciones cada pocas semanas.
Como ingeniero de iOS, es posible que ya haya adivinado el desafío que enfrentamos aquí: la necesidad de agregar nuevas animaciones y eliminar las antiguas requeriría una gran cantidad de trabajo del lado del cliente. Necesitaríamos tanto el equipo de desarrollo de Android como el de iOS para cada lanzamiento, lo que, cuando se combina con la cantidad de tiempo que las revisiones y la aprobación de la App Store a menudo toman, significaría que podrían pasar días antes de que cada actualización se active. Pero resolvimos el problema y les explicaré cómo.
Resumen de la solución
En esta etapa, ya sabíamos cómo
exportar animaciones Adobe After Effects (AAE) en el formato legible por nuestra aplicación iOS usando la biblioteca Lottie. Esta vez, sin embargo, fuimos un poco más allá: decidimos crear una especie de servicio de almacenamiento de animación, disponible a través de Internet. En otras palabras, almacenaríamos todas las animaciones reales en el servidor y las enviaríamos a las aplicaciones del cliente a pedido:

Así es como se ve la solución final en el simulador de iOS en la máquina del desarrollador:
Sin embargo, en esta publicación, el ejemplo que voy a usar es una animación muy simple que yo mismo creé. No es tan elegante como la de Badoo, pero es lo suficientemente bueno como para demostrar el potencial del enfoque descrito.
Exportando animaciones
El proyecto de animaciones Adobe After Effects (AAE) que estoy usando aquí se puede encontrar junto con otros
archivos fuente en github . Entonces, después de abrir el proyecto de animación AAE ubicado en
_raw/animations/Fancy/Fancy.aep
, debería ver una ventana como esta:

En este punto, no voy a analizar cómo se crean las animaciones en AEE, pero lo que voy a explicar es cómo importar animaciones ya existentes de AAE a un formato legible por aplicación iOS usando el
complemento Bodymovin .
Después de asegurarse de que el complemento esté instalado, ábralo seleccionando la opción
Ventana / Extensiones / Bodymovin en el menú:

Ahora debería ver la ventana Bodymovin donde puede seleccionar la animación que desea exportar, especificar la ruta del archivo de salida y luego abrir la configuración de exportación:

Después de seleccionar y abrir la configuración de animación, ahora podemos pedirle a Bodymovin que incruste los activos en el archivo JSON resultante marcando la opción
Activos / Incluir en json :

Finalmente, la composición de animación seleccionada se exporta y guarda en el archivo especificado haciendo clic en el botón
Renderizar .
Almacenar animaciones en el servidor
Supongamos que hemos movido nuestros archivos JSON de animaciones renderizadas a nuestro servidor web preferido a través de Internet. En nuestro caso, por simplicidad, los he subido al repositorio de github de este proyecto. Las animaciones están disponibles aquí:
URL base:
https://raw.githubusercontent.com/chupakabr/server-provided-animations/master/_raw/rendered-animations/ID específicos de animación:
clouds.json
fireworks.json
Nota: ¿Busca un servidor web de proveedor de animaciones escrito en Swift? Encuentre la solución aquí en github y una explicación detallada en este artículo .
En este punto, tenemos un servidor proveedor de animaciones completamente funcional, por lo que es hora de pasar a la parte más emocionante: presentar las animaciones a nuestros usuarios.
Obteniendo y presentando animaciones
En este punto, recomiendo abrir nuestro proyecto de aplicación iOS de ejemplo ubicado en
Client/ServerProvidedAnimation.xcworkspace
ya que ya tiene todos los códigos y configuraciones necesarios.
Cargando datos de animaciones
Dado que los puntos finales de la API REST para obtener datos de animación ahora están en funcionamiento, es hora de introducir el protocolo del proveedor de datos y agregar su implementación de servidor:
import Lottie protocol AnimationsProviderProtocol { typealias Completion = (_ animation: LOTComposition?) -> Void func loadAnimation(byId id: String, completion: @escaping Completion) } final class ServerAnimationProvider: AnimationsProviderProtocol { private let endpoint: URL init(endpoint: URL) { self.endpoint = endpoint } func loadAnimation(byId id: String, completion: @escaping Completion) { let path = "/\(id).json" guard let animationUrl = URL(string: path, relativeTo: self.endpoint) else { completion(nil) return } URLSession.shared.invalidateAndCancel() let task = URLSession.shared.dataTask(with: animationUrl) { (data, response, error) in guard error == nil, let data = data, let json = self.parseJson(from: data) else { completion(nil) return } let animation = LOTComposition(json: json) completion(animation) } task.resume() } private func parseJson(from data: Data?) -> [AnyHashable : Any]? { guard let data = data else { return nil } do { let json = try JSONSerialization.jsonObject(with: data, options: []) as? [AnyHashable : Any] return json } catch { return nil } } }
Esta clase de proveedor de datos nos permite cargar animaciones del servidor en formato JSON a pedido y guardarlas en la memoria para renderizar en la interfaz de usuario. Suponiendo que estamos siguiendo el patrón MVVM, se puede usar fácilmente en la entidad
ViewModel
de la siguiente manera:
// ... private let animationProvider: AnimationsProviderProtocol private(set) var animationModel: LOTComposition? // … func loadAnimation(byId animationId: String) { self.animationProvider.loadAnimation(byId: animationId) { [weak self] (animationModel) in self?.animationModel = animationModel } } // ...
ViewModel
actualiza la propiedad de datos de animación seleccionada cuando recibe una respuesta HTTP válida del servidor con un objeto JSON no vacío dentro. La capa de presentación utiliza estos datos para programar la representación de la animación.
Capa de presentación
Ahora podemos usar nuestro ViewModel para acceder a los datos de animación y presentarlos a través de la interfaz de usuario en el controlador de acción "al toque" adjunto al botón:
class ViewController: UIViewController { // ... @IBOutlet weak var animationContainer: UIView! override func viewDidLoad() { super.viewDidLoad() // ... self.animationView = { let view = LOTAnimationView(frame: self.animationContainer.bounds) self.animationContainer.addSubview(view) return view }() } @IBAction func onPlayAnimationAction(_ sender: Any) { self.animationView.stop() self.animationView.sceneModel = self.viewModel.animationModel self.animationView.play() } }
Básicamente, lo que tenemos aquí es un controlador de botones que desencadena una actualización de la instancia LOTAnimationView con los datos de animación más recientes provenientes del
ViewModel
.
Así es como se ve el resultado final:
Eso es todo. Las animaciones ahora se cargan desde el punto final API REST preparado y se procesan en el cliente a pedido.
Consejos y limitaciones
Consejos y trucos:
- AAE permite el uso de la mayoría de los tipos de activos, incluidos los gráficos ráster y vectoriales;
- Bodymovin hace posible incrustar todos los activos en un archivo de animación JSON de salida (usando codificación base64); esto significa que podemos evitar la carga de activos separados en el lado del cliente;
- Para las animaciones, puede elegir entre dibujar directamente en el vector en AAE o simplemente importar gráficos vectoriales de Adobe Illustrator.
Desafortunadamente, todavía no es posible importar gráficos vectoriales SVG en AAE (¡lo he intentado!).
Más trucos y problemas potenciales se describen en este
increíble artículo escrito por mi colega
Radoslaw Cieciwa .
Conclusiones
Entonces, ¿qué nos proporciona el uso de animaciones proporcionadas por el servidor? El beneficio más obvio de este enfoque es la capacidad de desacoplar a todos los interesados del flujo de actualización de animaciones. En otras palabras, para lanzar una nueva y elegante animación, todo lo que los diseñadores deben hacer es proporcionar la representación JSON de la animación al equipo del servidor. Y para eliminar uno, el equipo del servidor solo tiene que eliminar esa animación particular del servicio de descubrimiento. No hay tiempo perdido!
Otra cosa interesante es que la misma funcionalidad se puede implementar en todas las plataformas cliente compatibles (iOS, Android, Web, ...) sin tener que ajustar la funcionalidad del servidor existente o las animaciones sin formato.
Eso es todo por hoy! Gracias por leer
Recursos