Поделиться через


Компоновка приложений Xamarin.iOS

При сборке приложения Visual Studio для Mac и Visual Studio вызывают инструмент mtouch, который содержит компоновщик для управляемого кода. Он позволяет удалить из библиотек классов функции, которые не применяются в текущем приложении. Это нужно, чтобы уменьшить размер приложения, то есть предоставлять пользователю только необходимые возможности.

Чтобы определить, какие пути кода будет применять ваше приложение, компоновщик использует статический анализ. Это довольно громоздкий анализ, для которого нужно проверить все детали каждой сборки и убедиться, что не будет удалено что-то нужное. Для сборок симулятора такая возможность отключена по умолчанию, чтобы ускорить время сборки в период отладки. Но при помощи этой функции создаются приложения меньшего размера. Таким образом ускоряется компиляция AOT и передача на устройства. Поэтому компоновщик по умолчанию включен для всех сборок устройства (выпуска).

Компоновщик является статическим инструментом и не может отслеживать типы и методы включения, которые вызываются через отражение или создаются динамически. Есть несколько способов для обхода этого ограничения.

Поведение компоновщика

Вы можете изменить поведение компоновщика в специальном раскрывающемся списке в разделе Параметры проекта. Чтобы получить доступ к этому дважды щелкните проект iOS и перейдите к параметрам компоновщика сборки > iOS, как показано ниже:

Linker Options

Далее описаны три основных значения для этого параметра.

Отключив компоновку, вы сохраните все сборки проекта в неизменном виде. Чтобы повысить производительность, это значение по умолчанию применяется, когда в интегрированной среде разработки выполняется сборка для симулятора iOS. Для сборок устройства этот вариант можно использовать только как временное решение, если ошибка компоновщика не позволяет создать пригодное к выполнению приложение. Если приложение работает только в режиме сборки -nolink, обязательно отправьте отчет об ошибке.

Этот вариант соответствует параметру -nolink при запуске средства mtouch из командной строки.

В этом режиме компоновщик сохранит ваши сборки без изменений, но постарается уменьшить размер сборок для пакета SDK (т. е. компонентов из комплекта поставки Xamarin.iOS), удалив из них все элементы, которые не используются приложением. Это параметр по умолчанию применяется, когда в интегрированной среде разработки выполняется сборка для устройств iOS.

Это самый простой вариант, и он не требует изменений в коде. Но он отличается от полной компоновки тем, что некоторые виды оптимизации в этом режиме недоступны. Таким образом, это компромиссный вариант, который позволяет получить приемлемый размер приложения без длительной полной компоновки.

Этот вариант соответствует параметру -linksdk при запуске средства mtouch из командной строки.

При полной компоновке компоновщик сможет использовать все известные ему возможности оптимизации, чтобы создать файл приложения минимального размера. В таком режиме он будет изменять пользовательский код. Это может привести к проблемам в тех ситуациях, когда при статическом анализе неправильно оцениваются примененные в коде компоненты или алгоритмы. В некоторых случаях, например при использовании веб-служб, отражений и сериализации, для правильной работы компоновки в приложение нужно внести небольшие изменения.

Этот вариант соответствует параметру -linkall при запуске средства mtouch из командной строки.

Управление поведением компоновщика

Если вы используете компоновщик, иногда он может удалять код, вызываемый динамически или неявно. Чтобы предотвратить это, для компоновщика предусмотрено несколько функций и параметров, которые управляют его поведением.

Сохранение кода

Когда вы используете компоновщик, иногда он может удалять код, вызванный динамически через System.Reflection.MemberInfo.Invoke или путем экспорта методов в Objective-C с использованием атрибута [Export] и вызова селектора вручную.

В таких случаях вы можете указать компоновщику, что весь класс или отдельные его члены нужно сохранять при компоновке, установив атрибут [Xamarin.iOS.Foundation.Preserve] на уровне класса или на уровне членов. Все члены, которые не имеют статических ссылок из приложения, подлежат удалению. Таким образом, этот атрибут позволяет отметить нужные приложению члены, на которые нет статических ссылок.

Например, если вы динамически создаете экземпляры типов, для них нужно сохранять в коде конструктор по умолчанию. Если используется XML-сериализация, нужно сохранять свойства типов.

