
Reducing the size of iOS app binaries - tambourine_man
https://blog.halide.cam/one-weird-trick-to-lose-size-c0a4013de331
======
dfinlay
Circa 2014(15?), I spent a couple of weeks working on reducing a Universal iOS
App's(Trapster) payload size. This was before Asset Catelogs, so everything
was in a fat binary. We converted the audio to be monoaural. We did PNG-crush.
Gzipped embedded dynamic data that was preloaded. Optimized SVGs. All the
hoops, they were jumped through. It only reduced binary size from 60Mb to
50Mb.

Taking another look at the payload showed that the otherwise innocuous launch
images were 32ish Mb in size. The background of the images wasn't a solid
colour. The background pattern was more of grayscale static similar to an
unwatchable terrestrial TV feed. It was intended to resemble the initial sound
of a CB radio used by truckers. (The "Chshhh" in "Chshhh 10-4 Good Buddy")

Since "staticy" audio/imagery like that is inherently random, each launch
image(1 per device resolution) was composed of primarily uncompressable data.
Switching out of the "staticy" background for a plain gray reduced the payload
size to ~20M, a savings of ~30Mb. That change took approximately an hour.

The takeaway here is to take a good inventory of the payload before tackling
size reduction. Otherwise you end up fighting the hard fight just to be
pennywise

Also, uncompressable launch images for iPad Retina displays are stupid huge.

~~~
userbinator
_Switching out of the "staticy" background for a plain gray reduced the
payload size to ~20M, a savings of ~30Mb._

I know this might sound somewhat obvious in retrospect, but you could've
retained something similar to the original background _and_ reduced the size
significantly by generating it at runtime --- the code to create a random-
looking background may only be not more than a few dozen bytes, and can be the
same for multiple resolutions.

For more examples of this technique, see demoscene productions --- the
following video was generated by a binary of less than _4096 bytes_ :

