連載:マルチユースなライブラリの開発手法【C#/.NETでiOS/Android開発も】

連載:マルチユースなライブラリの開発手法【C#/.NETでiOS/Android開発も】

.NET互換環境

2013年10月21日 (2013/12/01 更新)

マルチプラットフォーム開発を実現するための.NET Frameworkの互換環境について説明。その代表として、今回はMonoと、Monoベースのフレームワークを取り上げる。

岩永 信之
  • このエントリーをはてなブックマークに追加

 前回紹介したようなマルチプラットフォーム開発を実現するために、今回は.NET Frameworkの互換環境について説明する。互換環境もいくつかあるが、その代表として、利用者が多くサポートもしっかり得られるMonoと、Monoベースのフレームワークについて説明しよう。

Mono

 Monoは、GNOMEプロジェクトの創設者Miguel de Icaza氏の主導で開発されている.NET Framework互換フレームワークである(以下、本稿で単に「.NET Framework」という場合、マイクロソフト製の.NET Frameworkを指す)。Windows、Max OS X、Linuxなどを中心に、さまざまなプラットフォーム上で動作する。

 Mono自体は歴史が長く、.NET Frameworkの仕様公開直後から開発が始まり、Mono 1.0の正式リリースも2004年のことである。近年、Monoが急速に注目を浴びるようになったのは、iOSやAndroidの普及によるところが大きいだろう。C#や.NET Framework互換のライブラリを使ってiOSやAndroid向けのアプリ/ゲームを作れる環境として期待が集まっている。

 Figure 1に、Monoベースの製品(後述する有償製品を含む)がカバーする範囲を示す。

Figure 1: Monoベースの製品がカバーする範囲

ライセンスなどについて

 Monoはオープンソースで開発されていて、現在はXamarin社によって開発、販売、サポートが行われている。

 Monoは、コンパイラやツールなどの種類によっていくつかのライセンス形態を併用しているが、LGPL、GPL、X11ライセンスのいずれかである(参考「FAQ: Licensing」)。LPGLなどが適さない場合にも、別途、商用ライセンスの相談にも応じている。

 また、Monoの元となるC#やCLI(Common Language Infrastructure: .NET Frameworkの基盤部分の仕様)は、Table 1に示す団体・規格で標準化されている。マイクロソフトは、規格化した仕様に沿って実装している限り、これらの互換製品に対して特許権を主張することはないという約束(Microsoft Community Promise)もしていて、特許係争などによってMonoプロジェクトが継続不能に陥る心配もない。

 ECMAISOJIS
C# ECMA-334 ISO/IEC 23270 JIS X 3015
CLI ECMA-335 ISO/IEC 23271 JIS X 3016
Table 1: C#とCLIの標準規格

Monoベースの製品

 Mono自体は無償で使えるオープンソース製品であるが、Monoをベースとした有償製品の、Xamarin 2.0とUnityの2つについて紹介しておこう。

Xamarin 2.0

 Xamarin社の提供する製品群が、現在は社名を冠したXamarin 2.0という名称で提供されている。その中でも、本連載に特に関連するのは、Xamarin.AndroidXamarin.iOSの2製品である。これらは、名前どおり、Monoベースで、C#や.NET Frameworkのライブラリを使ってAndroidとiOS向けのアプリを作るための製品である。

 これらの製品は、それぞれAndroid/iOSのネイティブAPIをC#から呼び出せるようにしたものである。OS依存度の高いGUIなどの部分まで含めたクロスプラットフォーム開発を実現するものではないので注意いただきたい。

【コラム】マイクロソフトなどとの提携(※2013/12/01 追記)

 11月13日のVisual Studio Launchイベントで、マイクロソフトとXamarin社の提携が発表された(提携内容はMSDN会員向けの価格/試用期間の優待)。マイクロソフトも、マイクロソフト製以外のプラットフォームでの.NET互換環境の普及を推進している。

 また、Xamarin製品は、日本では、エクセルソフトが代理販売(日本語サポート付き)を行っている。

