
大家好! 大约六个月前,我们推出了Badoo最激动人心的功能之一:
实时流媒体 。 它的主要功能之一是,观众可以向喜欢的彩带发送礼物,以表达他们的赞赏。 我们希望使这些礼物尽可能精美,吸引人,因此决定使其中的一些真正生动活泼,因此,我的意思是生动活泼。 为了进一步吸引人们,我们Badoo团队计划每几周更新一次这些礼物和动画。
作为一名iOS工程师,您可能已经猜到了我们在这里面临的挑战:需要添加新动画并删除旧动画,这需要在客户端进行大量工作。 每个发行版本我们都需要Android和iOS开发团队-再加上App Store审核和批准所花费的时间,这意味着每个更新可能要过几天才能发布。 但是我们已经解决了这个问题,我将向您解释。
解决方案概述
在此阶段,我们已经知道如何使用Lottie库
将Adobe After Effects(AAE)动画导出为iOS应用可读取的格式 。 但是这次,我们走得更远:我们决定创建一种动画存储服务,可以通过Internet获得该服务。 换句话说,我们会将所有实际的动画存储在服务器上,并根据需要将它们交付给客户端应用程序:

这是开发人员计算机上的iOS模拟器中最终解决方案的外观:
但是,在本文中,我将使用的示例是我自己创建的非常简单的动画。 它不像Badoo那样花哨,但足以说明所描述方法的潜力。
导出动画
可以
在github上找到我在这里使用的Adobe After Effects(AAE)动画项目以及其他
源文件 。 因此,在打开位于
_raw/animations/Fancy/Fancy.aep
的AAE动画项目
_raw/animations/Fancy/Fancy.aep
,您应该看到一个类似于以下的窗口:

在这一点上,我不打算讨论如何在AEE中创建动画,但是我要解释的是如何使用
Bodymovin插件将已经存在的动画从AAE导入到iOS应用可读格式。
确保已安装插件后,通过在菜单中选择
Window / Extensions / Bodymovin选项将其打开:

现在,您应该看到“ Bodymovin”窗口,您可以在其中选择要导出的动画,指定输出文件路径,然后打开导出设置:

选择并打开动画设置后,我们现在可以通过检查
Assets / Include in json选项,要求Bodymovin将资产嵌入到生成的JSON文件
中 :

最后,通过单击“
渲染”按钮,导出选定的动画作品并将其保存到指定的文件。
在服务器上存储动画
假设我们已通过Internet将渲染的动画JSON文件移动到首选的Web服务器上。 在我们的案例中,为简单起见,我将它们上传到了该项目的github存储库中。 动画在这里可用:
基本网址:
https :
//raw.githubusercontent.com/chupakabr/server-provided-animations/master/_raw/rendered-animations/动画专用的ID:
clouds.json
fireworks.json
注意:寻找使用Swift编写的动画提供商Web服务器吗? 在github上找到解决方案,并在本文中进行详细说明。
至此,我们拥有了一个功能齐全的动画提供者服务器,因此现在该着手最令人兴奋的部分了:向用户展示动画。
获取和呈现动画
此时,我强烈建议您打开位于
Client/ServerProvidedAnimation.xcworkspace
示例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
从服务器接收到有效的HTTP响应且其中包含非空JSON对象时,
ViewModel
更新选定的动画数据属性。 表示层使用此数据来安排动画渲染。
表示层
现在,我们可以使用ViewModel来访问动画数据,并通过UI将该事件显示在按钮上的“ on tap”动作处理程序中:
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可以将所有资产嵌入到输出JSON动画文件中(使用base64编码)-这意味着我们可以避免在客户端加载单独的资产;
- 对于动画,您可以选择在AAE中直接绘制到矢量中还是直接导入Adobe Illustrator矢量图形。
不幸的是,尚无法将SVG矢量图形导入AAE(我已经尝试过!)。
我的同事
Radoslaw Cieciwa撰写的这篇
惊人的文章中描述了更多的技巧和潜在的问题。
结论
那么,使用服务器提供的动画会给我们带来什么呢? 这种方法最明显的好处是能够分离动画更新流的所有涉众。 换句话说,要发布精美的新动画,所有设计人员要做的就是向服务器团队提供动画的JSON表示形式。 要删除一个动画,服务器团队只需从发现服务中删除该特定动画即可。 没有时间浪费!
另一个很酷的事情是,可以在所有受支持的客户端平台(iOS,Android,Web等)上实现相同的功能,而无需调整现有的服务器功能或原始动画。
今天就这样! 感谢您的阅读
资源资源