Liang Ma | Software Engineer, App Foundations
We all know app size (download size and local install size) matters, and there is a correlation between app size and customer engagement. Many times, people make decisions about using software based on size, and even pay for bandwidth by the megabyte. Not to mention, uninstall rates could go up when app size increases and causes users to try to free up disk spaces on their devices.
Recently, we shipped an improvement in the Pinterest iOS app v9.1, which significantly reduced its size:
As a result, we’re seeing increased app installs (users download apps from the app store) on new versions since the rollout.
What’s the issue
To create our localization files, we have a CI job that auto-scans all source code in the app (via bazel query) and sends them to Mojito for translation. This worked well until we added several extensions.
Each extension is a module with its own BUILD file. After Bazel was built, it would copy the localized strings from the main app bundle to each extension bundle. However, this would make copies of the Localizable.strings file in each extension, thus inflating the overall app bundle size.
So we decided to eliminate localization copies from extensions.
First, we updated the BUILD file so extensions no longer copy localized strings from the main app bundle.
With this change, however, NSLocalizedString can’t properly load the localized string. After further investigation, we learned that these macros both use +[NSBundle mainBundle], but +[NSBundle mainBundle] actually returns the bundle containing the “current application executable”, which is a subfolder of your app when called from within an extension. For example: it is `/path/to/Pinterest.app/PlugIns/SiriExtension.appex/` instead of `/path/to/Pinterest.app/`. We made a change to set the desired path so NSLocalizedStringWithDefaultValue can read the localized strings from the main app bundle.
All of these changes saved — (size of all Localizable.strings) * (count of extensions that have such localizations duplication) — represents about 30% of the total app size.
Long term plan
As a follow-up, we plan to put localization resources into their respective SDK/extension, instead of relying on the app bundle, with the following advantages:
- Each bundle will be self-contained so it doesn’t require the main app bundle to be able to run or test localizations, and it could be bundled into a separate app.
- NSLocalizedString and localization APIs work naturally in the extension’s code.
- We could make the bundles open source.
There are also other potential areas of improvement, such as removing unnecessary localizations for non-consumer-facing code, investigating more size-efficient image format(s), and other compiler level optimizations. Stay tuned for more updates, and visit our careers page if you’re interested in opportunities like this.
 Download Size is the actual size transferred when download from the app store, which will only be displayed if an app is over the Apple determined limit of 200 MB and the user is not on Wi-Fi unless users change the default setting. And it’s compressed, so it’s smaller than the usual Install Size.
 Local Install Size is the actual app size (Settings app->iPhone Storage->Pinterest->App Size) on your phone’s disk. It’s thinned for your phone model, so usually smaller than the Universal size.