> Nike iOS app install size was 182.2 MB. A week later, it was 322.1 MB
This is besides the point, but is anyone else concerned just how insane those sizes are? There are operating systems smaller than that, why is that needed for a single app from a sports brand? What is this app even supposed to do? How much functionality did they need to cram into it to get a 180MB binary? Why does the app even exist? Why does it apparently need 160MB of just text to do whatever unfathomable job it has?
"Programming went back to the beginning of time. It was a little like the midden out back of his father’s castle. Where the creek had worn that away, ten meters down, there were the crumpled hulks of machines — flying machines, the peasants said — from the great days of Canberra’s original colonial era. But the castle midden was clean and fresh compared to what lay within the Reprise’s local net. There were programs here that had been written five thousand years ago, before Humankind ever left Earth. The wonder of it — the horror of it, Sura said — was that unlike the useless wrecks of Canberra’s past, these programs still worked! And via a million million circuitous threads of inheritance, many of the oldest programs still ran in the bowels of the Qeng Ho system. Take the Traders’ method of timekeeping. The frame corrections were incredibly complex — and down at the very bottom of it was a little program that ran a counter. Second by second, the Qeng Ho counted from the instant that a human had first set foot on Old Earth’s moon. But if you looked at it still more closely … the starting instant was actually about fifteen million seconds later, the 0-second of one of Humankind’s first computer operating systems. So behind all the top-level interfaces was layer under layer of support. Some of that software had been designed for wildly different situations. Every so often, the inconsistencies caused fatal accidents. Despite the romance of spaceflight, the most common accidents were simply caused by ancient, misused programs finally getting their revenge."
The bit I really loved about this passage when I first read it, because it's so clever, is that of course these people with a space-faring culture assume that Unix time was based on the date we first landed on the Moon.
Most of that size is not “functionality”. The size doesn’t come from the program, it comes from the ancillary data files that go along with the program. You can actually see that in the TreeMaps, there are large files like “Zipcodes.sqlite”, “ph-data.json”, “imgCameraOnboarding1@3x.jpg”, “Alipay_icon_square.pdf”, “OnboardingLanding.mp4”, “FindFour.mlmodelc”, and so on.
The next major component is the orange “strings” files like “Localizable.strings”. These are repeated a bunch of times, once for each (human) language that the app supports. If you click on them to zoom in, you will see that there is one called “el.lproj/Localizable.strings”, a “ru.lproj/Localizable.strings”, “pl.lproj/Localizable.strings”, and so on.
Finally there are the blue “text” sections, which is the actual executable code (the name is historical, these sections actually contain binary machine code rather than readable text).
There are no exact counts on the webpage, but I would say that the executable code is around a third of the size of the app, possibly less.
And of course, the whole point of the article is that these apps now have a fourth major component: debugging symbols. These give you the name of every variable and function used in the program, as well as the filenames and line numbers for each instruction in the executable code. These are over 40% of the app size just by themselves. Because these symbol tables are so large, it has been increasingly common to split them out into their own files and only distribute them to your own developers, rather than to every user’s machine.
Swift is awful for app size. Structs carry an absurd amount of overhead, some of which is just plain questionable[0]. At one point even Apple's official docs were urging you to not use structs in Swift, though that has since been removed (probably because of SwiftUI being struct-heavy)
Because swift is a space inefficient language that likes to specialize & copy everything like it's a C++ template, because it's basically C++ templates gone wild under the hood for speed(tm). If you inspect the types swift makes under the hood sometimes, they can get silly huge. Then add codegen for your protobuffer network models and you explain most of the code bloat.
150k lines of objective-c will be significantly smaller than 100k lines of swift pretty much any day of the year.
Look at tweetbot for example, still objective c for the most part, a fairly complicated app, still actively developed and only 30MB.
I used to have an app built for some AWS services (mac, ios). First decision to use some AWS libraries added size to the binary, it grew from 1MB to 70MB, I wrote simple AWS library myself just for my needs and that resulted in the binary of 2-3MB.
Most of those apps use a lot of common libraries that add a lot of size to the binaries.
I'm working on a machine learning project where we're trying to package something up, and bringing in all the packages that get installed by default with the framework we're using adds gigabytes to the size of the application, almost all of which is probably not necessary. The challenge is it's bloat on top of bloat, without an obvious way to pare it down, so it becomes a separate engineering effort to try and make something small and efficient. Under a certain size and for many applications, it's more cost effective just not to worry about it and keep the bloat
I found myself in the same situation a few years ago. We hacked together a dubious version of treeshaking using 'python -v' and got the thing small enough to run on an aws lambda which saved a bunch of money. Fun times.
I'm flatly amazed that sort of thing isn't some kind of bitmap/vector hybrid format. Like a high resolution central logo and then rules for defining the background, like "blue fading to white at the edges".
Android has an interesting solution to this called 9-patch-files [1]. They basically add a 1px-margin around the image. By coloring the margin in different colors, you tell the OS what areas to stretch and what should be kept as-is based on the screen size.
iOS has not required launch images for every size for some time now (since iOS 8 in 2014). It requires instead a piece of UI called a launch storyboard [1], which scales using the standard UI layout system to the different sizes
However custom images can still be set for every possible size, if you really want
They're not. You're likely thinking of indexed color PNGs, but full color depth PNGs are quite large. A JPG/HEIC/AVIF image will be significantly smaller.
Developers want to avoid writing one simple thing, so they add a huge dependency, then never remove the dependency even if they later remove the needed feature. And then they don’t even bother to enable trivial optimizations like dead code stripping because they just don’t care.
Don't just put it on developers. There's the business requiring our team to include Google Analytics, Usabilla and Airship, and they're already asking us to include another random analytics package as well.
This is it. Developers on broadband and tight budgets don't care about app size. On the App Store there's usually no direct correlation between app size and conversion rate: the app will eventually be available anyway.
> Why would the "battletested" be better ? It is "battletested" by the user, anyway.
Your tense is incorrect there. "Battletested" means that past users have experienced the carnage of war, so current users can enjoy peace. Your second usage would need to be changed to present tense, like "battletesting", where you subject them to suffering.
I’m with you on that, but the two are not mutually exclusive. I don’t know how it is exactly in Xcode, but in my field there’s a huge difference between importing a whole kitchen sink named “moment.js” or a few “date-fns” functions.
My guess is it's a mix of an 'NPM mindset' of how to deal with dependencies (e.g. 'the more the merrier'), and then including those dependencies as dylibs/frameworks instead of static linking, which kills any chance of dead code elimination (e.g. it doesn't matter if you only call a single function in a dependency, you still get the whole thing included in the app bundle).
yep, was able cut down an app from 70mb down to 10mb just by stripping out some 3rd party libs, and it turns out that most of the time only 1 or 2 functions were being used in a lot of cases anyways... i see this all the time...
Usually because of dependencies. It's fairly frequent to add tens of megabytes when you pull some SDK or frameworks... Most of those functionalities are of course not needed at all, but unless you design a library with small binary size in mind it's very hard to automatically prune out those dependencies.
I frequently hear statements like that, but I doubt that it is literally true. Just the localization files in this app are easily a third of its size, and back in the Windows 3.1 era nobody could afford to casually install 40 megabytes of strings for languages they could not read. My entire hard drive held just 40 megabytes back then! (Also, Unicode didn’t quite exist yet.)
Incidentally, the TreeMaps provided in this article are really amazing. If every scientific paper provided this level of access to their data, we would be a lot better off.
Absolutely. In fairness, though, Apple should also catch this and either prompt or offer some kind of solution to this for devs that may be unaware of this change. The author seems to have found just this so a little education or notification would go a long way.
If any developer is relying on security by obscurity to protect anything sensitive, they deserve to be accessed better sooner than later.
However there are some practical purposes od obscurity like in games that madd reverse engineering harder (though possible of course), it might become easier in some situations.
I'm pretty sure the SO answer is (partially) wrong. As far as I understand, Bitcode is not architecture agnostic, you can't just take bitcode from a 32bit compilation and turn it into a 64bit executable since there still are a ton of architecture dependent things (like memory alignment) in the bitcode.
Yes, this answer is wrong. LLVM IR is not generic; not only can you not recompile to new architectures, it's not always true that it doesn't care what the original language was. (Since it needs to know the aliasing/memory model rules of the original language, sometimes you need new versions of bitcode to handle new languages.)
It's generic for a little while as long as things don't change too much, but eventually they do.
I am one of the answerers to the SO question mentioned in this thread.
With the end of support for the Apple Watch Series 3 (armv7k abi), I guess it was discontinued by Apple as they no longer needed Bitcode. Is there something I misunderstood?
> I may compile a C code to Bitcode and have LLVM generate a running binary for x86 CPUs in the end. If I save the Bitcode, however, I can later on tell LLVM to also create a running binary for an ARM CPU from that Bitcode, without having to compile anything and without access to the original C code. And the generated ARM code will be as good as if I had compiled to ARM from the very start.
There is some other stuff in the answer that is interesting (eg. that Apple apparently never actually used Bitcode for iOS, despite what they implied)
My guess is that they planned to use Bitcode to do minor optimisations for new generations of their chips, but it turned out to not work in practice, and so they scrapped it.
Isn't machine code also microarchitecture agnostic? I thought that the definition of a microarchitecture was a particular implementation of an ISA that externally conformed to the ISA in the same way as any other microarchitecture.
Mostly, yeah. But microarchitectures do sometimes add new instruction set extensions, like how Intel's Skylake added AVX-512. Bitcode can be re-lowered to the new extended ISA to use these instructions (assuming you don't need to target earlier uarchs). Machine code, not as easily (and I don't think anyone really tries, though I'd be interested to learn if someone does).
Latency of instructions, number of ALUs and FPUs and available special functions differ from micro architecture to micro architecture. This makes the compiler behave differently in instruction selection when you select different micro architectures.
Of course, implementation details are different between microarchitectures - that's the definition, after all.
However, "agnostic" usually means that behavior doesn't vary. Performance is orthogonal to behavior in this case. I definitely don't expect code optimized for Haswell to be as fast on a Broadwell as code optimized for Broadwell, but I do at least expect it to run.
The post's fundamental premise is wrong. LLVM bitcode is not architecture agnostic and never has been. Apple also has used it once, to move from 32 bit to 64 bit on watchOS. That was possible, but only because the armv7k and arm64_32 ABIs were developed together to ensure it would work.
1 - Everyone that follows clang development, knows that Apple's use of LLVM bitcode isn't what regular people get out of https://releases.llvm.org/download.html
2 - "You say, I say", school playground stuff, unless you actually have something to show beyond yes and no words.
Bitcode could never really help with big architecture changes, there's too many #ifdef / #define'd integers and enums that have different values on different platforms, which would cause platform-specific integer values to be embedded hardcoded in the bitcode
I thought the idea of bitcode is that Apple would produce binaries for each kind of supported device (i.e. different CPUs for supported models). Basically the benefit of a fat binary without having to generate one.
Did they give up on this idea? Was it not worth it?
EDIT: ridiculous_fish posted a link with some surmises on this question.
The one publicly known production use of bitcode was that it allowed them to recompile all existing armv7 watchOS apps as arm64_32, which made it so that the first 64-bit apple watch could run existing apps. This required specifically designing arm64_32 (which is arm64 but with 32-bit pointers) to enable this, and isn't really a viable approach for anything other than this specific scenario where they knew that they'd be migrating to a specific new architecture in the future.
Before the first 64-bit watch was announced they were very vague and hand-wavy about what bitcode was for because they had to keep the upcoming products a secret, and sort of implied that it'd be used for things which didn't actually make very much sense.
I think that here Android is a better ecosystem: you distribute your application as a bytecode, and then it's the phone itself to compile it to a real binary when you install it. This allow far greater compatibility with even very old versions of the OS or old applications in newer OS and simplifies the build process.
Working in a company that builds both Android and iOS application I have to say that building iOS apps generates 10x the problems that you have with building Android applications, in terms of CI infrastructure, that means that Android you run gradlew and it works, provided you have the right JVM version installed, with XCode it's always a mess. Also for how it works the ecosystem with Android I'm not forced to upgrade, that means that if a project uses SDK X I can build it forever with that SDK and it will still work even on latest devices, with Apple you have to build with the latest toolchain if you want to execute on newer terminals. That makes Android far more suitable for b2b applications.
While having the joy to manually write JNI wrappers to 90% of Android APIs, and fitting their build into CMake/Gradle scripts, or trying to fit building artifacts into AARs.
It might be relevant, however Google's own documentation and tooling during the last decade is quite clear that one should stay out unless doing games.
While I dislike the way Google has managed the whole Android Java story, the way they have doubled down on a managed environment for computing is great.
Certainly not the first, yet it shows how it can look like when everyone is committed to make it happen, unlike what WinDev did during Longhorn project.
Because to gain some stability about the raw LLVM bitcode they had to maintain their own fork, and most likely decided it wasn't worth the effort any longer.
Somehow people keep missing that Apple's clang and LLVM aren't the same one gets from clang.org.
"*
American: app is way too large. breaks constantly. "
It is good to know that there are ways around the bloat. It does beg: why do app developers release such bloated garbage when it would be easy to address?
Because few companies have insights on how much each branch/change affects the download / installation size. And I can imagine that at a medium-large company, noone is really taking the lead on overreaching topics like this.
This neglects to address WHY bitcode was removed. Wasn't this supposed to be a big deal, and required of all app submissions only a couple of years ago? I thought it was to facilitate the porting of applications to whatever architecture Apple saw fit to deploy.
Despite the release notes claiming it'll be removed in the future, trying to build with bitcode enabled is already a hard error in some cases with Xcode 14. Similarly the app store doesn't strip bitcode from things uploaded to it; it instead just tells you to rebuild with bitcode disabled.
Symbols not stripped? That could be fun... is there a simple way of downloading unencrypted ipas from the app store without access to a jailbroken phone?
Because no one cares. It's all about getting it out there asap. All kinds of libraries get included for 1 simple function and this bloats the size of the app. Blindness has set in. It used to be that an exe was 5MB. Now it's 150MB because it has a browser with it.
Why would they care? Whether an app is 100mb or 500mb has zero financial repercussions for them. (In a consumer-friendly world they would care, and we want them to care, but as is, they have no reason to care)
There's one major reason to care - the AppStore has a threshold (200MB i think) over which it will warn users about the app's size if they are on cellular connection (IIRC it used to block downloads entirely). So there's a fair bit of incentive to stay under 200MB.
If they're on mobile. But then we are talking about people with $1000 phones, who almost certainly have tens-of-gigs-if-not-unlimited data plans anyway, so companies still don't care.
I am always a few years behind on smart phone models, so I don't have that much storage space. Every few months I go through my app list sort by largest size and delete the top few apps which are not necessary for me. So it definitely has financial repercussions for them. Smaller apps stay on my phone longer and have a higher chance to be used again and bring them more ad revenue..
Does app size matter for install rates? I suspect not on high end mobile but this accident should give some data towards this.
Will throw a spanner into the 'we can't release that feature as it will increase app size' thinking that I've witnessed in my mobile dev career. I've never seen it actually impact metrics that much.
I'm not sure it affects install rates - but I know when I've been cleaning up my phone the apps that seem to occupy orders of magnitude more than their function would suggest, get culled first.
Makes me feel old. I'm sure 20 years ago I could have told you say what app/game had been installed from floppies and which was "CD ROM only"
My phone apps? Couldn't even guess as to their storage requirements.
Probably a good thing that storage is so plentiful we normally don't care - but cynic in me thinks that a company selling storage with a massive markup, maybe doesn't have aligned interests.
If 0.1% of people install an app, and it consumes a gig rather than 500Meg - and we sell millions of phones. That does turn into a real money pretty fast.
There are A LOT of people who ran out of space on their phones and can't install anything anymore. So if your app is 500MB, they'll first have to find 500MB worth of stuff to delete.
If they really want your app, they'll look through the storage settings on their phone, and start deleting their biggest apps.
So if your app is too big, many people won't even install it, and if they do, it'll be the first app to go if they need more space.
I just moved from android to apple and the IOS apps are 2x - 5X larger
It's really a disgusting tax and I install a lot less apps as a result.
They could easily fix this by adding intelligence in the App store, to serve up the binary for my device's architecture, but no, I have to get the universal bloated binary pig.
Example: You're about to pay your bill at a restaurant. The server tells you that they have an app that will get you a discount/loyalty points. Your cell has a 4G connection. On android, the download size is 20-50MB. No problem. On IOS, the download size is 40-240MB. Problem!
Yes it matters. My current scenario right now is our internet is down. The fastest way to reach ISP support is through Twitter DM. Twitter is not an option since their app is way over 300MB. So I download Tweetbot for only ~20MB.
I am also an Android dev and maintaining APK size has always been part of the dev process from the start. Apple is just so bad in policing their IPA size. And it is getting worse.
The problem isn't the speed, it's the ridiculous bandwidth caps imposed by ISPs. Here in Canada a fairly simple 10GB data plan runs about $75/month, if a restaurant is offering me a discount and requires their 250MB app to get it, that discount has effectively cost me $2.
Yeah, I haven't considered data caps, as here in Hungary, unlimited data is around 27eur/mo, but even capped is not that expensive (just an example: 10GB is 10eur, 50gb is 20 eur)
I have a really hard time calling those plans "unlimited" when it becomes unusably slow after your full-speed allotment. I hope the waiter told you about their app discount before you ordered, because best-case scenario that 250MB app is going to take a little over an hour to download at the 512kbps they allow.
There's a 200 MB size threshold where users on cellular connections get prompted if they're sure they want to download it, so if this pushes an app over 200 MB I would assume yes some users will bounce off of that.
And in some places 200 MB can still be a big deal, the whole world isn't on 20 GB data plans.
200MB for a 3d game with a bunch of assests... sure... but somehow there are more and more >200MB apps, that are basically a packed webapp that should be below 10MB.
It used to matter in the past, but it seems like these days the effect is not very significant...
Last year we ran a test which involved artificially bloating one of our IPAs from 160mb to 260mb* and compared the app performance metrics* before and after the change, we saw no meaningful difference between the two versions.
By using the app thinning mechanism, you can create a different IPA sizes for different devices.
High end or low end it doesn't matter. Poorly engineered is poorly engineered regardless. High end phones with lots of storage can (for now) get away with running apps that take up 2x more space than they need to. For an analogous problem try running poorly coded apps on old hardware, looking at you MS teams or zoom.
Well hold on. That seems to be begging the question. If a whole feature can be replaced by a web view (and the site is already there), is an app actually required?
Larger apps lead to more cycling behavior. Remove X and Y, install Z, then later remove Z to install something else. Biggest app that doesn't need to be installed at the moment gets removed first.
I guess the main problem is that it's most often a boiling frog problem, not a drastic change like in this case. Users may put up with long install times because they've slowly getting used to it, and usually they also can't judge whether the install size is actually justified for the features the app offers (and I have the impression that most devs also don't have much of a clue or even care).
This is besides the point, but is anyone else concerned just how insane those sizes are? There are operating systems smaller than that, why is that needed for a single app from a sports brand? What is this app even supposed to do? How much functionality did they need to cram into it to get a 180MB binary? Why does the app even exist? Why does it apparently need 160MB of just text to do whatever unfathomable job it has?