Building your own Cache for Lottie Files in iOS

Aitor Pagán
Inside_Wallapop
Published in
7 min readJun 1, 2021

What is it?

Lottie is a tool used worldwide to build custom animations and transitions for all kinds of platforms.

Since it works with vectors, the size and interpretation of the different animations consume very few resources on your devices, so it becomes an excellent option to engage users and gives a better user experience.

We are not going to expand on what is Lottie about since its documentation is very extensive. If you’d like to know more about Lottie we encourage you to visit their official page.

This post is about what we needed to customize from Lottie to improve the user experience and device resources. But first let’s introduce you to the reasons we had for using Lottie.

Animation Example

What advantages does it give to the team?

As a sort of big iOS team, we like to experiment with the different SDK’s Apple provides us, like CoreAnimation or Metal Kit. We are also part of a multi-stack software engineering team so we need to find solutions that make our lives easier in every way.

Furthermore, we are part of a product which is trying to build a unique experience that promotes a more conscious and human way of consumption. Our work involves people from many other fields such as Marketing or Design.

Certainly, Lottie allows us to involve most of the team in the user experience and also to have a common tool in the different engineering stacks, helping the development and delivery speed.

What’s the problem?

Let’s put it in a little bit of context.

We’re building a Backend Driven UI.

In one of the fields, we need to have the flexibility to display visual feedback (animating or static) to the user.

– Can you imagine what tool we need? –

We decided to host these resources in a S3 bucket so we won’t need to release a new version of the App every time we add new Lottie animations without updating any of them.

Lottie SDK gives you the chance to load an animation from a URL, so there’s no problem about that.

Long story short, every time you closed the App you needed to download the resource again.

We started by saying that Lottie resources are quite small, but, how does it fit in a Backend-Driven-UI and with a slow network situation?

We decided it would be better to persist with those files instead and re-use them since they were not going to change that often.

How do we control Lottie cache?

Before we dig into implementation details, let’s try to understand how we control and what we control.

Lottie provides an easy way for implementing a custom cache. They’ve declared a protocol for cache provider:

AnimationCacheProvider.swift

Therefore, we would just need to adapt to this interface and pass it to the init of the Animation initializer from URL.

Our decision was to make a Cache provider using the file storage of the application Sandbox. So every time an animation is being requested, Lottie would automatically decode it as an Animation and then call our cache implementation to do whatever we need to do.

Since Animation is already Codable, we could just use the JSONEncoder to encode it to Data and to save it the directory we wanted.

We decided to use the name included in the URL to save the file, so this will be our way of finding if the animation is already cached or not.

Then, when Lottie is reading from Cache, it would just need to check if the animation is already saved in our documents folder. If it finds a match it will decode it from the data with JSONDecoder and set the Animation object to the AnimationView.

quick schema about the implementation
Schema loading an animation

BUT…

We found a little issue with the current Codable implementation of the Animation object. When you convert it back to Data it seems some basic information to display the animation properly is lost, because when you read it back and decode it to Animation some frames had been lost.

We found this issue doing some QA with some animations, so we needed to make some changes in our implementation.

Basically the main change was to get rid of Lottie’s responsibility for making the network call. Then, implement our own network call to save the Data downloaded instead of the Data encoded from the Animation object.

How are we controlling the changes of the animation?

If we need to display any new animation, the only change we need to do is returning a different URL, so the file would be saved with a different name.

What would happen if there were too many downloaded Lottie animations?

We found two possible issues here:

  1. Sandbox is full and we cannot save more files.
    Since our source of truth is the data we’ve downloaded, we are not handling errors when saving the file. Animation will be displayed and downloaded until file system has enough space to save it.
  2. User realizes the App is using a lot of storage.
    We added an option to give the user the opportunity to clean cached files within the Device Settings in the App.

How did we implement it?

So let’s get our hands dirty and write some code.

We assume basic iOS development knowledge, how to import a third party library and how to build a simple application with a ViewController.

First let’s take a look at the Lottie Animation view container:

1. This is where we set the animation to the view. For the sake of simplicity, we just covered the ViewModel as an URL, but you can also have all the info you want to configure the animation properly. We just pass a completion block in order to retrieve the AnimationView and setup whatever is needed and of course, to play the animation, since once you change the animation it won’t start playing until play() function is called.

Now let’s cover the part of the code which decides if we should read it from cache or if we should call the network to download the resource.

/// 1

We cover checking if the animation is already in our cache. If there’s an animation, we just set the animation and finish the execution.
The provider is in charge of decoding data if needed. As we will see later, we’re doing the same thing that Lottie is doing in its implementation of the init from url of the Animation object.

/// 2

We make the request to download the resource. Here you could use your networking implementation, but again, for the sake of simplicity, we used the default shared session.

/// 3

After decoding the animation, if it doesn’t fail, we just save the data in the cache provider. Here is where the main issue using the AnimationCacheProvider protocol happened. This cache provider expects an Animation to save it, so encoding it again to Data was giving the unexpected behavior when decoding it back again.

Lottie AnimationCacheProvider approach.

<<Animation>> –save– <<AnimationCacheProvider>> –encode to data– <<FileManager>><<FileManager>> –decode– <<AnimationCacheProvider>> –get– <<Animation>>

encode to data → it’s where the information was lost.

Our approach.

<<Data>> –save– <<AnimationCacheProvider>> –save– <<FileManager>><<FileManager>> –decode– <<AnimationCacheProvider>> –get– <<Animation>>

Before digging into the last component of our implementation, let’s talk about implementing a AnimationCacheProvider according to the protocol, just for comparison.

Let’s review the code from the Animation loadedFrom function:

/// 1

They check if the animation is already in cache by asking the cache provider using the url. Here we’re following the same path.

/// 2

Here is the main problem. They send the animation object to the cache provider in order for them to save it wherever they want.
Since the default implementation LRUAnimationCache.swift is using a dictionary to save animations, no information is lost when decoding from cache.

So that’s why we needed to create our own implementation of the setImage from a URL, instead of using the one provided by Lottie directly and just provide an implementation of AnimationCacheProvider.

Last thing we need to cover is the provider implementation.

/// 1

We provide the animation if it’s found in the directory. We delegate the work to find the file path to a URL builder.

/// 2

Here, instead of encoding an Animation to Data, we just find the right path to save the file and save that Data. You could also use some kind of encryption but, let’s keep it simple for this post.

/// 3

AnimationCacheProvider protocol uses this function to clear the data. We also covered it to be able to remove all the files saved in our directory.

/// 4

Basically we remove all the paths, schemes and hosts from the URL and get the name of the file with its extension in order to save the file with the desired name. This is what gives us the flexibility to make any correction on the animations provided by just returning a new URL from the endpoint.

And that’s all needed to build a custom cache provider for Lottie.

It helped us to understand better how Lottie is working on the backstage and also to have more control in our users’ experience.

We hope you find it useful and we’re looking forward to your comments and suggestions.

--

--

Aitor Pagán
Inside_Wallapop

iOS Dev. In love with sports and animals. Interested in so many things that really don’t know about anything. https://polenoso.me