Этот атрибут можно применить для любого члена типа или для типа в целом. Чтобы сохранить весь тип, можно применить для него синтаксис [Preserve (AllMembers = true)].

Иногда нужно сохранять определенные члены при условии, что содержащий их тип уже сохранен. В таких случаях следует использовать [Preserve (Conditional=true)].

Чтобы устранить зависимости от библиотек Xamarin, например, при разработке межплатформенной переносимой библиотеки классов (PCL), вы также можете использовать этот атрибут.

Для этого достаточно объявить класс PreserveAttribute и использовать его в коде следующим образом:

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

Не имеет особого значения, в каком пространстве имен он определяется, так как компоновщик ищет этот атрибут по имени типа.

Пропуск сборок

Вы можете указать сборки, которые следует исключить из процесса компоновки, сохранив обычный режим для компоновки всех остальных сборок. Это полезно в тех случаях, когда для некоторых сборок невозможно применить [Preserve] (например, это код сторонних производителей) или в качестве временного решения в случае ошибки.

Этот вариант соответствует параметру --linkskip при запуске средства mtouch из командной строки.

Если вы используете вариант Компоновать все сборки и хотите, чтобы компоновщик полностью пропустил некоторые сборки, поместите следующий код в параметр Дополнительные аргументы mtouch для сборки верхнего уровня:

--linkskip=NameOfAssemblyToSkipWithoutFileExtension

Чтобы пропустить несколько сборок, включите сюда несколько аргументов linkskip:

--linkskip=NameOfFirstAssembly --linkskip=NameOfSecondAssembly

Для этого параметра нет пользовательского интерфейса. Но его можно указать в диалоговом окне параметров проекта в Visual Studio для Mac или на панели свойств проекта в Visual Studio, используя специальное текстовое поле Дополнительные аргументы mtouch. (Например, --linkskip=mscorlib не будет связывать mscorlib.dll, но будет связывать другие сборки в решении).

Компоновщик удаляет код, использование которого на устройствах крайне маловероятно, например код, который не поддерживается или не разрешен. В редких случаях приложение или библиотека могут зависеть от этого кода (даже если он не работает). Начиная с версии Xamarin.iOS 5.0.1 вы можете отключить эту оптимизацию компоновщика.

Этот вариант соответствует параметру -nolinkaway при запуске средства mtouch из командной строки.

Для этого параметра нет пользовательского интерфейса. Но его можно указать в диалоговом окне параметров проекта в Visual Studio для Mac или на панели свойств проекта в Visual Studio, используя специальное текстовое поле Дополнительные аргументы mtouch. (Например , --nolinkaway не удалит дополнительный код (около 100 кб)).

Добавление отметки о безопасности сборки для компоновщика

Пользователь может применить компоновку только к сборкам пакета SDK, исключив из оптимизации пользовательский код. Но это означает также, что из компоновки будут исключены и все библиотеки сторонних производителей, которые не являются частью SDK Xamarin.

Это распространенная ситуация, так как разработчики не любят вручную добавлять атрибуты [Preserve] в свой код. В такой ситуации компоновка не будет применяться для библиотек сторонних производителей. Это неплохой вариант по умолчанию, так как нет надежных методов проверки готовности сторонней библиотеки к обработке компоновщиком.

Чтобы разрешить компоновку для определенной сборки, которую вы включили в проект или разрабатываете для многократного использования, достаточно добавить в нее атрибут уровня сборки LinkerSafe, вот так:

[assembly:LinkerSafe]

Чтобы использовать этот механизм, не обязательно создавать в этой библиотеке ссылки на библиотеки Xamarin. Например, когда вы создаете переносимую библиотеку классов, которая будет работать на других платформах, вы также можете применить атрибут LinkerSafe. Компоновщик Xamarin проверяет атрибут LinkerSafe по имени, а не по фактическом типу. Это означает, что даже такой код будет работать правильно:

[assembly:LinkerSafe]
// ... assembly attribute should be at top, before source
class LinkerSafeAttribute : System.Attribute {}

Пользовательская конфигурация компоновщика

Выполните инструкции по созданию файла конфигурации компоновщика.