
Seis meses atrás, apresentamos um dos recursos mais impressionantes do Badoo -
transmissão ao vivo . Entre outras coisas, ele permite que os usuários expressem gratidão aos seus streamers favoritos na forma de presentes. Queríamos tornar esses presentes o mais brilhantes e atraentes possíveis, por isso decidimos revivê-los - em outras palavras, animar. E para torná-lo ainda mais interessante, planejamos atualizar presentes e animações a cada poucas semanas.
Os engenheiros do iOS provavelmente adivinharam quanto trabalho está sendo discutido: para remover animações antigas e adicionar novas animações, é necessário executar várias ações no lado do cliente. Para fazer isso, as equipes do Android e iOS devem estar envolvidas em cada versão e, juntamente com o tempo necessário para aprovar a atualização na App Store, isso significa que o lançamento de cada versão com animações atualizadas pode levar vários dias. No entanto, conseguimos resolver esse problema e agora vou lhe dizer como.
Arquitetura da solução
Naquela época, já sabíamos
exportar animações do Adobe After Effects (daqui em diante - AAE) em um formato compreensível para nosso aplicativo iOS usando a biblioteca Lottie. Desta vez, fomos um pouco mais longe: decidimos armazenar todas as animações relevantes no servidor e baixá-las conforme necessário.

Um exemplo de animação real em nossa aplicação, obtida desta maneira:
No entanto, neste post, como exemplo, pegarei uma animação simples que eu mesmo criei. Não é tão criativo quanto no Badoo, mas é bastante adequado para demonstrar nossa abordagem.
Exportar animações
O projeto AAE que eu uso pode ser encontrado junto com
outras fontes no GitHub . Então, abrindo o projeto localizado em
_raw/animations/Fancy/Fancy.aep
, você verá uma janela:

Agora, não estou falando sobre o processo de criação de animações no AAE, mas sobre como importar as animações existentes do AAE para um formato adequado para um aplicativo iOS usando o
plug- in
Bodymovin .
Após instalar o plugin, abra-o selecionando
Window / Extensions / Bodymovin no menu :

Aparecerá a janela Bodymovin, na qual é possível selecionar a animação para exportação, uma pasta para salvar o arquivo resultante e abrir as configurações de exportação:

Nas configurações de animação, podemos pedir ao Bodymovin para incluir recursos no arquivo JSON, selecionando
Ativos / Incluir no json :

Por fim, pressionando o botão
Render , exportamos e salvamos a composição animada selecionada em um arquivo.
Armazenando animações no servidor
Suponha que carregemos arquivos JSON animados renderizados em um servidor da web. No nosso caso, para simplificar, eu os coloquei no repositório do projeto no GitHub. As animações estão disponíveis aqui:
Link base
https://raw.githubusercontent.com/chupakabr/server-provided-animations/master/_raw/rendered-animations/IDs de animação:
clouds.json
fireworks.json
Nota: Procurando um servidor da Web Swift para animações? A solução está disponível aqui e uma explicação detalhada está neste artigo .
Portanto, temos um servidor ativo com animações, então é hora de passar para a parte mais interessante: renderizar animações na tela.
Exibição de animação
Agora, aconselho a abrir um projeto de
demonstração para o
nosso aplicativo iOS , pois ele contém todo o código e configurações necessários.
Download de animações
Dado que a API REST para recebimento de dados já está pronta, é hora de introduzir o protocolo do provedor de dados e adicionar sua implementação, que baixa dados do 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 } } }
Essa classe de provedor de dados nos permite baixar animações no formato JSON do servidor mediante solicitação e armazená-las na memória para renderização na interface do usuário. Suponha que sigamos o padrão MVVM - então é fácil usá-lo na entidade
ViewModel
seguinte maneira:
// ... 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
atualiza a propriedade da animação selecionada quando recebe a resposta HTTP correta de um servidor com um objeto JSON não vazio. Esses dados são usados pela camada de apresentação para exibir a animação.
Camada de apresentação
Agora podemos usar o
ViewModel
para acessar os dados da animação e exibi-los na interface do usuário usando o manipulador de ação de toque integrado ao botão:
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() } }
Quando um botão é clicado, a instância LOTAnimationView é atualizada com os dados mais recentes do
ViewModel
.
Aqui está o que parece:
Isso é tudo. Agora, o aplicativo exibe a animação baixada da nossa API REST
(do servidor).
Dicas e Limitações
Truques:
- O AAE suporta a maioria dos tipos de objetos, incluindo imagens raster e vetoriais;
- O Bodymovin permite incorporar todos os recursos no arquivo JSON final usando o Base64 e, graças a isso, você pode evitar o carregamento de recursos separadamente no lado do cliente;
- Você pode desenhar diretamente em um vetor em AAE ou simplesmente importar imagens vetoriais no formato Adobe Illustrator.
Infelizmente, não consegui importar arquivos SVG para o AAE (tentei!).
Você pode aprender mais sobre truques e resolver possíveis problemas neste
interessante artigo do meu colega
Radoslaw Sesiva .
Conclusão
Então, o que o download de animações do servidor nos dá? O benefício mais óbvio dessa abordagem é a capacidade de compartilhar todos os participantes no processo de atualização da animação. Em outras palavras, para lançar uma nova animação interessante, os designers precisam apenas fornecer à equipe do servidor o arquivo JSON apropriado. Para remover a animação no cliente, basta removê-la do servidor. Fácil e rápido.
Também é muito legal que as mesmas funções possam ser implementadas em todas as plataformas suportadas (iOS, Android, Web), sem fazer alterações no protocolo cliente-servidor, código do servidor e arquivos de animação diretamente no cliente.
Isso é tudo. Obrigado pela atenção!
Links úteis