Unityゲーム・エンジン

 Unityゲーム・エンジンは、ユニティ・テクノロジーズ社が提供する、Monoをベースとしたゲーム開発用フレームワークで、Figure 2に示すようなプラットフォームに対応する。プラットフォームごとにネイティブ・コードを呼び出すこともできるが、大部分はGUI部分まで含めて単一ソース・コードでマルチプラットフォーム向けゲームを開発できる。

Figure 2: Unityゲーム・エンジンが対応するプラットフォーム

【コラム】PlayStationとUnity/Mono(※2013/12/01 追記)

 ソニー・コンピューター・エンタテイメント(SCE)は「PlayStation Mobile」という開発プラットフォームを提供している。PlayStation Mobileを使うことで、誰でも自由にPlayStation 4など向けのゲームを作成し、PlayStation Storeを通じてオンライン配信できる。このPlayStation MobileのSDKもMonoベースになっていて、C#を使ってゲームを開発できる。

 また、SCEはユニティ・テクノロジーズ社と提携していて、Unityゲーム・エンジンを使ってのPlayStation Mobile開発も可能である。

 ちなみに、PlayStation Mobileが対応するハードウェアは、PlayStation 4、PlayStation 3、PlayStation Vita、および、SCEが認証する一部のAndroid端末となる。

互換性

 Monoのような互換製品に対して抱くありがちな疑問は、互換性の問題がないかというものだろう。

 結論からいうと、「BCL(Base Class Library)」と呼ばれるような基礎的なライブラリのみを使うコードに関してはMono上でも問題なく動作する。UIのようにOS依存の強い部分は書き直すことになるが、アプリやゲームの根幹となるロジック部分はさまざまなOS上で共通利用できる。

.NET Frameworkの構成要素

 .NET Frameworkの互換性を考えるうえで、.NET Frameworkを以下の3つの構成要素に分けて考えてみよう。

  • コンパイラ: C#などの高級言語で書かれたプログラムを「IL(Intermediate Language)」と呼ばれる中間形式に変換する
  • 実行環境(ランタイム): ILコードを解釈して実行する
  • 標準ライブラリ: .NET Framework(あるいはその互換環境)をインストールした時点で使えるライブラリ

 Figure 3に示すように、.NET FrameworkとMonoそれぞれが、コンパイラ、実行環境、標準ライブラリの実装を持つ。

Figure 3: コンパイラ+実行環境+ライブラリ
Figure 3: コンパイラ+実行環境+ライブラリ

 結論だけ先に言ってしまえば、互換性についての心配が必要なのは図中の右端、つまり、標準ライブラリのプロファイル(=標準ライブラリ中にどのクラス、どのメソッドが含まれるか)の差だけである。

コンパイラ

 C#についてもILについても標準化されていて、Monoの実装はこの標準に基づいている。その結果、マイクロソフト製C#コンパイラを使ってWindows上でビルドしたプログラムを、Linux上のMonoランタイムで実行したり、あるいはその逆も、全く問題ない。

 もちろん、Visual Studio上で編集したC#プロジェクトをMonoDevelop(= Monoプロジェクトが提供するIDE)で開いてビルドして実行することも問題なくできる。

 ちなみに、Monoプロジェクトでは、マイクロソフト自身がオープンソースにしたものについては二重開発するつもりはなく、そのまま取り入れる方針である。例えばF#のコンパイラはオープンソース化されていて、Monoの別実装はない。

実行環境

 CLR(= .NET Frameworkの実行環境)もMonoの実行環境も、ILの仕様に沿ってプログラムを実行する。ガベージ・コレクションの方式など内部的な挙動は異なるが、このことが問題になるようなプログラムは極めて少ないだろう。

