class: title, smokescreen, shelf, no-footer background-image: url(/assets/images/presentations/xamarin-android-apps-are-not-fat/sumo-wrestler.jpg) # Breaking news! ### Xamarin Android applications are not fat! --- # Xamarin ecosystem .NET is a developer platform made up of tools, programming languages, and libraries for building many different types of applications. Xamarin extends the .NET developer platform with tools and libraries specifically for building apps for Android, iOS, tvOS, watchOS, macOS, and Windows. There are two approaches to Android development with Xamarin: - Xamarin.Android - Xamarin.Forms --- # Demystifying an urban legend Xamarin is an additional layer on top of Android, a native application will always be lighter than a Xamarin one. Fortunately, the "cost" of Xamarin in terms of weight is **far from being 20-25MB**. A few key points here: - Xamarin.Android and Xamarin.Forms do not have the same impact - Both still rely on native Android tooling for weight management of the native side of things - Xamarin also has its own tooling for the .NET side of things - Developers often have little knowledge of this tooling --- # Smaller is better Because not everyone has the best internet connection, if your app is too big, some users will cancel installation. Furthermore, if their device has no more space, they will uninstall apps that takes the most space. **As a developer, I want my app to be installed on the users phone and stay there.** Having smaller apps have many benefits: - Download and install faster - Starts faster - Uses less memory and power - Have a better chance not to be uninstalled --- class: compact name: apk-analyzer # Apk Analyzer In order to understand why a specific application is big we need to analyze it with Apk Analyzer. ![apkanalyzer](/assets/images/presentations/xamarin-android-apps-are-not-fat/apk-analyzer.png# maxw-90pct center) --- class: img-right-full, no-footer # Where to look ![Yosemite](/assets/images/presentations/xamarin-android-apps-are-not-fat/apk-analyzer.png) There are four main areas that contribute to our large APK size: - **res** – All the files under your Resources folder. -- - **assemblies** – All of the assemblies required for your application. -- - **lib** – Native libraries for the respective ABIs that your application supports. -- - **classes.dex** – App's byte code that is executed by DVM or ART. --- class: title, fogscreen, no-footer background-image: url(/assets/images/presentations/xamarin-android-apps-are-not-fat/diet.jpg) # Let's start the diet --- class: roomy col-2 # Resources Resources are usually the first place to look. As a developer, it is very easy to add images that are not well suited for mobile apps. - **Remove** unused resources - **Resize and optimise** resources - Convert images to **WebP** - Use **vector assets** - Do not use **embedded images** ??? - Locating unused assets is very important : fonts, images, etc... - Optimising images to reduce their size : exemple with pixelmator and a command line script - Using webp to further compress images - Show how to covert a SVG to Android Vector assets ** DEMO TIME ** --- class: roomy # Resize and convert images Resize images ``` convert -resize 50% myfigure.png myfigure.jpg ``` Convert to webp ``` cwebp -q 80 image.png -o image.webp ``` --- class: roomy img-right # Vector assets ![](/assets/images/presentations/xamarin-android-apps-are-not-fat/android-asset-studio.png# maxw-100pct center) You can convert SVG to Android Vector assets with Android Studio. --- class: roomy # Dependencies Adding Nuget packages is really easy. But those packages might reference other packages and so on. A quick review on the packages used is always really helpful. - **Remove** unused Nuget packages - Try to be as native as possible - Assess whether you really need each library - Check for multiple packages that achieve **the same purpose** - Check if you have referenced a library for just a simple helper class or two ??? - Indirect references are important to check as they bring lot of mostly non forseen dependencies. - Native library tend to be smaller - Glide and Picasso are good exemples of same feature packages - Sometimes it's just easier to rewrite the code that to bring a whole bunch of assemblies --- class: col-2 # Use the Linker The Mono linker employs static analysis to determine code that is actually used by the app. It removes assemblies, classes, methods or even members found not used. > Three One options are available : - Don't link - Link SDK assemblies only - Link all assemblies ![](/assets/images/presentations/xamarin-android-apps-are-not-fat/linker-options.png# mw-90 center) ??? We should only ever use Link all assemblies but be careful with Reflection. That also why limiting the usage of reflection in your apps will help. --- class: compact # Configuring the Linker Sometimes the linker might remove too much code. You can use some the `PreserveAttribute` on your code to prevent the linker to remove it : ```csharp [Android.Runtime.Preserve (AllMembers = true)] class Example { // Compiler provides default constructor... } ``` Additionnally, you can skip entires assemblies by modifying the csproj : ```xml
Assembly1;Assembly2
``` ??? Actually any attribute named Preserve does the job. I do not recommand skipping complete assemblies with linksip, better use the linker description file. --- class: compact # Configuring the Linker You can provide an xml configuration file to control what is removed and what is kept. ```xml
``` --- class: roomy col-2 # Native tooling d8 is a new dex compiler that helps getting about ~15% reduction in dex files. r8 is the replacement for proguard and keeps backward compatibility with proguard configuration files. ![](/assets/images/presentations/xamarin-android-apps-are-not-fat/d8-r8.png# max-50pct center) --- class: compact # Proguard configuration Adding a configuration is done by setting the ProguardConfiguration build action. ```xml
``` Proguard configurations should be as precise as possible. ``` -keepattributes *Annotation* -keep class android.support.design.internal.BaselineLayout -keep class android.support.design.widget.Snackbar$SnackbarLayout -keep class android.support.design.widget.AppBarLayout$Behavior -dontwarn android.support.design.** ``` --- class: compact # Android App Bundles ![](/assets/images/presentations/xamarin-android-apps-are-not-fat/d8-r8.png# w-33pct db fr ml-4) App Bundle is a special packaging format for Android apps. From a bundle, the stores (Google Play/App Gallery) will generate specific versions of your app tailored to the user device. They use different dimensions for that: - Screen size / Pixel density - Languages - ABI *This resulted in a ~40% download size saving for our users.* --- class: compact # Android App Bundles Universal apk ``` bundletool build-apks --bundle=/MyApp/my_app.aab --output=/MyApp/my_app.apks --mode=universal --ks=/MyApp/keystore.jks --ks-pass=file:/MyApp/keystore.pwd --ks-key-alias=MyKeyAlias --key-pass=file:/MyApp/key.pwd ``` Generate apk for device ``` bundletool build-apks --connected-device --bundle=/MyApp/my_app.aab --output=/MyApp/my_app.apks ``` --- class: roomy # Best practices While compressing images can be done anytime, it is much easier to handle app size since the beginning of the app's development. - Vector assets needs to be designed - Linker and proguard configurations are much easier to handle as the app grows than just before release - Permanent care need to be given to app dependencies - Test release builds regularly --- class: roomy # Slides .qrcode.db.fr.w-40pct.ml-4[] Slides are available on my blog. Scan the QrCode for direct access. Contact: @johnthiriet - [Twitter](https://twitter.com/JohnThiriet) - [LinkedIn](https://linkedin.com/in/JohnThiriet)