Sign in to follow this  
  • entries
    3
  • comments
    7
  • views
    219

How I halved apk size

Ruslan Sibgatullin

1006 views

1*u_5yDFEpoTD3ST_bn0dgfQ.jpegOriginally posted on Medium

You coded your game so hard for several months (or even years), your artist made a lot of high-quality assets, and the game is finally ready to be launched. Congratulation! You did a great job. Now take a look at the apk size and be prepared to be scared. What is the size — 60, 70 or even 80 megabytes? As it might be sounds strange to hear (in the era of 128GB smartphones) but I have some bad news — the size it too big.

That’s exactly what happened to me after I’ve finished the game Totem Spirits. In this article I want to share several advises about how to reduce the size of a release apk file and yet not lose the quality.

Please, note, that for development I used quite popular game development engine Libgdx, but tips below should be applicable for other frameworks as well. Moreover, my case is about rather simple 2D game with a lot of sprites (i.e. images), so it might be not that useful for large 3D products.

 

 

 

To keep you motivated to read this article further I want to share the final result:

I managed to halve the apk size — from 64MB to 32.36MB.

Memory management

The very first thing that needs to be done properly is a memory management. You should always have only necessary objects loaded into the memory and release resources once they are not in use. This topic requires a lot of details, so I’d rather cover it in a separate article.

Next, I want to analyze the size of current apk file. As for my game I have four different types of game resources:

1. Intro — the resources for intro screen.

1*sC1w5idpfpfhzGSIL9_E8Q.jpeg

Intro background

Loaded before the game starts, disposed immediately after the loading is done. (~0.5MB)

2. In menu resources — used in menu only (location backgrounds, buttons, etc). Loaded during the intro stage and when a player exits a game level. Disposed during “in game resources” loading. (~7.5MB images + ~5.4MB music)

3. In game resources — used on game levels only (objects, game backgrounds, etc.). Loaded during a game level loading, disposed when a player exits the game level. Note, that those resources are not disposed when a player navigates between levels (~4.5MB images + ~10MB music)

4. Common — used in all three above. Loaded during the intro stage, disposed only once the game is closed. This one also includes fonts. (~1.5MB).

The summed size of all resources is ~30MB, so we can conclude that the size of apk is basically the size of all its assets. The code base is only ~3MB. That’s why I want to focus on the assets in the first place (still, the code will be discussed too).

Images optimization

The first thing to do is to make the size of images smaller while not harming the quality. Fortunately, there are plenty services that offer exactly this. I used this one.

This resulted in 18MB reduction already! Compare the two images below:

1*9A23phO-TVVQN11IBzJYhA.png

Not optimized

1*kmzB4p8v9MNSujGpX1gEPg.png

Optimized

the sizes are 312KB and 76KB respectively, so the optimized image is 4 times smaller! But a human eye can’t notice the difference.

Images combination

You should combine the same images programmatically rather than having almost the same images (especially if they are quite big). Consider the following example:

1*vn0LQGYxKlyEv6GWENs18A.jpeg

Before

1*7q6CTo6Gr1z6CWHvkU_f2A.png

After

1*wqQS_j0RgQbpT7QqzHldNw.png

God of Fire

1*GC097jZ5LGWJIyzscAV8bA.png

God of Water

Rather than having four full-size images with different Gods but same background I have only one big background image and four smaller images of Gods that are then combined programmatically into one image. Although, the reduction is not so big (~2MB) for some cases it can make a difference.

Images format

I consider this as my biggest mistake so far. I had several images without transparency saved in PNG format. The JPG version of those images is 6 times more lightweight! Once I transformed all images without transparency into JPG the apk size became 5MB smaller.

Music optimization

At first the music quality was 256 kbps. Then I reduced it to 128 kbps and saved 5MB more. Still think that tracks can be compressed even more. Please, share in comments if you ever used 64 kbps in your games.

Texture Packs

This item might be a bit Libgdx-specific, although I think similar functionality should exist in other engines as well. Texture pack is a way to organize a bunch of images into one big pack. Then, in code you treat each pack as one unit, so it’s quite handy for memory management. But you should combine images wisely. As for my game, at first I had resources packed quite badly. Then, I separated all transparent and non-transparent images and gained about 5MB more.

Dependencies and Optimal code base

Now let’s see the other side of development process — coding. I will not dive into too many details about the code-writing here (since it deserves separate article as well). But still want to share some general rules that I believe could be applied to any project. The most important thing is to reduce the quantity of 3d party dependencies in the project. Do you really need to add Apache Commons if you use only one method from StringUtils? Or gson if you just don’t like the built-in json functionality? Well, you do not. I used Libgdx as a game development engine and quite happy with it. Quite sure that for the next game I’ll use this engine again. Oh, do I need to say that you should have the code to be written the most optimal way? :) Well, I mentioned it.

Although, the most of the tips I’ve shared here can be applied at the late development stage, some of them (especially, optimization of memory management) should be designed right from the very beginning of a project.

Stay tuned for more programming articles!



4 Comments


Recommended Comments

Always interesting to hear experiences! :) I guess the runtime footprint and the APK size are quite interrelated, did you have any problems on devices from runtime memory use which encouraged you to load resources only when required? Or was it more a pre-emptive measure to prevent problems on smaller devices (difficult to test there are so many!)?

Another good trick with the multiple similar images is to do a 'diff' on them, and then instead of saving the whole image each time, just save the difference. If a lot of the values are the same, the diff will be zero and this will compress well.

Share this comment


Link to comment

Hi lawnjelly! Actually, that way to organize resources loading is one of the "best practices" suggested by libgdx devs. So it is more a pre-emptive measure indeed. But I even tested the game on my old Acer Liquid MT (released 7 years ago) and everything works smoothly :) 

The trick about images diff sounds complicated, have you ever used it in a real project? 

Share this comment


Link to comment

All the time, saving the difference between values rather than an absolute value is one of the most fundamental compression methods. I've used in it images, video, audio, animation data, both as part of my own compression, or as a pre-process before applying other compression (like png). And nearly all compression formats you use everyday will use the idea. :)

Share this comment


Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now