Animations fournies par le serveur dans les applications iOS



Salut tout le monde! Il y a environ six mois, nous avons lancé l'une des fonctionnalités les plus intéressantes de Badoo: la diffusion en direct . L'une de ses principales fonctionnalités est que les téléspectateurs peuvent envoyer des cadeaux à leurs streamers préférés pour exprimer leur appréciation. Nous voulions rendre les cadeaux aussi fantaisistes et aussi attrayants que possible, alors il a été décidé de rendre certains d'entre eux vraiment vivants, et par là je veux dire animés. Et pour impliquer davantage les gens, nous, l'équipe Badoo, avions prévu de mettre à jour ces cadeaux et animations toutes les quelques semaines.

En tant qu'ingénieur iOS, vous avez peut-être déjà deviné le défi auquel nous avons été confrontés ici: la nécessité d'ajouter de nouvelles animations et de supprimer les anciennes allait exiger beaucoup de travail du côté client. Nous aurions besoin des équipes de développement Android et iOS pour chaque version - ce qui, combiné au temps de révision et d'approbation de l'App Store, prendrait plusieurs jours avant la mise en ligne de chaque mise à jour. Mais nous avons résolu le problème, et je vais vous expliquer comment.

Présentation de la solution


À ce stade, nous savions déjà comment exporter des animations Adobe After Effects (AAE) dans le format lisible par notre application iOS à l'aide de la bibliothèque Lottie. Mais cette fois, nous sommes allés un peu plus loin: nous avons décidé de créer une sorte de service de stockage d'animation, disponible via internet. En d'autres termes, nous stockons toutes les animations réelles sur le serveur et les livrons aux applications clientes à la demande:



Voici à quoi ressemble la solution finale dans le simulateur iOS sur la machine du développeur:


Cependant, dans cet article, l'exemple que je vais utiliser est une animation très simple que j'ai créée moi-même. Ce n'est pas aussi sophistiqué que celui de Badoo, mais il est assez bon pour démontrer le potentiel de l'approche décrite.

Exportation d'animations


Le projet d'animations Adobe After Effects (AAE) que j'utilise ici peut être trouvé avec d'autres fichiers source sur github . Ainsi, après avoir ouvert le projet d'animation AAE situé dans _raw/animations/Fancy/Fancy.aep , vous devriez voir une fenêtre comme celle-ci:



À ce stade, je ne vais pas expliquer comment les animations sont créées dans AEE, mais ce que je vais expliquer, c'est comment importer des animations déjà existantes d'AAA dans un format lisible par l'application iOS à l'aide du plug-in Bodymovin .

Après vous être assuré que le plugin est installé, ouvrez-le en sélectionnant l'option Fenêtre / Extensions / Bodymovin dans le menu:



Vous devriez maintenant voir la fenêtre Bodymovin où vous pouvez sélectionner l'animation que vous souhaitez exporter, spécifier le chemin du fichier de sortie, puis ouvrir les paramètres d'exportation:



Après avoir sélectionné et ouvert les paramètres d'animation, nous pouvons maintenant demander à Bodymovin d'incorporer les actifs dans le fichier JSON résultant en cochant l'option Actifs / Inclure dans json :



Enfin, la composition d'animation sélectionnée est exportée et enregistrée dans le fichier spécifié en cliquant sur le bouton Rendu .

Stocker des animations sur le serveur


Supposons que nous avons déplacé nos fichiers JSON d'animations rendues sur notre serveur Web préféré via Internet. Dans notre cas, pour des raisons de simplicité, je les ai téléchargées dans le référentiel github de ce projet. Les animations sont disponibles ici:


URL de base: https://raw.githubusercontent.com/chupakabr/server-provided-animations/master/_raw/rendered-animations/

ID spécifiques à l'animation:

  • clouds.json
  • fireworks.json

Remarque: Vous recherchez un serveur Web de fournisseur d'animations écrit en Swift? Trouvez la solution ici sur github et une explication détaillée dans cet article .
À ce stade, nous avons un serveur de fournisseur d'animations entièrement fonctionnel, il est donc temps de passer à la partie la plus excitante: la présentation des animations à nos utilisateurs.

Récupération et présentation d'animations


À ce stade, je recommande fortement d'ouvrir notre exemple de projet d'application iOS situé dans Client/ServerProvidedAnimation.xcworkspace car il possède déjà tout le code et les configurations nécessaires.

Chargement des données d'animations


Étant donné que les points de terminaison de l'API REST pour obtenir des données d'animation sont désormais opérationnels, il est temps d'introduire le protocole du fournisseur de données et d'ajouter son implémentation de serveur:

 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 } } } 

Cette classe de fournisseur de données nous permet de charger des animations à partir du serveur au format JSON à la demande et de les conserver en mémoire pour le rendu sur l'interface utilisateur. En supposant que nous suivons le modèle MVVM, il peut facilement être utilisé dans l'entité ViewModel de la manière suivante:

  // ... 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     } } // ... 

Le ViewModel met à jour la propriété de données d'animation sélectionnée lorsqu'il reçoit une réponse HTTP valide du serveur avec un objet JSON non vide à l'intérieur. Ces données sont utilisées par la couche de présentation pour planifier le rendu de l'animation.

Couche de présentation


Nous pouvons maintenant utiliser notre ViewModel pour accéder aux données d'animation et les présenter via l'interface utilisateur dans le gestionnaire d'actions "on tap" attaché au bouton:

 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()   } } 

Fondamentalement, ce que nous avons ici est un gestionnaire de boutons qui déclenche une mise à jour de l'instance LOTAnimationView avec les données d'animation les plus récentes provenant du ViewModel .

Voici à quoi ressemble le résultat final:


C'est à peu près ça. Les animations sont désormais chargées à partir du point de terminaison API REST préparé et rendues sur le client à la demande.

Conseils et limitations


Trucs et astuces:

  • AAE permet l'utilisation de la plupart des types d'actifs, y compris les graphiques raster et vectoriels;
  • Bodymovin permet d'incorporer tous les actifs dans un fichier d'animation JSON de sortie (en utilisant le codage base64) - cela signifie que nous pouvons éviter le chargement séparé des actifs côté client;
  • Pour les animations, vous avez le choix entre dessiner directement dans le vecteur en AAE ou simplement importer des graphiques vectoriels Adobe Illustrator.

Malheureusement, il n'est pas encore possible d'importer des graphiques vectoriels SVG dans AAE (j'ai essayé!).

D'autres astuces et problèmes potentiels sont décrits dans cet article étonnant écrit par mon collègue Radoslaw Cieciwa .

Conclusions


Alors, que nous apporte l'utilisation d'animations fournies par le serveur? L'avantage le plus évident de cette approche est la possibilité de découpler toutes les parties prenantes du flux de mise à jour des animations. En d'autres termes, pour publier une nouvelle animation de fantaisie, tout ce que les concepteurs doivent faire est de fournir la représentation JSON de l'animation à l'équipe du serveur. Et pour en supprimer un, l'équipe du serveur n'a qu'à supprimer cette animation particulière du service de découverte. Pas de temps perdu!

Une autre chose intéressante est que la même fonctionnalité peut être implémentée sur toutes les plates-formes clientes prises en charge (iOS, Android, Web, ..) sans avoir à ajuster la fonctionnalité de serveur existante ou les animations brutes.

C'est tout pour aujourd'hui! Merci d'avoir lu

Les ressources


Source: https://habr.com/ru/post/fr439370/


All Articles