Shrinking the app package

No app uses all the features of all the included libraries. The .NET libraries are quite big, and we often only use a tiny subset. To reduce the size of an app, we need to remove any unnecessary code or libraries that exist in it.

How to do it...

To reduce the overall size of the app, we enable the linker. This is used to remove any unused code from our app, or from any assemblies that are used:

  1. We select either the Link SDK assemblies only option or the Link all assemblies option from the Linker behavior dropdown:
    How to do it...

    The linker options

  2. When we link assemblies, types and members are removed. To prevent members from being removed, we can add the [Preserve] attribute to those members:
    public class MyClass {
      [Preserve]
      public string MyMember() {
      }
    }
  3. We can also request that the linker skip all the members on an entire type:
    [Preserve(AllMembers = true)]
    public class MyClass {
    }
  4. If we can't, or don't, want to use the [Preserve] attribute, we can provide a block of code that prevents the linker from removing the referenced members:
    public class MyActivity : Activity {
      static bool falseflag = false;
      static MyActivity() {
        if (falseflag) {
          var ignore = new MyClass();
        }
      }
    }
  5. The last thing we can do to stop the linker, is to specify which assemblies it must not process:
    How to do it...

    Specify which assemblies to skip

  6. Once the linker is enabled for the .NET assemblies, we enable ProGuard to remove the unnecessary Java bytecode:
    How to do it...

    The option to enable ProGuard

How it works...

Most apps contain libraries, or parts of libraries, that aren't being used by the app at all. If the app never connects to the Internet, the entire networking stack is unused and can be removed. As a result of removing the unnecessary code, the final size of the assemblies is much smaller than the initial size. To remove unnecessary code from our app, we use the linker.

Using a linker with Xamarin.Android is essential, as we are including the entire Mono framework and runtime, which is over 40 MB. As Google Play only allows up to a maximum of 50 MB for the app package, we will be severely limited in the amount of extra resources we can add. And, users will not want to download a very simple app if the app has a very large download size.

When we enable the linker, we can reduce the total size of the app package to around 5 MB for simple apps. This is far more desirable, and usually, only extra resources increase the app size.

Note

Enabling the linker is essential for almost all apps, as this significantly reduces the final app size.

There are two ways in which we can enable the linker. We can select the Link SDK assemblies only option, which specifies that the linker should only processes the Xamarin.Android platform and the runtime assemblies. This will reduce the size of only the framework, but will leave any additional assemblies as is.

However, we can rather select the Link all assemblies option, which will try and remove any unused code from all assemblies, including from any referenced libraries. Removing code from referenced assemblies is very useful if we are making use of many, or large, libraries.

When we link assemblies, some types and members will be removed. This sometimes causes problems if we are accessing these types through reflection or serialization. These members are removed as a result of the linker not being able to see where they are being referenced in the code.

Note

The linker may sometimes remove the code that is actually being used. When this happens, steps can be taken to prevent it for occurring.

There are several ways to prevent the linker from removing types and members. One way to do this is by adding the [Preserve] attribute to those members. In the cases where we can't, or don't, want to use the [Preserve] attribute, we can provide a block of code that causes the linker to think that the members are used, but in fact, they aren't used at runtime.

Another way we can prevent the linker from processing certain assemblies, is to specify in the project options the list of assemblies to ignore. This method is very useful if there is an assembly that is being used specifically for serialization, or if there are many types that need to be preserved. However, this results in the entire assembly being skipped, which is mostly unnecessary.

With Xamarin.Android, there are two sets of libraries, the .NET assemblies and the Java libraries. For example, if we create an app that uses the Android Support Libraries, the actual .NET assembly that gets referenced is actually just a wrapper for the underlying Java library. Thus, when we link the .NET assembly, we are only linking a tiny wrapper instead of the large Java library.

As many Xamarin.Android apps make use of many Java libraries, we need a way to link the underlying Java libraries as well. When compiling our app, there is the option to use ProGuard, which is the Java linker and obfuscator.

Note

ProGuard will link only the Java libraries, and is used together with the managed linker, which links only the managed code.

ProGuard is similar to the managed linker, and it will remove the unused Java code. However, it is also an obfuscator. This means that it will also obfuscate and optimize the generated and included Java code.

There's more...

The maximum size for a package published on Google Play is 50 MB. If an app exceeds that size, Google Play will allow extra assets to be delivered through APK Expansion files. Android Expansion Files permit the app to have two additional files, with each being up to 2 GB in size. Google Play will host and distribute these files at no cost.

To use these expansion files, we must install the Android APK Expansion Downloader NuGet. We create a service that inherits from DownloaderService and also implements the IDownloaderClient interface. Although not as simple as this, we connect to the service and start the download.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset