
APK Golf: Reducing an Android APK's Size by 99.99% - jbergstroem
https://fractalwrench.co.uk/posts/playing-apk-golf-how-low-can-an-android-app-go/
======
kbenson
This is code golf. I mention that because apparently some people are missing
the point, which is _purely_ to get the smallest size. This isn't _directly_
applicable to most work you might do, but like many exercises that explore the
extremes, useful knowledge can be learned from the attempt.

In a similar vein, there's a classic article on creating a tiny ELF
executable.[1]

1:
[http://www.muppetlabs.com/~breadbox/software/tiny/teensy.htm...](http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html)

~~~
petercooper
Also, building a 1KB Docker container:
[https://blog.quickmediasolutions.com/2017/09/28/a-1-kb-
docke...](https://blog.quickmediasolutions.com/2017/09/28/a-1-kb-docker-
container.html)

~~~
rorosaurus
Also, The Infinitely Profitable Program:
[https://web.archive.org/web/20160304014157/http://peetm.com/...](https://web.archive.org/web/20160304014157/http://peetm.com/blog/?p=55)

------
dheera
1.5 MB for an app that does nothing. 1.5 _million_ bytes for _nothing_. How
inefficient we are these days. I _really_ wish it were as simple as this:

    
    
        $ cat > myapp.aml
        <!doctype android>
        <head><title>My App</title></head>
        <app activity="MainActivity.java"></app>
        ^D
    
        $ cat > MainActivity.java
    
        import android;
    
        class MainActivity extends Activity {
          void main() {
            android.toast("hello world");
          }
        }
        ^D
    
        $ android compile myapp.aml
    
        Could not find a keystore in your home directory. Would you like me to create one for you (y/n): y
        Enter a keystore password: ********
        Confirm password: ********
        Thanks!
        Compiling Java code ... done!
        Zipping it up ... done!
        Signing ... done!
        Byte-aligning ... done!
        Wrote myapp.apk. You're ready to upload to the Play Store!
        $
    

But no. We must over-complicate things. AppCompatActivity, manifestations of
manifests, layers upon layers of gradle BS, keystores, lots of stackoverflow
lookups just to deal with byte aligning, signing, etc. And then Android Studio
updates itself, breaking your entire project's 79+ files that for a blank app.
What has the world come to?

~~~
maxsilver
I totally agree with you. But as an Android developer, I know why we won't get
to this...

What does this app do on phones? On tablets? On laptops? Where is the header
bar (the original has one, yours doesn't). What color is it? What font? What
placement? What about users who don't read English? What about users who's
languages don't fit in ASCII. What about users who's languages aren't read
left-to-right. How should the header bar even be drawn? What about devices
that can't draw the header bar as defined? What about devices that were
invented before header bars even existed? What about devices whos OEMs
fundamentally redefined what 'drawing' even means. MainActivity.java does
what? Is it Java 6? 7? 8?. Which of the 26 'Activity' classes are you
extending from, and how do you know it exists on the device? How do you know
it behaves identically? The .toast method does what? For which phones? On
which API release? How long or short should the Toast display for? Your
keysigning the app? Which method of keysigning are you using (old or new, they
aren't the same). Who's authoritative for the signing (yourself, or Google
Play. Those aren't the same either.)

The sample app, with it's 1.5 million wasted bytes that 'do nothing' handles
those problems. It's easy to say "I saved 5k bytes by dropping RTL" but...
_you dropped all RTL language support_. People use that stuff. The example
steals a pre-made asset from system resources to save space, which is clever
_until system resources you need aren 't there, which happens in the real
world_. AppCompat is heavy, but it isn't bytes-for-nothing. Some poor souls at
Google waste a lot of time making sure developers get a large library of
useful layouts and controls that all mostly-just-work mostly-consistently
across a huge spectrum of devices and API releases.

No one intentionally sits down and builds over-complicated code by choice
(except perhaps Spring). Every layer of the BS here may be annoying and
wasteful, but it attempts to solve a real problem a real person had to deal
with.

I love the simplicity of your example. But I'm not sure I'd want to deal with
the consequences of living in that world.

~~~
userbinator
_The sample app, with it 's 1.5 million wasted bytes that 'do nothing' handles
those problems._

If all apps have to include 1.5MB of code to handle the same set of problems,
then it sounds like the perfect place for that code is in a shared library,
perhaps distributed with the OS.

~~~
pipeep
A large amount of that 1.5 MB of code is to shim around the incompatibilities
between different versions of the shared libraries that ship with Android. The
root of the problem is that not everyone is on the same version of Android.

~~~
userbinator
_The root of the problem is that not everyone is on the same version of
Android._

Alternatively, it seems the root of the problem is that all the different
versions of Android don't have enough commonality for compatibility. I have
apps which were originally written for Win95 and continue to work on Win10.
Microsoft hasn't always made great decisions, particularly recently, but
seeing a single small binary run unchanged over 20+ years of platform
differences is something that IMHO other companies can learn much from.

(I know Android devices, despite mostly being ARM, cover a wider range of
architectures... but isn't that what basing everything on Java was supposed to
solve?)

~~~
dlubarov
I don't really see a difference. Android's API changes are almost always
backwards compatible. There are a few exceptions, like AudioManager.setRouting
(now a no-op), but they're very rare. For the most part, apps built for for
early versions of Android still work fine on modern devices.

The support libraries which the parent referred to are optional utilities.
They're often the most convenient way to implement something like a snackbar
([https://material.io/guidelines/components/snackbars-
toasts.h...](https://material.io/guidelines/components/snackbars-
toasts.html)), but they're by no means required. Just like on the Windows
side, WPF is probably the most convenient way to create a ribbon, but you
could build your own with the old win32 APIs if you wanted to, or just not use
ribbons.

------
fractalwrench
Author here - happy to answer any questions anybody might have.

Also sorry for the shameless plug, but the startup I work for is currently
hiring: [https://www.bugsnag.com/jobs/](https://www.bugsnag.com/jobs/)

~~~
markcerqueira
Are you guys based out of Bath, UK? Visited it this past summer and loved it!
:)

~~~
fractalwrench
Our main HQ is in San Fransisco, but we also have an office in Bath as both
the founders went to university there (as did I). It's a really great city to
see on a good Summer's day - the Roman Baths are well worth a visit.

------
nneonneo
I got slightly nerd-sniped on this and started optimizing (along with a few
others)...we’re under 1K now (922 bytes from 1757 bytes) and still going.
[https://github.com/fractalwrench/ApkGolf/pull/4](https://github.com/fractalwrench/ApkGolf/pull/4)

------
brink
Kinda cool.. though it also seems pointless or hollow of meaning? "Let's make
a package as small as possible while removing everything. Our next feat will
be the world's most empty room."

What's more interesting to me is when the app is extremely small, yet still
does something useful.

~~~
craftyguy
> Our next feat will be the world's most empty room

Actually, this is incredibly hard to do, since it would require creating a
near-perfect vacuum.

~~~
pbhjpbhj
My room is doughnut shaped and resides in the relative space between a
hydrogen atoms proton and electron ... do I win?

~~~
vesinisa
I measured the size of your room and it seems to have collapsed.

------
netsec_burn
Info on further reduction:
[https://github.com/fractalwrench/ApkGolf/issues/2](https://github.com/fractalwrench/ApkGolf/issues/2)

------
saagarjha
I'd like to see how this is done on iOS, since the OS is much pickier about
what it will let you install.

------
warent
So... it's a signed binary manifest file? That's hilarious and fascinating

------
freecodyx
Do 50 push-ups while gradle syncs. touche

------
mike_kamau
Beautiful. Someone should do the same for all the Javascript-framework-driven
web apps clogging the web.

~~~
bdcravens
Given that the app only displays "Hello world" I'm sure an equivalent
Javascript library wouldn't be too difficult.

~~~
jlebrech
<script></script>hello world

------
n-gauge
android:allowBackup="true"

But I may want my app to be installed to the sd storage.

On a separate note: can we not recalc the apk v1 signatures via a javascript
crypto function?

~~~
yjftsjthsd-h
What, is it too big for your internal storage? ;)

------
ggm
If you depend on shared library or external state, then in the zen sense, it
cannot be "whole" in "one"

(sorry)

------
aw4y
removing support library, layouts...please.

~~~
HillaryBriss
yeah, i had the same thought. this post cannot be taken as practical advice.
interesting to see just how much bloat an apk contains though.

~~~
kbenson
What made you think this article was meant to be taken as practical advice?
It's code golf, which has _never_ been about practical advice.

------
theandrewbailey
> Beautiful. Our APK weighs in at approximately 1.5Mb.

WTF? This Hello World app is 1.5 MB, but MS Paint, a program with much richer
functionality, is not even a third of that! I know that MS Paint is ancient,
but if it takes 1.5 MB by default to put text on a screen, multiple levels of
something have failed, especially when it can squeeze down to <100 KB without
too much trouble.

~~~
kogus
I don't necessarily disagree, but MS Paint on my Windows 10 machine weighs in
at 6.5Mb. Notepad++ is just 2.5Mb though. And the Windows Media Player is just
163k.

~~~
drak0n1c
Aren't there also dll dependencies that allow modern Windows apps to be so
small?

~~~
georgemcbay
Yes. The Windows Media Player referenced is a perfect example, since it is
basically just a shell app where all the UI functionality is pulled in from
plugins and all of the codec support is handled through external codec
libraries.

There is definitely a bit of bloat when it comes to Android apps that use the
support libraries, as the OP article mentions, but the benefit you get for
that bloat is worth it if you're writing full featured real-world
applications. (The support libs make it easy to support newer Android features
backward compatibly to very old handsets).