[https://www.youtube.com/watch?v=jB0vBmiTr6o](https://www.youtube.com/watch?v=jB0vBmiTr6o)

Source code:
[https://github.com/in4k/rgba_tbc_elevated_source](https://github.com/in4k/rgba_tbc_elevated_source)

Explanation:
[http://www.iquilezles.org/www/material/function2009/function...](http://www.iquilezles.org/www/material/function2009/function2009.pdf)

~~~
richardwhiuk
You can't programmatically generate the launch image on iOS.

~~~
userbinator
I've never worked with iOS but given what I've heard about the extensive
restrictions on what apps can do, I'm not surprised. I guess this is more like
an icon which the OS retrieves from a known place and displays, _before_ the
app even runs?

Then again, like most demosceners, I see "you can't" as a challenge... and
immediately thought of whether exploiting the image format/whatever loads it
to run the necessary code would do the trick. Probably wouldn't please Apple
for sure. ;-)

~~~
adrianN
Use an obscure format with a code execution vulnerability in imagemagick to
run the generator.

~~~
richardwhiuk
PNG only, and I think certain types of PNG as well (e.g. you can't use the
alpha channel).

------
chrismorgan
Reducing the size of _anything_ : websites, apps, you name it: just _think_
about it, pay attention to shrinking easily-shrunk things, and avoid including
unnecessary stuff.

Improving the performance of _anything_ : much the same. (Caveats apply, of
course. Sometimes using such-and-such a library can genuinely make things
faster than hand-rolling an equivalent.)

Improving _anything_ : actually _think_ about things. _Care_ about them.

(There are trade-offs with everything, of course. And time is often a major
one. When you see something you want to do but don’t have time for it—“Alas
for the wailing of the gulls!”)

~~~
adrianN
"Actually think about it" is not a very actionable recommendation though. If I
have a big application and I want to make it smaller, it'd be more helpful if
you gave me tips how to find spots where I should focus my attention and some
hints about how to avoid "unnecessary" stuff. Developers don't include things
just because it looks nice in the makefile. Everything solved some problem
when it was included.

~~~
stestagg
“ Developers don't include things just because it looks nice in the makefile”

This is actually surprisingly common, much more so these days with cookie
cutter repositories.

There are large communities of developers who feel better with a large toolkit
of functionality in a build environment, where a typical project may only
benefit from a fraction of the included libraries

My limited experience of iOS dev suggests this is less of a problem Here, but
I’m sure still is a factor

~~~
userbinator
_There are large communities of developers who feel better with a large
toolkit of functionality in a build environment, where a typical project may
only benefit from a fraction of the included libraries_

In my experience, these tend to be the same type of developers who tend to
copy-paste code extensively and not really understand what they're doing. They
may be really good at finding these "cookie cutter" solutions and following
instructions, but when asked to actually explain, they're unable to. This is
particularly problematic for debugging, when you ask one of these developers
about the reason for the way something is written and he doesn't know beyond
the fact that he saw and copied it from somewhere.

------
Jyaif
Not mentioned: their product is incomprehensibly simpler than FB. Besides
having 100 times less features, they probably skipped all the a11n, i18n,
multitasking, etc...

They mention not doing A/B testing and that sort of things because it's "their
philosophy". Obviously for their size it doesn't make sense to spend a week
A/B testing to possibly increase usage by 0.5%, but for FB any change like
this represents millions of USD.

~~~
GuB-42
Still, 400MB is just huge. To put it into perspective, the entire storage of
the Nexus One is 512MB. The current Facebook iOS app is larger than an entire
smartphone OS with the 2011 Facebook app installed.

People don't seem to realize how big a megabyte actually is. Just look at the
size of oldschool games (ex : 8MB for Super Mario 64), or what size coders
manage to archive now (see demoscene 64k/4k intros).

And you might say that it was the past, things are much more complex now, blah
blah blah... Well, it's partially true but modern platforms allow savings that
we couldn't have back then. Realtime vector graphics, better compression
algorithms. And considering the trend towards minimalist graphics as opposed
to real-life images, assets shouldn't exceed a few kilobytes.

Libraries? The OS has plenty of libraries and assets you can use for free,
this should be another size saving compared to the old times. And if you
insist on packing your own libraries, I suspect sizes would be much smaller if
development tools were smart enough to get rid of everything not needed.

Essentially, the real reason apps are so huge nowadays is because we have
enough storage space to be lazy.

~~~
bluedino
>> Essentially, the real reason apps are so huge nowadays is because we have
enough storage space to be lazy.

Exactly. In the early days of gaming, if you came up with creative ways to
pack more levels, graphics, or characters into that same 64k of RAM or 2MB of
ROM, you'd likely end up with the more advanced game and sell more copies.
Pushing hardware to it's limits was the pride and joy of programmers back
then.

The barrier to entry is so much lower now. Anyone can create a phone app. All
you need is a Mac and watch some YouTube tutorials, that's why 90% of the App
store is garbage.

In the old days you have to have development kits and licenses and you would
need to have an actual idea/product, expensive hardware to test and develop
on, etc. And I'm really doubting that there were many arcade or console
programmers that weren't "clever". Sure, there were bad games back then but
mostly do to bad design, graphics, horrible movie license tie-ins...

------
Veratyr
Slightly off topic but I wonder if the name is likely to cause issues given
that there's another, possibly older project named Halide in the image
processing software world: [http://halide-lang.org/](http://halide-lang.org/)
(~6 yrs old according to Github commit history).

~~~
dharma1
Also used heavily in mobile photography, by Google and others

------
perilunar
Relevant: The Size of iPhone's Top Apps Has Increased by 1,000% in Four Years

[https://news.ycombinator.com/item?id=14616536](https://news.ycombinator.com/item?id=14616536)

~~~
ship_it
That makes me think if all these stuff happens because of
developers/requirements, or because of Apple/XCode build routine.

------
rtpg
> It’s just our philosophy around products. Knowing too much data warps your
> mind. You find yourself optimizing for a local maximum, instead of making
> big bets that really move the needle.

Talk about a false dichotomy around A/B tests. You can do big things _and_ do
small things.

But I guess a lot of people like having the moral high ground of not following
trends... they could really just say "we don't feel the need for A/B tests".

~~~
1337p337
Not a false dichotomy at all. Ignoring that the size of the team is exactly
two (and there's only so much you can keep in your head), when you have a
metric, you optimize for it. It's not even a conscious process.

------
kartickv
I have to update the screenshots for my iOS app, but it seems that I should
submit a new binary, which in turn pushes it all my users.

I wonder if it would help to have a checkbox "This update is not worth pushing
to already installed devices."

~~~
yoz-y
At some point it was possible to update screenshots without uploading a new
app. Apple changed it because it was abused by apps that uploaded a crappy app
and changed the screenshots after review.

At one wwdc delta updates were mentioned (this would solve this issue) but it
seems that it went to the pile with open source FaceTime.

~~~
saagarjha
Delta updates are for users, not developers. It means that they don't have to
download the full app when updating.

~~~
yoz-y
Well yes. But in this case that is the problem no? As a developer I have to
upload new binary when changing screenshots, thus forcing my users to
redownload a new version. A diff of an identical binary would be zero (or
something very small as at least the build number would have to be updated).
For developers it would be better too but Apple has always privileged user
comfort over developers.

------
goblin89
For some non-obvious on-point tips regarding binary size and (also
importantly) startup speed in complex apps, see ‘Swift with a hundred
engineers’ (2016) where Tuomas Artman shared what Uber engineering’s learned
from their iOS rewrite[0].

Nit: advocating AutoLayout to me doesn’t seem to compute with avoiding
libraries. Is it actually feasible to use AutoLayout in a larger-scale app
without something like Cartography[1]? Interface Builder still feels quite
buggy in this regard.

[0] HN discussion:
[https://news.ycombinator.com/item?id=14207752](https://news.ycombinator.com/item?id=14207752)

[1] [https://github.com/robb/Cartography](https://github.com/robb/Cartography)

~~~
DerekL
> Is it actually feasible to use AutoLayout in a larger-scale app without
> something like Cartography?

You can now do this: addConstraint(button1.rightAnchor.constraint(equalTo:
button2.leftAnchor, constant: -12.0))

I think this is pretty compact and readable as it is. But it's only supported
in iOS 9 and macOS 10.11 (right now, only one version back).

------
manmal
This is a quite opinionated piece, and of course not for everyone. I want 100%
of all crashes reported, so I need Fabric or similar. And I write way better
and more stable code with an RX framework, so I'll use RxSwift or
ReactiveSwift/Cocoa. And since I do have to interface with JSON, I will
include ObjectMapper or similar (until I can have iOS11 as min target). And
sure, I could go by with just NSURLSession, but Alamofire's footprint is not
that big, so I'll add that too. Why should my app be smaller than 20-30MB if
Facebook can get away with 400MB? There will be 1% of users who are delighted
by a small binary footprint, but the rest will not even notice.

BTW there's a totally different story with Android apps that will be installed
in developing countries, by users with cheap devices and low connectivity. In
that case I would scrape every last bit off. On an iPhone I do expect most
users to have a fairly decent connection because you won't get very far
without it.

~~~
danieldk
_Why should my app be smaller than 20-30MB if Facebook can get away with
400MB?_

Facebook can get away with it due to being so central to people's lives. Even
though 32GB is the minimum storage on new iOS devices now, there are still a
lot of people with 16GB iPhones and iPads. Managing storage on these devices
is quite painful, with a lot of apps now taking between 50 and 500MB. When I
still had a 16GB iPhone, I had to remove many applications because I ran out
of space all the time since about a year ago.

We should feel collectively responsible for all this bloat. Sure, we don't
have to fit a full Pascal IDE and compiler on a 1.44MB disk anymore. But it is
certainly good to keep some reference points in mind:

\- Turbo Pascal was a full IDE and was 2.29MB for all the bits. They didn't
use an existing GUI framework either.

\- QNX fit a kernel + graphical environment on a 1.44MB 3.5" disk, with a
network stack and web browser.

213MB for a chat app is outrageous, no matter how you look at it [1].

[1]
[https://itunes.apple.com/us/app/snapchat/id447188370?mt=8](https://itunes.apple.com/us/app/snapchat/id447188370?mt=8)

~~~
pjmlp
> Turbo Pascal was a full IDE and was 2.29MB for all the bits. They didn't use
> an existing GUI framework either.

Forgetting about Turbo Vision? :)

I used to carry MS-DOS 3.3 and Turbo Pascal on a 1.44MB 3.5" disk, back on
those days.

Don't remember if it was TP 3, or if I tailored it to my purposes though.

------
pat2man
As the article points out its mostly a review of
[https://developer.apple.com/library/content/qa/qa1795/_index...](https://developer.apple.com/library/content/qa/qa1795/_index.html)

~~~
pjmlp
Still relevant, as it appears many developers don't pay attention to what
happens at WWDC, IO or BUILD sessions, where these type of advices are
repeated over and over.

------
blinkingled
Does iOS not have incremental app updates? One time big download on Wifi
followed by smaller incremental updates is not a big problem when devices are
starting to have doubled storage capacities and fast transfer speeds.

~~~
ksk
Yeah it kinda sucks that Apple makes you re-download the app essentially. Its
worse for iOS updates though. A full GB just for a point release?! I haven't
use a Mac in a few years, so I'm not sure if its the same on the OSX App
Store. Few years back I was aghast at having to re-download XCode for updates,
plus it was super buggy then. Maybe its changed now.

~~~
otterley
Over-the-air updates have been very small since iOS 9. Last one was about 32MB
or so.

~~~
ksk
Hmm, I use itunes to update. Not sure why I'm forced to download such giant
files if they already have tech for differential updates.

------
jmnicolas
> "Unfortunately, tech CEOs [...] don’t live in areas with shoddy speeds"

Even Linux distro devs don't : Fedora's DNF package manager systematically
downloads a file of 30 MB that (I assume) contains the signature of all
packages to compare it to my local packages. Even if there are no updates, it
still takes 10 min and slows my connection speed.

This boggle my mind, I would have thought from all OS Linux would be the one
to save bandwidth.

~~~
majewsky
On my Arch Linux box, package lists are about 5.8 MiB total. (And yes, those
contain basically a list of package metadata and signatures in the repo.) I'm
going to assume that Fedora carries more packages (do you have rpmfusion
enabled?), so at least the magnitude looks okay.

One thing is worth mentioning here: The package manager _could_ easily save
bandwidth if it didn't download the whole package list and instead queried the
server only for updates for the set of packages that are actually installed
(which is usually an order of magnitude less than what's in the repos).
However, this approach is not feasible for most Linux distributions since they
rely on mirrors to distribute packages, and mirrors only serve static content.

~~~
ramses0
There are several very clever ways around this, with continual rolling updates
in a general fashion with only static files.

Not static per user, but basically giving (source + diff + diff) on a daily /
weekly / monthly basis allows you to only download a diff based on the
frequency which you connect.

Hell, at this point, just git-clone a repo/data structure (potentially with an
initial shallow clone since you may not care about history) and roll forward
"as good as git"

------
adomanico
The points regarding AB tests and analytics simply isn't applicable to most
commercial apps.

Understanding how your features/changes affect key metrics and understanding
how your users are interacting with your app is so crucial when you are trying
to generate revenue.

I would argue Apples analytics are no where near enough to accomplish this.

------
grabcocque
Facebook's app is so bloated because of one thing: Apache Thrift. Last I
checked it came with over 16,000 stubs and serialisers for thousands of
different data types.

------
stereo
Everyone should throw their whole source trees at ImageOptim:

[https://imageoptim.com/mac](https://imageoptim.com/mac)

------
mahyarm
What a luxury to have an app that is only 15kloc. That is why it's small.

If he had a 20kloc objective-c app, how much smaller would of it been ;)

------
ryandrake
Wow, I thought I was going to read an article about optimizing your code for
size, finding ways via assembly to beat your compiler, etc. What's actually in
the article are basic "best practice" things that every developer should be
doing anyway. I'm glad the article exists, but as a mobile developer, if this
stuff is news to you, you might need a wake-up call.

~~~
valuearb
It's a best practice to dump cocoapods?

~~~
ryandrake
I've never measured whether using cocoapods to import dependencies produces
larger or smaller binaries than not using it. I would imagine it makes no
difference, but it's something worth measuring if you are considering using
cocoapods and are worried about binary size.

Personally I don't like cocoapods and if it were my project I would remove it
(and/or not use it in the first place). This is more of a personal preference
though, and not necessarily the right thing for other people's projects.

------
pcgamestime
I do not think so

------
HenryBemis
I am building an app, right now it's about 600MB exploded. My backup, with
reduced image quality (winzip for mac does this), drops to 30MB (git is good
but 3 backups per day on a cloud is better).

I will ask pngcrush out on a date, take it out to a nice restaurant and then
marry it!!

Thank you for the great tips!

------
vladdanilov
The vast majority of people don't care about the app size unless it's blown
out of proportion.

If Apple started to charge for bandwidth transparently at market price, that
would make a lot of difference. But right now if an app is within the Over-
the-Air limit of 100MB, developers don't really care.

Look at Apple's own best practices. No incremental updates, zip compression
when brotli and zstd already there, forcing its own pngcrush which just hurts
compression without any real benefits for loading time and now it's a
mandatory for Asset Catalogs and App Thinning.

~~~
weavie
I disagree. My phone is completely full, every new app I install requires
going through and deciding which apps I need to delete to make space for it.
Large apps get chopped pretty much straight away unless they are exceptional.

~~~
vladdanilov
If the vast majority did care, there would not be a 419 MB Facebook app.

I personally analyzed a number of apps and found image assets can be reduced
by 30-50%. Not only caring, working on the solution.

~~~
pjmlp
People do care, but there is a big difference between Facebook and unknown
developer X.

~~~
vladdanilov
Then why do I get all these ignorance and downvotes by taking action?

