服务器上的iOS应用程序中的动画



六个月前,我们推出了Badoo最令人印象深刻的功能之一- 实时流媒体 。 除其他事项外,它还允许用户以礼物的形式对自己喜欢的彩带表示感谢。 我们希望使这些礼物尽可能明亮和吸引人,因此我们决定复兴它们-换句话说,赋予生命。 为了使它更加有趣,我们计划每几周更新一次礼物和动画。

iOS工程师必须已经猜到有什么工作要做:为了删除旧动画并添加新动画,必须在客户端执行许多操作。 为此,Android和iOS团队必须参与每个版本,并且在App Store中批准更新所需的时间,这意味着每个发布带有更新动画的版本可能要花费几天的时间。 但是,我们设法解决了这个问题,现在我将告诉您如何解决。

解决方案架构


到那时,我们已经知道如何使用Lottie库以我们的iOS应用程序可以理解的格式导出Adobe After Effects动画(以下称为AAE) 。 这次我们走得更远:我们决定将所有相关的动画存储在服务器上,并根据需要下载它们。



通过以下方式获得的应用程序中真实动画的示例:



但是,在本文中,我将以自己创建的简单动画为例。 它不像Badoo那样具有创造力,但是非常适合演示我们的方法。

导出动画


可以在GitHub上找到我使用的AAE项目以及其他资源 。 因此,打开位于_raw/animations/Fancy/Fancy.aep ,您将看到一个窗口:



现在,我不是在讨论在AAE中创建动画的过程,而是在讨论如何使用Bodymovin插件从AAE将现有动画导入适合iOS应用程序的格式。

安装插件后,通过从菜单中选择Window / Extensions / Bodymovin来打开它:



将显示“ Bodymovin”窗口,您可以在其中选择要导出的动画,用于保存结果文件的文件夹并打开导出设置:



在动画设置中,我们可以通过选择Assets / Include in json来要求Bodymovin在JSON文件中包括资源:



最后,通过按“ 渲染”按钮,我们将选定的动画构图导出并保存到文件中。

在服务器上存储动画


假设我们将渲染的动画JSON文件上传到Web服务器。 在我们的案例中,为简单起见,我将它们放在GitHub上的项目存储库中。 动画在这里可用:



基本链接https://raw.githubusercontent.com/chupakabr/server-provided-animations/master/_raw/rendered-animations/

动画ID:

  • clouds.json
  • fireworks.json


注意:是否正在寻找用于动画的Swift Web服务器? 该解决方案在这里可用,并且本文中有详细的说明。


因此,我们有一台具有动画的工作服务器,因此该着手最有趣的部分了:在屏幕上渲染动画。

动画展示


现在,我建议您为我们的iOS应用程序打开一个演示项目,因为它包含所有必要的代码和设置。

下载动画


鉴于用于接收数据的REST API已经准备就绪,是时候介绍数据提供者的协议并添加其实现了,该实现将从服务器下载数据:

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


该数据提供程序类允许我们根据请求从服务器下载JSON格式的动画,并将其存储在内存中以呈现到UI。 假设我们遵循MVVM模式-那么很容易在ViewModel实体中使用它,如下所示:

  // ... 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从带有非空JSON对象的服务器接收到正确的HTTP响应时, ViewModel更新所选动画的属性。 表示层使用此数据来显示动画。

表示层


现在,我们可以使用ViewModel来访问动画数据,并使用附加到按钮的内置点击动作处理程序将其显示在UI上:

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


单击按钮时,将使用ViewModel的最新数据更新LOTAnimationView实例。

看起来是这样的:



仅此而已。 现在,该应用程序显示从REST API下载的动画
(来自服务器)。

提示与限制


技巧:

  • AAE支持大多数类型的对象,包括光栅和矢量图像。
  • Bodymovin允许您使用Base64将所有资源嵌入最终的JSON文件中,因此,您可以避免在客户端分别加载资源。
  • 您可以直接在AAE中绘制矢量,也可以简单地以Adobe Illustrator格式导入矢量图像。

不幸的是,我无法将SVG文件导入AAE(我尝试过!)。

您可以从我的同事Radoslaw Sesiva的这篇有趣的文章中了解更多有关技巧和解决可能出现的问题的信息

结论


那么,从服务器下载动画会给我们带来什么呢? 这种方法最明显的好处是可以共享动画更新过程中的所有参与者。 换句话说,要发布新的炫酷动画,设计人员只需要向服务器团队提供适当的JSON文件即可。 要在客户端上删除动画,只需将其从服务器上删除即可。 简单快速。

同样很酷的是,可以在所有受支持的平台(iOS,Android,Web)上实现相同的功能,而无需直接在客户端上更改客户端-服务器协议,服务器代码和动画文件本身。

仅此而已。 感谢您的关注!


有用的链接


Source: https://habr.com/ru/post/zh-CN439368/


All Articles