How a default behavior change broke Mac App Store Submissions

In Xamarin.Mac 3.2 one of the focuses was improving general application performance. In additional to Ahead of Time complication and the partial static registrar smaller improvements were looked into to speed up launch time performance.

Out of this work it was discovered that unlike Xamarin.iOS, Xamarin.Mac did not default to ever using the static registrar. You can read about the registrars a bit here, but the short version is that they handle exposing C# classes to the objective-c runtime. To grossly simplify — there is the faster to build slower at runtime “dynamic” and a slower to build much faster at runtime “static” option.

This registration is a large part of the average Xamarin.Mac application startup time. Since a majority of user applications never change their build settings, they were missing out of this possible performance gain.

So in 3.2, the default was changed in Release configurations to default to static if the user did not specify an opinion. Testing did not uncover any issues and the change made its way to the Stable channel.

A few users ran into bugs or limitations with the static registrar, which have been filed and will be fixed, but one interaction with another feature surprised me. To understand that, we’ll need a brief diversion to discuss target frameworks and our linker.

There are two supported target framework options “Modern (Mobile)” and “Full (XM 4.5)”, which can be crudely simplified as “BCL without System.Configuration” and “BCL with System.Configuration”.

System.Configuration is a large API surface which exposes a number of features, but the only important one for our purposes today is that it adds significant dynamic behaviors to other assemblies. Use of one property might under the hood reading some configuration file which might load some other assembly. Calculating a linker graphic in such a system, filled with reflection, is very difficult to get completely right.

In Xamarin.Mac Classic linking was allowed in this case and there was no end to the number of user issues / bug reports it caused. Thus, application targeting the Full (XM 4.5) target framework can not enable linking, since it is unsafe.

Ok, back to the main story — the interaction between these two features. The static registrar is a static code generator that generates objective-c code to registrar all types in your applications that the objective-c runtime needs to know about. Since Xamarin.Mac.dll is part of your application, this means we generate code for every single API that has a C# binding.

Some of our bindings are for “deprecated” Apple technologies such as QTKit. However, Apple refuses App Store submissions that reference such deprecated technologies. On Xamarin.iOS and Xamarin.Mac Modern (Mobile) if your Application does not reference those bindings, they are linked away and everything works in Release configuration.

However, Full (XM 4.5) does not have access to the linker but we just enabled the static registrar by default. This interaction broke a number of customers. :(

The short term solution is to add “ — registrar:dynamic” to your Project Options -> Build -> Mac Build -> Additional MMP Arguments” to force the old behavior.

Longer term, work in progress to allow a limited “safe” form of linking to solve this use case.