ものがたり(旧)

atsushieno.hatenablog.com に続く

Mono for Android 4.0がリリースされました

http://android.xamarin.com/Releases/Mono_for_Android_4/Release_4.0.0

いきなり4.0と銘打っていますが、当初Mono for Android 2.0と言われていたやつのマーケティング的な番号の変更にすぎないので、実態はこれまで1.9.xとして出していたものとそれほど変わりません。

…と言いたいところですが、実際には1.9.2から内部的には小さくない変更が加えられています。ここには1.9.0のリリース以来何も書いていなかったので、1.9.1-4.0.0の間に行われた変更について、一度まとめておこうと思います。

Android 4.0 (IceCreamSandwich) support

MfA 1.9.2で、ICSに対応しました。Honeycombの時はタブレットを用意してHoneycombGalleryというサンプルを移植して動作確認できたのですが、ICS端末はまだ手元に来るほど出回っておらず、BeamとかNFCとか(あ、かぶってるか)wifidirectとか、新機能を利用するサンプルの多くがデバイス前提なので、とりあえずAPIバインディングは用意したというレベルです。

ICS対応については、重要な変更があります。それは、Android 4.0で加えられたdalvik VMのJNIのメモリモデルの変更によって、従来のMfAでビルドされたアプリケーションが動作しなくなっている(!)という問題に対応するものです。ICS上で動作するapkをビルドするためには、MfA 4.0で改めてビルドし直す必要があります。

(従来のAndroidのJNIでは、local referenceとglobal referenceを区別できなかったため、MfAに含まれるmonoランタイムのGCでも、これらを区別して扱うことはなかった(できなかった)というわけです。JNIメモリモデルの変更は、Androidで今後Copying GCを導入するにあたって解決する必要があった問題と言えます。)

ちなみに、この変更に関連するものとして、MCW (Managed Callable Wrapper)として作成されていたクラスでは、IntPtrだけを取るコンストラクタを、IntPtrとJniHandleOwnershipという2つの引数を取るコンストラクタに変更する必要がありました。もしユーザーレベルでカスタムバインディングコードを作成していた場合は、同様の変更を加える必要があります。

fast deployment support

Titanium Mobileにはfastdevというアプローチがあり、開発中のアプリケーションのapkを全てまとめてインストールすることなく、アプリケーションのコードを変更して実行できるようにするものです。Androidの特にarmエミュレータは非常に遅く、apkをインストールするだけでも何秒も待たされてイライラすることになります。apkをインストールするということは、アプリケーション全体をインストールするということです。

Android SDK r14以降では、apkの作成時に、更新されていないファイルの再アーカイブをスキップする改善が加えられましたが、apk全体を転送しなければならないことに変わりはなく、依然としてしばらく待たされることに変わりはありません。

Mono for Androidの場合、開発時(デバッグ中)のランタイムは、Market等で配布するためのリリースビルドとは異なり、開発機に別途インストールされた共有ランタイムパッケージを利用しています。デバッグ時にビルドされたアプリケーションのapkに含まれて実際に転送されるのは、アプリケーションのコードのみであり、全体をパッケージして長大な転送処理を行うようなことにはなっていません。

そんなわけで、デバッグのパッケージの転送には、長大な時間がかかっていたわけではないのですが(共有ランタイムが入っていない環境でデバッグを開始した場合は、共有ランタイムをインストールすることになるので、これはもちろん時間がかかりますが初回のみです)、fast deploymentでは、この部分にさらに改良を加えます。fast deploymentモードでは、コードにのみ変更がある場合、apkの再インストールは行われません。更新されたファイルのみが転送され、アプリケーションのフォルダ内で更新されます。

fast deploymentモードは、ストレートに実行する場合よりは複雑な処理を伴う以上、安定性に対する不安が無いとは言えないので、プロジェクト設定でoffにすることもできます。

起動時間の短縮

MfAアプリケーションは、apkの中にmonoランタイムが含まれていて、これをネイティブコードとして実行して初期化し、さらにJavaクラスをJNIでやりとりできるようにmono for androidのランタイムに登録するところから始めなければなりません。これが起動時間が長くなる原因なのですが、今回のバージョンではこの部分に大きな改良が加えられ、起動時間を開発者の実機環境で2.451秒から1.141秒までに短縮することに成功しています。

実際には遅延読み込みに切り替えているので、後で必要になったら読み込み処理が行われることに変わりはないのですが、起動時間の改善は多くの人から要望として上がっていたことでもあり、大きな改善になったと思います。

Google Maps API binding

これはMfA 1.9.2でICSサポートと同時に追加されたAPIで、google APIの対応するライブラリのバインディングということになります。Google Maps APIを使いたい人にとっては普通に便利でしょうし、今後追加される機能を示唆するものでもあります。

アプリケーションサイズの縮小

これはMfA 1.9.1で行われた改良のひとつで、実際にはリリースビルドに含まれるアセンブリを大きく縮小したということになります。

MonoTouchやそれ以前のmonoを知っている人は(わたしもこれまで何度か書いていますが)、cecil linker / tunerというツールが、アプリケーションで使用されていないコードを参照アセンブリから削り落とすことが出来るという話を知っているかもしれませんが、MfA 1.9.1では、(それ以前からlinkerは使用されていましたが)これがより効果的に作用するように、Mono.Android.dllに改良を加えています。リリースノートにも例が載っていますが、4MBだったアプリケーションが3MB以下に収まるようになっています。

おまけ: generic API bindingの拡大

従来のMfAではJava genericsが使用されているクラスのバインディングのサポートは限定的なもので、AdapterView<T>みたいな重要なクラスだけが実は手動で追加されているのですが、今回のリリースで、これまでサポートしていなかったジェネリッククラスやジェネリックメソッドに依存するメンバーを拾えるように改良を加えました。

Javaと.NETの両方のジェネリクスに詳しい人は(なかなかいないと思いますが)、これらが性格を異にし相性が悪いことを知っているかもしれません。erased genericやvarianceの違い、constraintの違いなど、問題がいくつもあります。この辺を改良してAPI coverageを広げたいというのがわたしの希望で、今回ある程度納得の出来る範囲でこれを実現できたことになります。個人的に大きいのはParcelable.Creator<T>を取り込めたことで、出来ることが広がっています。がこの話はまた今度。

というわけで

今回のMono for Androidのリリースが、今年最後のものになると思いますが、これまでにない数多くの改善が加えられた the latest and greatest releaseになっていると思います。Mono for Android 1.2の頃と比べて、だいぶ変わってきたと思います。

ちなみに先月はXamarin本社でミーティングがあって、チームメンバーが開発しているものを見せてもらったりしてきたのですが、今後のMfAにも割とビックリするような新機能が追加されそうで、既に公開される日が待ち遠しいところです。