++C++; // 未確認飛行 C ブログ

http://ufcpp.net/

Xamarin 2.0

leave a comment »

Xamarin 2.0 のアナウンスがあったわけですが。

Xamarin 2.0 の内容

単に、メジャー バージョンアップに合わせて、ブランド名を統一したという内容。今まで、Mono Touch、Mono for Android だったものが、Xamarin.iOS、Xamarin.Android に。

メジャー バージョンアップによって、Visual Studio 使って Windows 上で iOS 開発できるようになったりも。新 IDE の Xamarin Sudio は世界で一番の Android UI ビルダーだという自信もあるそうで。

クロス プラットフォーム

クロス プラットフォームというと割と夢見がちな意見と、それを警戒する意見にたどりつきがち。

Xamarin 2.0 のニュースを見て、知り合いから「こういうツールって使い物になるの?」とのご意見も求められてしまったので、改めてこのあたりを説明。

結論を先に言ってしまえば、Xamarin は割といい具合に現実解を得ていると思います。警戒は必要ないですが、逆に、夢も見すぎてはいけません(100%コード流用の Write once, run anywhere を想像しちゃいけない)。

クロス プラットフォームの問題点

まずは、クロス プラットフォームを頑張りすぎることの問題点から。

iOS に Flash が乗らない理由としても有名ですが、Write once, run anywhere 的な完全なクロス プラットフォーム狙いには問題も多いです。例えば以下のような:

  • タイムラグ: OS がアップデートされても、クロス プラットフォーム ランタイム側が対応しない限り、アプリが最新機能を使えない
  • 最大公約数: どの OS でも使えるような最低限の機能しか使えなくなる
  • なじまないUI: OS には OS ごとのマナーがあるのに、それを無視した UI が作られる

クロス プラットフォームにしないという選択肢

なので、同じマイクロソフトのプラットフォーム(PC、タブレット、Phone、Web サーバー)ですら、Write once, run anywhere はもうあきらめられています。基礎的な部分だけクロス プラットフォームに作って、プラットフォーム固有の部分は別途書く。具体的には、

クロス プラットフォームに使える部分(いわゆる、基本ライブラリ):

  • 文字列処理
  • 数学関数
  • ネットワーク通信
  • ファイル(正確にはストリーム)操作
  • コレクションと、それに対する操作(LINQ)

プラットフォーム固有の部分:

  • 最新の機能
  • セキュリティ/プライバシー的な制限が必要な部分
  • UI

となっていて、前者にだけ依存するものならばクロス プラットフォームにできます。いわゆるモデルはほぼクロス プラットフォーム可能。ビューモデルもある程度可能(古いプラットフォームを捨てれば)。

Xamarin の方針もこれと全く同じです。MVVM パターンというか、ビューモデルまでポータブルに使えるようにライブラリ整備も頑張っているそうで。

Xamarin がやっていること

端的に言うと、Xamarin はネイティブ相互運用をやっているだけ。

.NET Framewoke には通称 P/Invoke(platfrom invoke: プラットフォーム呼び出し)という、ネイティブ コードを呼びだすための仕組みがあります。この仕組みはもちろん Mono でも実装されています。Xamarin.iOS や Xamarin.Android がやっていることは、この P/Invoke を介して iOS/Android の API を C# に公開しているだけです。

これが、最初に言ったような「警戒する必要ないけど、逆に、夢も見れない」という理由。クロス プラットフォーム製品にありがちな問題はほとんど起こらない代わりに、Write once, run anywhere もできません。

もっとも、慣れれば8割くらいのコードを共有化できるので、十分有用かと思われます。

Xamarin.iOS

Mono Touch と呼ばれていたころから有名な話ですが、iOS は仮想マシン(VM)を乗せれないことになっています。で、じゃあ、Xamarin.iOS がどうしているかというと、事前にコンパイルしてネイティブ コード化してしまいます。

中間言語を介してその場その場でネイティブ化する JIT(Just In Time)コンパイルとの対比で、AOT(Ahead Of Time)コンパイルと呼ばれます。Mono は昔からこの AOT コンパイル機能を持っているので、それを使って iOS 向けアプリ パッケージを作っています。内部的に LLVM 最適化コンパイラーを使っているので、普通に効率のいいコードを吐き出します。

ちなみに、この AOT のせいで、C# の機能をフルに使えなかったりします。

  • 値型のジェネリックが怪しい
    • 例えば、Nullable 型の配列に対する Sum とかが動かなかったり
    • 構造体を Dictionary のキーにすると動かなかったり
  • ジェネリックな virtual メソッドが使えない
  • リフレクションが全滅
    • シリアライザーの類も大体全滅

詳しくは以下のページに:

Xamarin Developer Center > iOS > Limitations

