本サイトからスピンオフした姉妹サイトです。複数プラットフォーム向けのライブラリを作れるPCLの概要と利点について解説。Xamarin.iOSやXamarin.Androidでの利用方法や、XamarinでPCLを実現する仕組み、PCLの課題を説明する。今回はPCL(ポータブル・クラス・ライブラリ)について取り上げる。ポータブル・クラス・ライブラリの意義PCLについてはMSDNに詳しい記事があり、あらためてここで説明するようなことでもないが、PCLの「P」とは「portable」であり、日本語にすれば「可搬性がある」「移植性がある」というニュアンスになるだろう。.NETにいくつかのプロファイルが存在することは、第4回でも言及したが、ここで言われている「移植」とは、「.NET技術に準拠する各種プロファイルの2つ以上で利用できること」を示すと考えればよい。CLIおよび類似環境」とでもしておきたい。PCLとして作成されたライブラリは、複数のプラットフォームで使うことができる。同一のコードを使い回せるので、コードのメンテナンスが楽になるかもしれない。使用できるAPIは、全ての対象プラットフォームで使用できるものに限定される。FrameworkのAPIのサブセットであって、特定のプラットフォームでしか利用できない「ポータブルでない」APIは除外される。PCLをどう使いこなすかは、開発者の考え方次第だろう。PCLの主な活用方法としては、アプリケーションにおけるビジネスロジックに含まれる部分をPCLで実装して、クロスプラットフォームで共有する、といった開発手法が挙げられる。.NET開発では、MVVMパターンが主にWPFを対象としたアプリケーション開発モデルとして推奨されているが、Xamarinをターゲットとする場合でもMVVMを適用することは可能であり、実際にMvvmCrossなどのライブラリで適用されている。MVVMにおいては、プラットフォームに依存しないModelおよびViewModelに相当する部分を、PCLに基づいて作成できるだろう(MvvmCrossの使い方については、Microsoft渡辺氏のはてなブログで詳細にまとめられている)。PCLは、複数プラットフォームで共通のAPIを集めているが、単一の最大公約数的なAPIではない。開発者が自分のPCLでどのプラットフォームを対象とするか決定することで、利用できるAPIの範囲が決まる。PCLには「プロファイル」があり、各プロファイルが対象プラットフォームの集合体を規定している。PCLとは何だったのかPCLにおける「プロファイル」は、第4回で言及したものとは幾分か異なる分類のものが含まれている。Frameworkの機能全てを選ぶことも、そのサブセットを選ぶこともある。Profileのような名前を見たことがある人も多いのではないだろうか。Phone、Xbox)である。JavaやQtやWxWidgetの言うような「クロスプラットフォーム」には遠く及ばない。このPCLにおける「クロスプラットフォームを意識したコード」は、例えばUIレイヤーにおいては、しょせん「Silverlightでも動作する」程度の存在でしかなかった。デスクトップの.NETもSilverlightも、UI層のAPIはWPFを基にしており、根本的な違いは無い。WPFはMonoには存在しないため、それらUIの「ポータブルなクラスライブラリ」には、Mono環境への移植性は全くなかった。Mono開発者の視点で言えば、Monoで利用できないコードでは、到底ポータブルとは言えず、PCLの仕組みをサポートする意義は小さかった。そのような状況であったが、2013年後半になってPCLの位置付けはだいぶ変わる。マイクロソフトがPCLのアセンブリをMonoプロジェクトでも利用できるように無償ライセンスで公開したのである。Xamarin.iOSやXamarin.Androidがターゲットとして追加された。Phoneに類似するAPIを備えているが、iOSにもAndroidにも、WPFの基盤はもちろん存在しない。iOSやAndroidを対象とするライブラリは、WPFの機構を前提とするクラスを参照できない。UIが直接関係しない部分でも、WPFのDispatcherTimerクラスなどは存在しない。PCLをXamarinで利用するXamarin.iOSおよびXamarin.Androidでは、PCLアセンブリを参照できるようになっている。詳細に言えば、これらのプラットフォームを対象に含むPCLアセンブリは、同製品から参照できる。Library」というプロジェクト・テンプレートが存在する。このテンプレートで作成されるライブラリのアセンブリは、PCLアセンブリとなり、Xamarin.iOSおよびXamarin.Androidで参照できる。Storeが有効になっている。Silverlightは対象外だ。プロジェクトを作成したら、そのプロパティ・ダイアログのビルド設定で、プロファイルを変更できる(次の画面)。Frameworks]を選択するチェックボックスがあるが、どちらを使用してもよい。このチェックボックスには、Xamarin製品を選択する項目は無い。これらは常に選択されており、オフにする余地はない(!)のである。PCLプロジェクトのアセンブリ参照は、通常のアセンブリ参照とは少し異なる。Subset」という参照アセンブリのグループのようなものが表示される。これを展開すると、現在のプロファイルに含まれるアセンブリを一覧でき、それぞれのアセンブリをダブルクリックすると、その内容を見ることができる(次の画面)。PCLプロジェクトのアセンブリ参照PCLによらないコードの共有PCLはAPIの制約が大きいので、コードの一部のみプラットフォーム固有の実装を作成したい場合もあるかもしれない。使われている方法としては、iOS、Android、その他のプラットフォームで、それぞれ別々のプロジェクトファイルを作成して、ソースファイルを「リンク」で含める、というものがある(次の画面はその例で、リンクファイルには赤枠のようなマークが表示されている)。これは、Xamarin製品がPCLをサポートする以前にMvvmCrossなどのライブラリでも用いられていた、典型的なトリックである。PCLでないプロジェクトの構造この方式だと、作成されるライブラリは全て別々になるので、それらを参照するプロジェクトは、やはりプラットフォーム別に作成する必要がある。PCLは、プラットフォーム間でバイナリレベルのコード共有が行えるので、それを参照するライブラリもPCLにすることができる。PCLを実現する仕組みPCLの「使い方」(「作り方」)については、日本語でもすでにいろいろな解説があるので、これ以上ここで詳しく説明することはしない。その代わりに、ここでは、PCLが特にマイクロソフト以外のフレームワークについて、どのように実現されているのか、その仕組みを説明したい。Frameworkのプロファイルとは全く別のプロファイル(の集合)を規定しており、全く別のアセンブリ集合が、そのプロファイルに関連付けられている。PCLのフレームワーク・アセンブリには、通常のアセンブリとは異なり、実行できるコードが全く含まれていない。具体的には、これらのアセンブリはTypeForwardedToAttributeという属性(System.Runtime.CompilerServices名前空間)の集合体となっている。Frameworkでも使用されていたものである。4.0以降はこれらの属性を伴ってSystem.Xaml.dllに含まれている。4.0ではSystem.Runtime.Serialization.dllファイルに移動している。このTypeForwardedToAttributeの集合体となっているアセンブリを、「ファサード(Façade)アセンブリ」と呼ぶ(「façade」はフランス語だが、英語にすれば「frontend」あるいは「face」のような意味であり、デザインパターンの用語でもある)。C#コンパイラーは、TypeForwardedToAttributeが適用されている型については、型の参照解決時に、その属性が指示するアセンブリを代わりに参照して型を解決する。PCLのファサードに含まれる型には、必ず対象プロファイル上に対応するアセンブリと型があり、アプリケーションの実行時には、その対象プロファイルのアセンブリのコードが実行される。TypeForwardedToAttribute自体は、明示的にアセンブリを指定することはない。代わりにSystem.Typeオブジェクトを引数に取る。このオブジェクトが表す「型」はコンパイル時に解決されなければならず(そうしないとコンパイラーが型解決エラーを起こす)、またアセンブリ生成時に参照先アセンブリ(ポータブルでない)の完全修飾名が埋め込まれることになる。TypeForwardedToAttributeが指定する参照先アセンブリは、実のところ対象プラットフォームによって異なる。4.5と互換のプロファイルについてのみ意味があるものだ。「PCLをサポートする」プラットフォーム全てが、このファサードを用意することになる。Xamarin.iOSおよびXamarin.Androidには、Xamarinがビルドしたファサードアセンブリが含まれている。GUIDを持つ)、そのプロジェクトファイル(.csprojファイル)はMicrosoft.CSharp.targetsファイルではなくMicrosoft.Portable.CSharp.targetsファイルをインクルードする。このtargetsファイルは、アセンブリの参照解決先として、ファサードアセンブリのディレクトリを指定する。以上のような仕組みで、PCLはコマンドラインのMSBuildからもIDEからもビルドできるようになっている。高度なPCLの作成とNuGetを使用した配布のトリックPCLは、その性質上、対象フレームワークが提供するAPIの最大公約数的なものになるのが一般的だ。プラットフォーム別のアセンブリを用意することで、この限界を突破しつつ、ライブラリをPCLとして提供することもできないわけではない。ここでは、Xamarinのエヴァンジェリストが作成した、UI上のメッセージポップアップを実現するPCLのNuGetパッケージのサンプルを基に、その方法を簡単に紹介する。Frameworkでは、コンパイル時と実行時の型参照の解決に、アセンブリ名を含む完全修飾名を使用する。コンパイル時と実行時でアセンブリが異なっても、この完全修飾名さえ一致する型であると判断されれば、問題なくロードできて実行できてしまう。この性質を利用すると、次のようなトリックが成立する。APIだけはPCLとして共通化しておいて、コンパイル時にはそのAPIを定義したアセンブリが参照されるようにしておいて、アプリケーションのビルド時には、そのAPIのプラットフォーム固有の実装を含むアセンブリが参照されるようにすれば、本来同一のDLLであるPCLに比べて、より幅広い機能を対象とするライブラリを作成して公開できるのである。これは、NuGetを活用することで、ユーザーが自然に使用できるような方法で、ライブラリを参照できるのである。具体的には、API定義として機能するPCLを作成する。実装はまともに動作しなくてよい(アプリケーションからは呼び出されない)。PhoneではMessageBoxが用いられている)。それらのアセンブリのクラスは、API定義のPCLと同じ完全修飾名となるよう、ネームスペースとアセンブリ名を同一にする必要がある。それぞれのプラットフォーム用にビルドされたアセンブリを、対応するプラットフォーム用のディレクトリに配置したNuGetの.nupkgファイルが作成されるよう、.nuspecファイルを記述し、これに基づいて.nupkgファイルを作成する。このPCLを参照するアプリケーションのビルド時には、それぞれのプラットフォームに対応したアセンブリが、このNuGetパッケージの中から適宜選択されることになる。このような手順によって、PCLが共通APIの最大公約数の範囲を超える機能を提供できるのである。API定義と実装が分かれているだけでもPCLとしては十分であって、NuGetにする必要はないが、通常の参照DLLでは、API解決とアプリケーションのビルドで、別々の実体(ファイル)を使用することはできないだろう。すると複雑な参照の仕方をユーザーに要求することになってしまう。NuGetパッケージにしておくことで、ユーザーにとって違和感のない参照が可能になるのである。PCLの課題PCLはまだ真の意味でポータブルであるとは言えない。2などのオープンソースライセンスに基づいて配布されることが必要だ。この意味では、マイクロソフトもXamarinも、現在のPCLの配布形態が十分に良いとは考えていない。Linux上のMonoDevelopでも、PCLのプロジェクトを「作成」することは可能だ。そのプロジェクトのビルドは成功しない。PCLのビルドに必要な、肝心のファサードアセンブリが存在しないからだ。4.6をインストールした後、それらのアセンブリを手動でLinux環境のMonoインストール先にコピーする必要がある。4.6にある.zipファイルの内容を展開する(UNIX環境では「.(ドット)」で始まるこのフォルダ名は隠しディレクトリ扱いになることに注意されたい)。これで、Linux版MonoDevelopでも、PCLのテンプレートが有効に機能するはずだ。Microsoft.Portable.CSharp.targetsなど、PCLプロジェクトのビルドに必要なファイルは、別途、Monoがインストールしているはずである。1つの課題は、オープン性にあるといえる。「System」で始まるPCLのAPIのカタログは、マイクロソフトが定義しており、Xamarinのファサードアセンブリは、それに従っているだけだ。これらに含まれない型が必要になる場合は、別のPCLアセンブリを作成すればよく、一般開発者としては問題ないが、プラットフォームの提供者が関与する余地は今のところ無い。PCLに関しては、JavaにおけるJSRのような存在は無い。Studioのプロファイル選択ダイアログに反映されることはない。マイクロソフトが新しくPCLプロファイルを定義することになれば、IDEサポートにも反映されるのではないか、と筆者は想像する。Foundationが担うことが期待されるのかもしれない(もちろん、特にそのような声が上がらなければ、特に需要はないということで、現状のままで進行するだろう)。※以下では、本稿の前後を合わせて5回分(第10回~第14回)のみ表示しています。INDEX]を参照してください。Xamarin.AndroidにおけるJava相互運用の仕組みと、Javaバインディング・プロジェクトXamarin.AndroidでJavaとの相互運用を実現するアーキテクチャについて、さらにメモリ管理などの注意点を説明。Xamarin.Androidの制限事項についても解説する。MonoDevelopの基本的な機能を解説。C#コーディング補助機能についても紹介する。MonoDevelopにおけるビルド/実行/デバッグと、iOS/Android向けのGUIデザイナーMonoDevelopでアプリをビルド/実行/デバッグするための機能を解説。iOS/Android向けのGUIデザイナーや、MonoDevelopのカスタムアドインについても紹介する。Xamarinと、ポータブル・クラス・ライブラリ(PCL)複数プラットフォーム向けのライブラリを作れるPCLの概要と利点について解説。Xamarin.iOSやXamarin.Androidでの利用方法や、XamarinでPCLを実現する仕組み、PCLの課題を説明する。Xamarin.Formsの基本構想と仕組みクロスプラットフォームで使用できるモバイルUIライブラリであるXamarin.Formsの基本構想や仕組みについて説明する。機械学習エンジニアを目指す人~初中級者のための技術情報サイトです。「機械学習&AI」「クラウド&ビッグデータ」「IoTデバイス」のネット記事情報を共有中。開発者のためのSlackチーム、作りました:「機械学習&AI」「クラウド&ビッグデータ」「IoTデバイス」のネット記事情報を共有中。2020最適なビューへの切り替えを推奨します:スマートフォン用表示に。