Xamarin.iOS アプリをリンクするLinking Xamarin.iOS Apps

アプリケーションをビルドするとき、Visual Studio for Mac または Visual Studio は mtouch という名前のツールを呼び出します。このツールには、マネージド コードのリンカーが含まれています。When building your application, Visual Studio for Mac or Visual Studio calls a tool called mtouch that includes a linker for managed code. アプリケーションで利用されない機能をクラス ライブラリから削除するために使用されます。It is used to remove from the class libraries the features that the application is not using. これが目標としているのは、アプリケーションのサイズを小さくし、必要なデータだけで出荷することです。The goal is to reduce the size of the application, which will ship with only the necessary bits.

リンカーではスタティック分析を利用し、アプリケーションが選択するさまざまなコード パスを判断します。The linker uses static analysis to determine the different code paths that your application is susceptible to follow. 検出可能なものが何も削除されないように各アセンブリのあらゆる細部まで分析するため、少し重くなります。It's a bit heavy as it has to go through every detail of each assembly, to make sure that nothing discoverable is removed. デバッグ中のビルド時間を早めるために、シミュレーター ビルドでは既定で有効になっていません。It is not enabled by default on the simulator builds to speed up the build time while debugging. ただし、アプリケーションが小さくなるため、AOT コンパイルとデバイスへのアップロードが速くなります。デバイス (リリース) ビルド ではすべて、既定でリンカーが使用されます。However since it produces smaller applications it can speed up AOT compilation and uploading to the device, all devices (Release) builds are using the linker by default.

リンカーは静的なツールであり、リフレクション経由で呼び出される、あるいは動的にインスタンス化されるインクルードの種類およびメソッドの場合、設定できません。As the linker is a static tool, it can not mark for inclusion types and methods that are called through reflection, or dynamically instantiated. この制約を回避するために、いくつかのオプションが存在します。Several options exists to workaround this limitation.

リンカーの動作Linker Behavior

リンク プロセスは、 [プロジェクト オプション] のリンカーの動作ドロップダウンからカスタマイズできます。The linking process can be customized via the linker behavior dropdown in Project Options. これにアクセスするには、iOS プロジェクトをダブルクリックし、 [iOS ビルド]、[リンカーのオプション] の順に選択します。下の画像をご覧ください。To access this double-click on the iOS project and browse to iOS Build > Linker Options, as illustrated below:

リンカー オプションLinker Options

3 つの主要なオプションは次のとおりです。The three main options are offered are described below:

リンクを無効にすると、アセンブリは変更されません。Disabling linking will make sure that no assemblies are modified. お使いの IDE の対象が iOS シミュレーターのとき、パフォーマンス上の理由から、これが既定の設定となります。For performance reasons this is the default setting when your IDE targets for the iOS simulator. デバイス ビルドの場合、これは、アプリケーションの実行を妨げるバグがリンカーに含まれるときの解決策としてのみ利用してください。For devices builds this should only be used as a workaround whenever the linker contains a bug that prevents your application to run. アプリケーションが -nolink のみで動作する場合、バグ レポートを提出してください。If your application only works with -nolink, please submit a bug report.

これは、コマンドライン ツールの mtouch を使用するときの -nolink オプションに相当します。This corresponds to the -nolink option when using the command-line tool mtouch.