標準ライブラリ

 前述のとおり、コンパイラや実行環境については、.NET FrameworkとMonoの差が出ることはない。問題は、標準ライブラリとして利用できるクラスやメソッド(= プロファイル)の差である。

 といっても、BCL(Base Class Library: 基本クラス・ライブラリ)と呼ばれるような基礎的な部分についてはほぼ移植されている。気にすべきは、バージョンくらいだろう。

 ただし、一部*1を除けば仕様を基に再実装したものであるため、互換性があるのはあくまでpublicな部分に関してのみである*2

  • *1MEF(Managed Extensibility Framework)やASP.NET MVCなどに関しては、マイクロソフト自身がオープンソース化していて、Monoでもこれがそのまま使われている。
  • *2通常はprivateな部分を参照することはなく問題にならないが、例外(例えばBinaryFormatterクラスのようにリフレクションを使ってprivateメンバーの読み書きを行うもの)もあるため、注意が必要である。

 要するに、以下の点に注意すれば、.NET FrameworkとMonoの間での移植やソース・コード共有ができる。

  • BCLの範疇(はんちゅう)の外(例えばSystem.Windows名前空間(= WPF)やMicrosoft名前空間)を避ける
  • (サーバーOS以外では)ASP.NET関連のクラスを避ける
  • (リフレクションを使った)privateメンバーへのアクセスを避ける
  • Monoのどのバージョンが.NET Frameworkのどのバージョンに対応するか確認する

【コラム】ビルドさえ通れば動く

  .NET Frameworkはコンパイラや実行環境の仕様がしっかりしていて、その移植版であるMonoもかなりしっかりと互換性が保たれている。

 ターゲットとするプラットフォームごとに利用できるライブラリ・プロファイルに差があっても、それぞれでどのクラス、どのメソッドが使えるのかはビルド時に分かっているため、ビルドさえ通ってしまえば、実機で試してみるまでもなく、ほぼ動くことが保証される*3

  • *3ただし、iOSの場合は後述するAOTコンパイルの制約に引っかかった際に、ビルドは通るが実行時エラーになることがある。ジェネリックな仮想メソッドや、値型のジェネリックを使う場合には注意が必要

 例えば、Windowsデスクトップ上でだけデバッグを行った後、Android上で動かしてもほぼ問題なく動く。実機へのデプロイにそれなりの時間がかかってしまうモバイル開発では、この利点は非常に大きいだろう。

対応プロファイル

 前述のとおり、差を気にする必要があるのはライブラリ・プロファイルの部分だけである。この点について詳しく見ていこう。

デスクトップ向けMono

 開発当初のMonoは、ライブラリ・プロファイルまで含めて.NET Frameworkとの完全互換を目指していた。現在でも、デスクトップ向けのMonoは、一部(WPFなど)を除いて.NET Frameworkとの互換性を保っている*4(ASP.NETも動作可能)。

  • *4GUIに関しては、現在では、OSのマナーに沿ってOSごとに実装すべき(少なくとも標準ライブラリの範囲には不要)というポリシーになっている。もちろん、Gtk#のようなマルチプラットフォーム対応したGUIフレームワークもあるので、必要ならばこちらを使うといいだろう。

 要は、バージョンにだけ気を付ければよい。Table 2に、.NET FrameworkとMonoのバージョンの対応関係と、それぞれのバージョンで使える主要な機能の例を示す。例えば、.NET Framework 3.5向けにビルドしたライブラリは、Mono 2.6でそのまま実行できる。同様に、.NET 4向けのものであればMono 2.10で実行できる。

.NET FrameworkMonoLINQTaskクラスdynamicasyncCaller Info
3.5 2.6 × × × ×
4 2.10 × ×
4.5 3.2
Table 2: バージョンの対応関係と、使える機能の例

Xamarin.iOS/Xamarin.Android

 Xamarin.iOS/Xamarin.Androidが提供しているのは、.NET Frameworkの基本ライブラリと、それぞれiOS/AndroidのネイティブAPIに対する相互運用APIである。これらは、現状(2013年7月のアップデート以降)ではMono 3.2がベースとなっている*5(つまり、.NET Framework 4.5相当の基本ライブラリが利用できる)。

  • *57月のアップデート以前はMono 2.10ベース(.NET 4相当)。

 ただし、残念ながら、.NET 4.5向けにビルドしたDLLは、iOS向け/Android向けのプロジェクトからは参照できない。ライブラリも、それぞれiOS向け/Android向けに設定する必要がある。現状ではPortable Class Libraryにも対応しておらず*6、たとえ.NET 4.5との共通部分に当たるクラスやメソッドしか使わなかったとしても、別途プロジェクトを用意してビルドし直す必要がある。

  • *6Visual Studio LaunchイベントでのマイクロソフトとXamarinの提携発表と併せて、Xamarin.iOS/Xamarin.AndroidのPortable Class Libraryへの対応が発表された。最新版にアップグレードすればPortable Class Libraryを利用できる(※2013/12/01 修正: 対応する計画はあり、実際にコードベースも存在する。製品レベルの品質にまだ達していないということで、Xamarin 2.0の製品群でのサポートは外れている)。

