Shrinking your Xamarin iOS binary using the mtouch linker

Submitting an app to the App Store can be tricky business – setting up certificates, provisioning profiles, providing all the necessary assets – it can take hours, if not days to finally get your app submitted for review for the first time. Add to this Apple’s 100mb file size limit and you can end up in a world of hurt.

One way of squeezing the size of your app binary is to make use of the linker, which can be set here:

linkerlocation
(iOS Project) > Options > iOS Build

During build time, the mtouch linker will run through every part of your code, stripping out anything that it deems unused, so that your resulting binary is as small as possible. By default, your project’s default setting for  will likely be set to ‘Don’t Link’ for your iPhone Simulator configuration (which means a faster compile time, since the linker doesn’t attempt to strip away unused code), and ‘Link Framework SDKs Only’ for debugging on a device, which means that the linker will only strip unused code from the Xamarin.iOS SDK and leave your code and packages alone.

These settings may be sufficient for your app, but when it comes to publishing to the App Store you might find that your app’s file size is greater than Apple’s 100mb limit, especially if you’re using a lot of embedded media. To help solve this problem you can use the linker to cut down on unused code from all of the packages and assemblies you’ve added to your project, as well as your own code by setting the behaviour to ‘Link All‘. Your compiled binary will be made as lightweight as possible.

Magic, right?

Well, it might not be as easy as all that. Depending on your app, it’s likely that the linker will strip away code that your app actually needs, such as code that your app calls dynamically or indirectly. In these cases, you need to tell the linker to preserve the code that you’re still using.

It comes down to a bit of trial and error – running your app and seeing where it crashes or doesn’t behave predictably, then finding the code that’s no longer executing properly. When you do find the bugs, you can make use of Preserve attributes to make the linker ignore the feature and move on.

Preserving your code

In my latest iOS project, the code I found to be troublesome during linking were the data models I created for using Json.NET parsing. The linker was stripping out the empty constructors, which Json.NET relies on whilst serializing/deserializing Json data.

To overcome this, firstly I created a new PreserveAttribute class so that I could use Preserve attributes in my shared PCL (place this in any namespace you like – the linker looks this attribute by type name):

public sealed class PreserveAttribute : System.Attribute {
    public bool AllMembers;
    public bool Conditional;
}

Then I used thePreserve attribute to tag all of the models that were causing issues:

[Preserve(AllMembers = true)]
public class Route
{
    [JsonProperty("name")]
    public string Name { get; set; }

    [JsonProperty("description")]
    public string Description { get; set; }

    [JsonProperty("distance")]
    public double Distance { get; set; }

    //...
}

Do this wherever there’s code that you don’t wish the linker to remove. You have the option of using [Preserve (AllMembers = true)] for preserving the whole class, or [Preserve (Conditional=true)] to protect specific members within a class.

Preserving assemblies

If you are having problems with the linker taking useful code away from 3rd party packages that you’ve installed, you won’t have the option of setting attributes like above. To protect an assembly from the linker, you can use the mtouch command-line tool. In Xamarin Studio you can add arguments in the iOS Build settings of your project, for example:

Screen Shot 2017-06-10 at 10.06.33

 

Finding the troublesome code can be very tricky and time consuming, so in some cases using the linker might not be the best option for you. If you have large media files embedded in your project such as images or video, you could consider hosting them on a server and then downloading them at run-time instead of bundling them into your package file.

If you’re having problems using the linker, more details are available on the Xamarin website, where there is also details about using the Android linker.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s