Hacker News new | ask | show | jobs
by dfinlay 3280 days ago
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.

2 comments

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

Source code: https://github.com/in4k/rgba_tbc_elevated_source

Explanation: http://www.iquilezles.org/www/material/function2009/function...

You can't programmatically generate the launch image on iOS.
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. ;-)

I think it's instead brilliant that they are giving developers the opportunity to display an image that gives user feedback while the app is loading its binary, executing static constructors, dynamically linking libraries, etc. you are not forbidden to roll out your own splash screen screen, but it will not be as immediate and smooth as the builtin splash screen support.
Use an obscure format with a code execution vulnerability in imagemagick to run the generator.
PNG only, and I think certain types of PNG as well (e.g. you can't use the alpha channel).
iOS most certainly does not use ImageMagick to generate this images.
That wasn't an option before iOS 8, I think.

edit: I'm not entirely sure if it's possible to do something like this using launch screens.

Since iOS 8, you can use storyboards to generate launch images at runtime
They still aren't "full" view controllers, though. I don't think any of the controller callbacks are executed. I would be surprised if custom drawing is possible. This feature mostly seems to let you leverage autolayout and size classes, which is probably enough for most people
Yep, that's basically it. You can't link any code to it. I think it was added just to make your launch screen look as similar as possible to your app's first screen.