Unityゲーム・エンジン

 Unityゲーム・エンジンは、Mono 2.6がベースとなっている。つまり、利用できる標準ライブラリは.NET Framework 3.5相当になる。

 Unityゲーム・エンジンは、一般的なC#プロジェクトとは異なり、ソリューション(.sln)やプロジェクト(.csproj)管理用のファイルを持たず、特定のディレクトリ以下にあるC#ソース・ファイルやDLLファイルをすべてビルド対象とする。このとき、DLLファイルは.NET Framework 3.5向けにビルドしたものをそのまま利用できる。

注意点: iOSの制限

 ご存じのとおり、iOSアプリでは、CLRのような仮想実行環境の動作が認められていない。そのため、Unityゲーム・エンジンやXamarin.iOSは、Monoの「AOT(Ahead of Time)コンパイル」という機能を使って、あらかじめネイティブ化してからアプリにパッケージ化している。

 Mono 3.0以前では、AOT実行にいくつか制約があり、利用できない言語機能/ライブラリがあった。詳しくは以下のページを参照してほしい。

 特に、ジェネリックな仮想メソッドと値型のジェネリックに関する制約はよく引っかかるので注意が必要である(Mono 3.2で、値型のジェネリックに関する制約は緩和された)。

 また、動的なコード実行は一切できない。実行時型情報が一切使えないわけではないが(is演算子やas演算子は使える)、C# 4.0のdynamicReflection.Emit式ツリーのコンパイルなどは利用できない。

最後に

 .NET FrameworkとMonoの互換性は、少なくとも基礎的な部分に関してはかなりしっかりしていて、使用するクラスやメソッドにだけ気を付ければ、簡単にマルチプラットフォームな開発が実現できるだろう。

 ただし、対応したいプラットフォームを増やせば増やすほど、やはり、共通して使用できるクラスやメソッドに制限がかかる。特にGUIに関しては難しく、GUIだけはOSごとに書き直すか、あるいはUnityゲーム・エンジンのように特定用途向けに絞ったフレームワークを使うことになるだろう。

 いずれにせよ、マルチプラットフォーム化しやすい部分としづらい部分を明確に意識して、分離するようなプログラミング設計が重要である。

【関連記事】:
  「Visual StudioでiOS/Androidアプリが書けるXamarinを試してみた(iOS編)
  「Visual StudioでiOS/Androidアプリが書けるXamarinを試してみた(Android編)
  ・ディープなXamarin技術情報の連載記事「インサイドXamarin」 )

1. iPhone/Android/Windows/Linux向けマルチターゲット化のシナリオとは?

C#を活用してマルチプラットフォームを実現する方法を解説する連載がスタート。今回は、ゲームを題材に、その「共通して使いたい部分」に関するシナリオを紹介する。

2. 【現在、表示中】≫ .NET互換環境

マルチプラットフォーム開発を実現するための.NET Frameworkの互換環境について説明。その代表として、今回はMonoと、Monoベースのフレームワークを取り上げる。

イベント情報(メディアスポンサーです)

Azure Central の記事内容の紹介

GrapeCity Garage 記事内容の紹介

Twitterでつぶやこう!


Build Insider賛同企業・団体

Build Insiderは、以下の企業・団体の支援を受けて活動しています(募集概要)。

ゴールドレベル

  • グレープシティ株式会社
  • 日本マイクロソフト株式会社