- PVSM.RU - https://www.pvsm.ru -

Полгода назад мы представили одну из самых впечатляющих функций Badoo — прямые трансляции [1]. Среди прочего она позволяет пользователям выразить благодарность любимым стримерам в виде подарков. Мы хотели сделать эти подарки максимально яркими и привлекательными, поэтому решили их оживить — другими словами, анимировать. А чтобы было ещё интереснее, мы планировали обновлять подарки и анимации каждые несколько недель.
iOS-инженеры наверняка догадались, о каких объёмах работы идёт речь: чтобы удалять старые и добавлять новые анимации, необходимо совершить множество действий с клиентской стороны. Для этого в каждом релизе должны быть задействованы Android- и iOS-команды, а вкупе со временем, необходимым на одобрение обновления в App Store, это означает, что запуск каждого релиза с обновлёнными анимациями может занять несколько дней. Однако нам удалось решить эту проблему, и сейчас я расскажу как.
К тому времени мы уже умели экспортировать анимации Adobe After Effects (далее — AAE) в понятный нашему iOS-приложению формат [2] при помощи библиотеки Lottie. В этот раз мы пошли чуть дальше: решили хранить все актуальные анимации на сервере и скачивать их по мере необходимости.

Пример реальной анимации в нашем приложении, полученной таким способом:

Однако в этом посте в качестве примера я возьму простенькую анимацию, которую создал сам. Она не такая креативная, как в Badoo, но вполне подходит для демонстрации нашего подхода.
AAE-проект, который я использую, можно найти вместе с другими исходниками на GitHub [3]. Итак, открыв проект, расположенный по адресу _raw/animations/Fancy/Fancy.aep, вы увидите окно:

Сейчас я расскажу не о процессе создания анимаций в AAE, а о том, как импортировать уже существующие анимации из AAE в подходящий для iOS-приложения формат при помощи плагина Bodymovin [4].
Установив плагин, откройте его, выбрав в меню Window/Extensions/Bodymovin:

Появится окно Bodymovin, в котором можно выбрать анимацию для экспорта, папку для сохранения получившегося файла и открыть настройки экспорта:

В настройках анимации мы можем попросить Bodymovin включить ресурсы в JSON-файл, выбрав пункт Assets / Include in json:

Наконец, нажатием кнопки Render экспортируем и сохраняем в файл выбранную анимированную композицию.
Предположим, что мы загрузили JSON-файлы отрендеренных анимаций на веб-сервер. В нашем случае для простоты я поместил их в репозиторий проекта на GitHub. Анимации доступны здесь:
Базовая ссылка https://raw.githubusercontent.com/chupakabr/server-provided-animations/master/_raw/rendered-animations/ [7]
Идентификаторы анимаций:
clouds.json
fireworks.json
Примечание: ищете написанный на Swift веб-сервер для анимаций? Решение доступно здесь [8], а подробное объяснение — в этой статье [9].
Итак, у нас имеется рабочий сервер с анимациями, а потому пора перейти к самой захватывающей части: рендерингу анимаций на экране.
Сейчас я советую открыть проект демоверсии нашего iOS-приложения [10], так как он содержит весь необходимый код и настройки.
Учитывая, что 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 для получения доступа к данным анимации и отображать их на 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()
}
}
При нажатии на кнопку экземпляр LOTAnimationView обновляется с помощью свежих данных из ViewModel.
Вот как это выглядит:

Вот и всё. Теперь в приложении отображается анимация, загруженная из нашего REST API
(с сервера).
Хитрости:
К сожалению, у меня не получилось импортировать в AAE файлы формата SVG (я пытался!).
Узнать больше о хитростях и решении возможных проблем вы можете из этой интересной статьи [2] моего коллеги Радослава Сесивы [2].
Итак, что нам даёт загрузка анимаций с сервера? Самое очевидное преимущество этого подхода — возможность разделить всех участников процесса обновления анимации. Иными словами, чтобы выпустить новую крутую анимацию, дизайнерам достаточно предоставить серверной команде соответствующий JSON-файл. Чтобы удалить анимацию на клиенте, достаточно просто удалить её с сервера. Легко и быстро.
Ещё очень здорово, что одни и те же функции можно реализовать на всех поддерживаемых платформах (iOS, Android, Web), не внося изменений в клиент-серверный протокол, серверный код и в сами файлы анимаций непосредственно на клиенте.
На этом всё. Спасибо за внимание!
Автор: Valeron
Источник [17]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/razrabotka/308052
Ссылки в тексте:
[1] прямые трансляции: http://badoo.live/
[2] экспортировать анимации Adobe After Effects (далее — AAE) в понятный нашему iOS-приложению формат: https://badootech.badoo.com/behind-the-scenes-with-importing-adobe-after-effects-animation-into-badoo-ios-app-45a21e2ba1e4
[3] другими исходниками на GitHub: https://github.com/chupakabr/server-provided-animations
[4] Bodymovin: https://airbnb.io/lottie/after-effects/bodymovin-installation.html
[5] Облака: https://raw.githubusercontent.com/chupakabr/server-provided-animations/master/_raw/rendered-animations/clouds.json
[6] Фейерверки: https://raw.githubusercontent.com/chupakabr/server-provided-animations/master/_raw/rendered-animations/fireworks.json
[7] https://raw.githubusercontent.com/chupakabr/server-provided-animations/master/_raw/rendered-animations/: https://raw.githubusercontent.com/chupakabr/server-provided-animations/master/_raw/rendered-animations/
[8] здесь: https://github.com/chupakabr/server-provided-animations/tree/master/Server
[9] в этой статье: https://medium.com/@myltik/rest-api-with-swift-on-vapor-fca5ea6667f
[10] демоверсии нашего iOS-приложения: https://github.com/chupakabr/server-provided-animations/tree/master/Client
[11] Radoslaw Cieciwa: https://medium.com/@radekcieciwa
[12] Bodymovin plugin for AAE: https://github.com/airbnb/lottie-web/blob/master/build/extension/bodymovin.zxp
[13] AirbnbEng: https://medium.com/@airbnbeng
[14] Lottie iOS library: https://github.com/airbnb/lottie-ios
[15] Валерий Чевтаев: https://github.com/chupakabr
[16] ZXP plugin installer: http://aescripts.com/learn/zxp-installer/
[17] Источник: https://habr.com/ru/post/439368/?utm_source=habrahabr&utm_medium=rss&utm_campaign=439368
Нажмите здесь для печати.