このモードでは、リンカーはアセンブリに変更を加えません。アプリケーションで利用されないものを全部削除することで、SDK アセンブリ (Xamarin.iOS と共に出荷されるものなど) のサイズを減らします。In this mode, the linker will leave your assemblies untouched, and will reduce the size of the SDK assemblies (i.e. what's shipped with Xamarin.iOS) by removing everything that your application doesn't use. これは、お使いの IDE の対象が iOS デバイスのときの既定の設定です。This is the default setting when your IDE targets iOS devices.

これは、コードを変更する必要がなく、最も単純な選択肢です。This is the most simple option, as it does not require any change in your code. すべてをリンクする場合との違いは、このモードではリンカーが最適化のいくつかを実行できないことです。そのため、すべてをリンクするための仕事量と最終的なアプリケーション サイズの折り合いになります。The difference with linking everything is that the linker can not perform a few optimizations in this mode, so it's a trade-off between the work needed to link everything and the final application size.

これは、コマンドライン ツールの mtouch を使用するときの -linksdk オプションに相当します。This correspond to the -linksdk option when using the command-line tool mtouch.

すべてをリンクするとき、リンカーはあらゆる最適化を活用し、アプリケーションを可能な限り小さくします。When linking everything, the linker can use the whole set of its optimizations to make the application as small as possible. ユーザー コードが変更されるので、リンカーのスタティック分析で検出できないようにコードで機能が利用されるときはコードが中断されることがあります。It will modify user code, which may break whenever the code uses features in a way that the linker's static analysis cannot detect. そのような場合、たとえば、Web サービス、リフレクション、シリアル化では、すべてをリンクするために、アプリケーションにいくつかの調整が必要になることがあります。In such cases, e.g. webservices, reflection, or serialization, some adjustements might be required in your application to link everything.

これは、コマンドライン ツールの mtouch を使用するときの -linkall オプションに相当します。This correspond to the -linkall option when using the command-line tool mtouch.

リンカーを制御するControlling the Linker

リンカーを使用すると、動的に、あるいは間接的に呼び出したことがあるコードが削除されることもあります。When you use the linker it will sometimes will remove code that you might have called dynamically, even indirectly. そのような状況に対処するために、アクションを細かく制御するための機能やオプションがいくつかリンカーに用意されています。To cover those cases the linker provides a few features and options to allow you greater control on its actions.

コードの維持Preserving Code

リンカーを使用すると、System.Reflection.MemberInfo.Invoke を使用するか、[Export] 属性を使用してメソッドを Objective-C にエクスポートし、その後セレクターを手動で呼び出すことによって、動的に呼び出した可能性があるコードが削除されることがあります。When you use the linker it can sometimes remove code that you might have called dynamically either using System.Reflection.MemberInfo.Invoke, or by exporting your methods to Objective-C using the [Export] attribute and then invoking the selector manually.

そのような場合、クラスレベルかメンバーレベルで [Xamarin.iOS.Foundation.Preserve] 属性を適用することで、クラス全体を使用するか、個々のメンバーを保持するようにリンカーに指示できます。In those cases, you can instruct the linker to consider either entire classes to be used or individual members to be preserved by applying the [Xamarin.iOS.Foundation.Preserve] attribute either at the class-level or the member-level. アプリケーションで静的にリンクされないメンバーはすべて、削除の対象となります。Every member that is not statically linked by the application is subject to be removed. この属性はそのため、静的に参照されないが、アプリケーションで必要となるメンバーに印を付けるために利用されます。This attribute is hence used to mark members that are not statically referenced, but that are still needed by your application.

たとえば、型を動的にインスタンス化する場合、型の既定のコンストラクターを保存することもできます。For instance, if you instantiate types dynamically, you may want to preserve the default constructor of your types. XML シリアル化を利用する場合、型のプロパティを保持することもできます。If you use XML serialization, you may want to preserve the properties of your types.

この属性は、ある型のすべてのメンバーに適用するか、型自体に適用できます。You can apply this attribute on every member of a type, or on the type itself. 型全体を保持する場合、その型で構文 [Preserve (AllMembers = true)] を利用できます。If you want to preserve the whole type, you can use the syntax [Preserve (AllMembers = true)] on the type.

含まれている型が維持された場合にのみ、特定のメンバーを維持したいことがあります。Sometimes you want to preserve certain members, but only if the containing type was preserved. その場合、[Preserve (Conditional=true)] を使用します。In those cases, use [Preserve (Conditional=true)]

クロス プラットフォームのポータブル クラス ライブラリ (PCL) をビルドするときなど、Xamarin ライブラリへの依存を希望しない場合でもこの属性を使用できます。If you do not want to take a dependency on the Xamarin libraries -for example, say that you are building a cross platform portable class library (PCL) - you can still use this attribute.

これを行うには、PreserveAttribute クラスを宣言し、それをコードで使用します。次のようになります。To do this, you should just declare a PreserveAttribute class, and use it in your code, like this:

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

どの名前空間にこれが定義されるかは問題ではありません。リンカーは型の名前でこの属性を探します。It does not really matter in which namespace this is defined, the linker looks this attribute by type name.

アセンブリをスキップするSkipping Assemblies

リンカー プロセスから除外するアセンブリを指定し、他のアセンブリを通常どおりリンクできます。It is possible to specify assemblies that should be excluded from the linker process, while allowing other assemblies to be linked normally. このような処理は、一部のアセンブリで [Preserve] を利用できない場合に (サードパーティ コードなど)、あるいはバグの一時的な回避策として便利です。This is helpful if using [Preserve] on some assemblies is impossible (e.g. 3rd party code) or as a temporary workaround for a bug.

これは、コマンドライン ツールの mtouch を使用するときの --linkskip オプションに相当します。This correspond to the --linkskip option when using the command-line tool mtouch.

[すべてのアセンブリをリンクする] オプションを使用するとき、アセンブリ全体をスキップするようにリンカーに通知する場合、最上位アセンブリの 追加 mtouch 引数 オプションに次を入れます。When using Link All Assemblies option, if you want to tell the linker to skip entire assemblies, put the following in the Additional mtouch arguments options of your top-level assembly:

--linkskip=NameOfAssemblyToSkipWithoutFileExtension

リンカーに複数のアセンブリをスキップさせる場合、複数の linkskip 引数を含めます。If you want the linker to skip multiple assemblies, you include multiple linkskip arguments:

--linkskip=NameOfFirstAssembly --linkskip=NameOfSecondAssembly

このオプションを使用するユーザー インターフェイスはありませんが、Visual Studio for Mac の [プロジェクト オプション] ダイアログまたは Visual Studio プロジェクトの [プロパティ] ウィンドウの 追加 mtouch 引数 テキスト フィールドに表示できます。There is no user interface to use this option but it can be provided in the Visual Studio for Mac Project Options dialog or the Visual Studio project Properties pane, within the Additional mtouch arguments text field. (例:(E.g. --linkskip=mscorlib は mscorlib.dll をリンクしませんが、ソリューションの他のアセンブリをリンクします)。--linkskip=mscorlib would not link mscorlib.dll but would link other assemblies in the solution).

リンカーは、未対応や禁止されているものなど、デバイスで使用される可能性が非常に少ないコードを削除します。The linker will remove code that is very unlikely to be used on devices, e.g. unsupported or disallowed. まれに、(動作しているかどうかに関係なく) このようなコードにアプリケーションまたはライブラリが依存することもあります。In rare occasion it is possible that an application or library depends on this (working or not) code. Xamarin.iOS 5.0.1 以降、リンカーにこの最適化をスキップするように指示することができます。Since Xamarin.iOS 5.0.1 the linker can be instructed to skip this optimization.

これは、コマンドライン ツールの mtouch を使用するときの -nolinkaway オプションに相当します。This correspond to the -nolinkaway option when using the command-line tool mtouch.

このオプションを使用するユーザー インターフェイスはありませんが、Visual Studio for Mac の [プロジェクト オプション] ダイアログまたは Visual Studio プロジェクトの [プロパティ] ウィンドウの 追加 mtouch 引数 テキスト フィールドに表示できます。There is no user interface to use this option but it can be provided in the Visual Studio for Mac Project Options dialog or the Visual Studio project Properties pane, within Additional mtouch arguments text field. (例:(E.g. --nolinkaway は余分なコード (約 100 kb) を削除しません)。--nolinkaway would not remove the extra code (about 100kb)).

アセンブリをリンカー対応に設定するMarking your Assembly as Linker-ready

ユーザーは SDK アセンブリのリンクだけを選択し、コードにはいかなるリンクも行わないように選択できます。Users can select to just link the SDK assemblies, and not do any linking to their code. つまり、Xamarin のコア SDK に含まれないサードパーティ ライブラリはリンクされないことを意味します。This also means that any third party libraries that are not part of Xamarin's core SDK will not be linked.

これは通常、ユーザーが自分のコードに [Preserve] 属性を手動で追加することを望まない場合に選択されます。This happens typically, because they do not want to manually add [Preserve] attributes to their code. 副作用は、サードパーティ ライブラリがリンクされないということです。サードパーティ ライブラリがリンカーにとって使い勝手がよいかどうかはわからないため、一般的にこれは初期設定として適切です。The side effect is that third party libraries will not be linked, and this in general is a good default, as it is not possible to know whether a third party library is linker friendly or not.

プロジェクトにライブラリがある場合、あるいは再利用可能なライブラリを開発するとき、アセンブリをリンク可能としてリンカーに処理させる場合、必要な作業は次のようにアセンブリレベルの属性 LinkerSafe を追加することだけです。If you have a library in your project, or you are a developer of reusable libraries and you want the linker to treat your assembly as linkable, all you have to do is add the assembly-level attribute LinkerSafe, like this:

[assembly:LinkerSafe]

このためにライブラリが Xamarin ライブラリを参照する必要は実際にはありません。Your library does not actually need to reference the Xamarin libraries for this. たとえば、他のプラットフォームで実行されるポータブル クラス ライブラリをビルドする場合でも LinkerSafe 属性を使用できます。For example, if you are building a Portable Class Library that will run in other platforms you can still use a LinkerSafe attribute. Xamarin リンカーは LinkerSafe 属性を実際の型ではなく、名前で探します。The Xamarin linker looks up the LinkerSafe attribute by name, not by its actual type. つまり、次のように自分でこのコードを記述しても動作します。This means that you can write this code and it will also work:

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

カスタム リンカーの構成Custom Linker Configuration

リンカー構成ファイルを作成する方法に従って操作してください。Follow the instructions for creating a linker configuration file.