(何が一番たちが悪いかというと、これ、コンパイルまではできてしまうこと。iOS 上にデプロイして実行して初めてダメだとわかります。せっかくの C# なのに…)

Xamarin.Android

一方で、Android 版は普通に Mono ランタイム上での JIT 実行に。「実機にデプロイして初めてわかる」みたいな問題はほとんど起こりません。

というか、むしろ、Mono VM は Dalvik VM よりも性能いいくらいだそうで。

Dalvik の性能がいまいちな理由と、Mono だとどうか:

  • 言語仕様/VM 仕様的に Java よりも .NET の方がいくつか、性能への配慮がある
    • 値型のサポート(小さいオブジェクトは値渡しにできる)
    • ジェネリックが VM レベルでの対応(不要なキャストやボックス化が起きない)
    • 既定でメソッドが非 virtual
  • ライセンス問題
    • Oracle が非協力的で既存の Java VM には頼れず、Dalvik VM はフル スクラッチで作りなおされていて、こなれていない
    • 一方、マイクロソフトは Mono に対して協力的(少なくとも絶対に特許権を主張しない)

それでも問題なくはない

こういう仕組みなので、クロス プラットフォーム製品にありがちな問題は“ほとんど”起こらないんですが、“まったく”ないわけではないです。

問題として残るのは以下の点:

  • タイムラグ: 中間層はさむよりはよっぽど早く最新機能に対応できますが、ノー タイムとはいかない
  • パッケージ サイズが膨らみがち: ランタイム同梱のせい

タイムラグ

P/Invoke を行うためには、P/Invoke 用のコードが少し必要になります。これの用意は多少手間。なので、「OS 機能のアップデートの瞬間に Xamarin 側も即座に対応」とはいかなくなります。

本当は、WinRT の言語プロジェクション/WinMD(Windows Metadata)のような仕組みが標準化されて欲しいところなんですが。OS 機能側が最初から言語中立なメタデータを公開。タイムラグなしでネイティブ機能を C# から利用可能。

残念なのは、WinRT の実装は WinDiv(マイクロソフトの Windows 開発部署)であって、DevDiv(Visual Studio とか C# を作っている開発部署)ではないんですよねぇ… こんな有望な技術に「Windows」の名を冠してしまって…

パッケージ サイズ

こっちが一番の懸念点。

アプリ パッケージに Mono ランタイムも含めることになるので、パッケージは総じてでかくなります。数MBの増加。

それなりにコンパクト化はしてるんですが:

Xamarin Developer Center > Android > Application Package Size

それでも Xamarin

普通は(iOS 上での Flash 排除に対する Steve Jobs の主張ももっともで)、公式提供の SDK の上にこんな別製品を重ねて(しかも有償製品)使っても良いことないんですけどもね。Xamarin でも実際、上記の通り多少の問題残りますし。

Xamarin.iOS や Xamarin.Android に関しては、それ以上に公式 SDK が未成熟で、起こる問題以上に、別製品を重ねるメリットの方が大きい状態。

iOS は、悪名高き Objective-C をいまだに使っていますし。Apple は根本的にハードウェア メーカーなので、ソフトウェア開発基盤への取り組みも弱いです。

Android は、Java のライセンスに関する係争を抱えています。ただ、でも、この辺りの問題は Java が Oracle の手から離れれば解決するというものでもないでしょう。「Java に足りないのは長期的なビジョンと開発リソース」というような話もあって、要は、きっちりお金を掛けないとできない部分が欠けてます。

なんだかんだ言って、.NET はマイクロソフトが一番バブリーな頃(Windows 95 の大ヒット直後から)に、かなりしっかりした研究を行った上で作ったものですからね。一朝一夕で抜けるものではないです。その .NET のクロス プラットフォーム移植、しかも、マイクロソフトも協力的で係争のない実装、それが Mono です。

ちなみに: Unity

少し余談的に。

Unity なんていう Mono の上に作られたクロス プラットフォームなゲーム エンジンもあるわけですが。

これ、結構もろに前述のようなクロス プラットフォームであることに起因する問題抱えます。ぎりぎりセーフなのは、

  • ドメインが狭い: ゲームという用途、それも(流行っているのは)スマフォ向けで、機器性能がある程度そろっている
  • 時期がよかった: ゲームの主戦場が据え置きゲーム機からスマフォに移る途中で、開発に関するノウハウが一度一気にリセットされた

というような背景があるからです。

Unity は初期設計もそんなにきれいじゃないので、寿命もそれほど長くないかも(といっても、個人的な想像としては、2・3年はたぶんまだ平気)。クロス プラットフォームだからって、Unity 依存の部分が多いコードを書くと後で泣くかも。きっちり設計すれば8割方のコードを Unity に依存しないように作れるはずなので、そうすべき(自分はそう作ってる)。Xamarin の勢いを見るに、C# を使うこと自体はもっともっと寿命長いはずなので。

Written by ufcpp

2013年2月24日 @ 05:02

カテゴリー: .NET, C#

Tagged with

コメントを残す