The smaller your app file size the quicker end users can download it from the App Store. This may not seem like an issue, when your mobile is connected to WiFi, with a fast internet connection, but can be a concern if users typically download your app when on the move. Users may not download your app if they are using Mobile Data and you have a large file. I have mostly focused on Android in this post, as Android has the most significant app size issues.
File Size Comparisons
These comparisons are with a single page Xamarin.Forms application. I do mention a Native Xamarin.Android app and a Native Android app for comparison, just below.
- Default: Standard settings when compiling an app
- AOT: AOT was enabled
- NoDebug: The nodebug option was enabled in the AOT Compiler
- NoWrite: The no-write-symbols option was enabled in the AOT Compiler
- Both: Both AOT Compiler options were enabled
- ProGuard: ProGuard was enabled
- All: Linker settings set to Sdk and User Assemblies
- Sdk: Linker settings set to Sdk Only
The take away from this, is that No AOT, with the Linker set to Sdk And User Assemblies (All), will give you the lowest file size possible, but you miss out on the benefits of increased app start time.
With all options enabled, including AOT and ProGuard, for a single architecture, you get an increase in file size of about ~39%. Please note this percentage increase may go up or down, depending upon your code and resources. A blank Xamarin.Forms app, with AOT enabled, can only get down to 15MB at it’s best. Your app is going to be bigger.
If you don’t enable the other AOT options and ProGuard, but still use AOT, you may be looking at a ~65% increase in file size. The increase is more dramatic with multiple architectures selected.
A single page native Xamarin.Android application, with no AOT, Linking Sdk And User Assemblies, comes in at 5,800KB. With AOT, it jumps to 10,021KB. This is for armeabi-v7a only. No other options were set. A single page native Android application, comes in at a small 1,747KB. There is just no beating native, when you have the Mono overhead.
AOT in Android
If you use AOT in your app, to speed up the start times and performance of your app, you will notice that the file size balloons rapidly.
Android Aot Additional Arguments
Thanks to coming across a bug report, I actually found these interesting arguments you can pass to the AOT compiler, to reduce your binary size further. While I have not seen what happens to a stack trace, in any crash report, I can at least confirm, they do reduce your file size. As a precaution, I would ensure your analytics and logging is well written, to capture as much data as possible, to not rely on the stack trace. As a quick reference, you can add both of these to your Android csproj with the following.
In the resulting AOT, normally full method names are included in the resulting *.so files. You can stop this by passing this attribute.
Debug information may also be coming out in the final AOT binary, hence this option turns it off.
Drop x86 Support
This may not suit your needs, but if you have an app, designed only for mobile phone’s, there are actually hardly any phones out there, with support for x86. The Asus Zenfone 2 is the only one I have seen, and some reports put x86 usage in the 1% range. Dropping support for x86 could drop your package size by a large amount.
Split APK in Android
If you support multiple architectures (ABIs), using the Multiple APK Support, can let you generate a new package for each ABI. Google does caution you on this, but only because you have to support two APKs, there is actually no disadvantage for using two or more APK’s, except the additional overhead of actually having to create them.
To do this, you can check the Generate one package (.apk) per selected ABI. This will create an APK for each architecture you chose to support.
App Thinning in iOS
If you enable Bitcode, this option is on by default, you enable iOS to apply it’s app thinning, when you submit it to the App Store. As such, only the relevant code for each architecture will be sent to the users device, when they download your app.
If you have a lot of high quality images in your app, you can easily compress them, without losing any quality. Go to TinyPng, to compress PNG or JPEG files. I have seen image file size reduction at over 80% on some files, with no quality loss. It won’t help with memory usage, but could shave MB’s off your app package file size. Using SVG instead, is of course another option, if you are just starting to build your app.
ProGuard is normally known as a code obfuscator, meaning that it will try to scramble the method names and code structure if possible, to make it very hard for people to reverse engineer your code. I personally don’t believe in obfuscation, as it only slows them down, it never stops them. But in addition to this, ProGuard also optimizes and minimizes your code, resulting in additional file size reductions.
Xamarin.Forms and Mono, add quite a significant amount of overhead to the file size. AOT, amplifies that even further. Unfortunately not much can be done at this stage, however, with proper management, it is possible to get AOT working, with an acceptable file size, for a Xamarin app.