SG

Mono for Android を触ってみたときのメモ(Visual Studio 向け)

 MonoDroid として開発されていた AndroidC# 開発環境が正式に「Mono for Android」としてリリースされました。仕事で業務特化された Android アプリケーションを作る案件があるのですが、今まで .NET Framework 上で動作していたライブラリをそのまま使用できるのか、という点に非常に興味があり、触ってみることに。

インストール

 すでに Eclipse などを使用して、Android アプリケーションを開発している人は、Visual Studio 2010 .NET Framework 3.5 と Mono for Android をインストールすれば OK です。そうでない方は、Java JDK JREAndroid SDK の導入を済ませておいてください。なお、Mono for AndroidSDK 参照先がデフォルトでは C:\android-sdk-windows に設定されているため、特に問題がなければ C:\android-sdk-windows に置いておいたほうが楽です。

 http://mono-android.net/DownloadTrial より、インストーラをダウンロードして実行。インストール完了後に、Visual Studio を立ち上げて、新しいプロジェクトを作成してみましょう。[Visial C#] の中に [Mono for Android] が追加されていれば成功です。


設定

 Android SDK を起動し、デバイスエミュレータを作成します(参考)。
 Android SDKディレクトリをデフォルト以外の場所に格納した場合、Visual Studio にも設定変更が必要となります。

Visual Studio の [ツール] から [オプション] をクリックし、オプションダイアログを表示します。[Mono for Android] の [Android SDK Location] を Android SDK が格納されているフォルダに変更します。


サンプルを動かす

 まずはサンプルをダウンロードします。Mono for Android 用のサンプルは GitHub - mono/monodroid-samples で公開されています。好きなものを選択してソリューションを起動。見た感じはいつもの C# プロジェクトですが、含まれている内容は Android のものです。Resources フォルダにイメージ、アクティビティのレイアウト、値などが格納されています。既に Android アプリケーションを開発したことがある方は馴染みが深いものでしょう。AndroidManifest.xml は AssemblyInfo.cs と同じ場所に格納されています。

using System;

using Android.App;
using Android.OS;

namespace Mono.Samples.HelloWorld
{
    [Activity (Label = "Hello World Demo", MainLauncher = true)]
    public class HelloAndroid : Activity
    {
        protected override void OnCreate (Bundle savedInstanceState)
        {
            base.OnCreate (savedInstanceState);

            SetContentView (Resource.Layout.main);
        }
    }
}


 コードを見る限りは Android のコードをラップしちゃいました的な。メソッドの名前が大文字から始まるようになっていたり、TextView に Text プロパティが使用できるようになっていたり、FindViewById にジェネリックが使用できたり、C# らしく書くことが出来るように考慮されているのは非常にありがたい。もちろん LINQ もあるぜよ。


 さて実際に起動させてみましょう。作成しておいたデバイスエミュレータに配置&起動。時間がかかるけど泣かない。[ビルド] メニューからプロジェクトを配置することができる。 [> ツールボタンで配置と実行を一度に行うときは、[構成マネージャ] で [配置] にチェックをいれておく。エミュレータの起動が終わった。配置だ。

C:\Program Files\MSBuild\Novell\mandroid.exe -v --nosign --sdk-dir="C:\Program Files\android-sdk-windows" --builddir="C:\Documents and Settings\User\デスクトップ\mono-monodroid-samples-0ab146c\HelloWorld\obj\Debug\android" --framework-dir="C:\Program Files\Reference Assemblies\Microsoft\Framework\MonoAndroid\v2.2" --framework-dir="C:\Program Files\Reference Assemblies\Microsoft\Framework\MonoAndroid\v1.0" -S="C:\Documents and Settings\User\デスクトップ\mono-monodroid-samples-0ab146c\HelloWorld\obj\Debug\res" --package="mono.samples.helloworld" --nolink --abi="armeabi" --java-sdk-dir="C:\Program Files\Java\jdk1.6.0_24" --debug --manifest-template="C:\Documents and Settings\User\デスクトップ\mono-monodroid-samples-0ab146c\HelloWorld\Properties\AndroidManifest.xml" --sdk-platform="8" "C:\Documents and Settings\User\デスクトップ\mono-monodroid-samples-0ab146c\HelloWorld\bin\Debug\HelloWorld.dll" "C:\Program Files\Reference Assemblies\Microsoft\Framework\MonoAndroid\v2.2\Mono.Android.dll" "C:\Program Files\Reference Assemblies\Microsoft\Framework\MonoAndroid\v1.0\mscorlib.dll" "C:\Program Files\Reference Assemblies\Microsoft\Framework\MonoAndroid\v1.0\System.Core.dll" "C:\Program Files\Reference Assemblies\Microsoft\Framework\MonoAndroid\v1.0\System.dll" "C:\Program Files\Reference Assemblies\Microsoft\Framework\MonoAndroid\v1.0\System.Xml.dll" "C:\Program Files\Reference Assemblies\Microsoft\Framework\MonoAndroid\v1.0\System.Xml.Linq.dll"
C:\Program Files\MSBuild\Novell\Novell.MonoDroid.Common.targets(335,2): error MSB6006: "mandroid.exe" はコード -1 を伴って終了しました。 [C:\Documents and Settings\User\デスクトップ\mono-monodroid-samples-0ab146c\HelloWorld\HelloWorld.csproj]
プロジェクト "C:\Documents and Settings\User\デスクトップ\mono-monodroid-samples-0ab146c\HelloWorld\HelloWorld.csproj" (SignAndroidPackage ターゲット) のビルドが終了しました -- 失敗。

ビルドに失敗しました。

"C:\Documents and Settings\User\デスクトップ\mono-monodroid-samples-0ab146c\HelloWorld\HelloWorld.csproj" (SignAndroidPackage ターゲット) (1) ->
(_CompileAndroidPackage ターゲット) ->
C:\Program Files\MSBuild\Novell\Novell.MonoDroid.Common.targets(335,2): error MSB6006: "mandroid.exe" はコード -1 を伴って終了しました。 [C:\Documents and Settings\User\デスクトップ\mono-monodroid-samples-0ab146c\HelloWorld\HelloWorld.csproj]

0 個の警告
1 エラー


 なん……だと……。どうもサンプルをデスクトップに置いていたのが原因で、Cドライブの直下などに格納しなおすと問題なくいける。日本語が入ってると駄目みたいだなー。
 気を取り直して再度挑戦。配置できたので起動。



 んー HelloWorld を表示するだけなのに重たい……。こんなものなのかしらん。 
 出来上がった .apk のサイズが妙に大きい。Java で作った .apk が可愛くみえるサイズ。恐らく Visual Studioデバッグ情報を交換するためだと思われます。実機リリースでは小さくなるのかな? この辺りはライセンスを購入してもらえたら調査……*1


 ライセンスといえば。

Mono for Android Evaluation

The evaluation version of Mono for Android does not expire, but enables development and testing against the

Android Emulator only.

http://mono-android.net/DownloadTrial


 Evaluation バージョンについては、エミュレータのみですが無期限で使用できます。遊ぶ分には Evaluation で問題ないのですが、Visual Studio Express Edition には対応していないので、完全に無料で遊べないという点にはご注意を。

既存のプロジェクトを参照してみる

 Mono for Android プロジェクトではないクラスライブラリのプロジェクトを参照できるのか調査。今回は単純に Homu*2 というクラスがあるだけの、クラスライブラリ プロジェクトを作成。Homu クラスには FirstName プロパティと FamilyName プロパティがあるだけです。


using System;

using Android.App;
using Android.OS;
using Android.Widget;

namespace Mono.Samples.HelloWorld
{
    [Activity (Label = "Hello World Demo", MainLauncher = true)]
    public class HelloAndroid : Activity
    {
        protected override void OnCreate (Bundle savedInstanceState)
        {
            base.OnCreate (savedInstanceState);

            SetContentView(Resource.Layout.main);

            TextView textView = FindViewById<TextView>(Resource.Id.text);

            CSharpClassLibrary.Homu homuhomu = new CSharpClassLibrary.Homu();

            textView.Text = homuhomu.FirstName + " " + homuhomu.FamilyName;
        }
    }
}


 単純に苗字と名前を表示するだけです。この程度なら気にしないで使用できる……かと思いきや、ビルドは通ってデバッグ実行もできるにも関わらず、エラー一覧には警告が表示されています。



 これは Mono for Android 用のクラスライブラリ プロジェクトを作成して、各ソースコードを SCM か何かでリンクするのが良さそう。

VBで作られたプロジェクトを参照してみる

 ちなみにVBで書かれたクラスライブラリ プロジェクトを参照して使用してみる。先ほどの C# クラスライブラリ同様、警告が表示されるがビルドは通る。さていけるか……?

C:\Program Files\MSBuild\Novell\mandroid.exe -v --nosign --sdk-dir="C:\Program Files\android-sdk-windows" --builddir="C:\HelloWorld\obj\Debug\android" --framework-dir="C:\Program Files\Reference Assemblies\Microsoft\Framework\MonoAndroid\v2.2" --framework-dir="C:\Program Files\Reference Assemblies\Microsoft\Framework\MonoAndroid\v1.0" -S="C:\HelloWorld\obj\Debug\res" --package="mono.samples.helloworld" --abi="armeabi" --java-sdk-dir="C:\Program Files\Java\jdk1.6.0_24" --debug --manifest-template="C:\HelloWorld\Properties\AndroidManifest.xml" --sdk-platform="8" "C:\HelloWorld\bin\Debug\HelloWorld.dll" "C:\Program Files\Reference Assemblies\Microsoft\Framework\MonoAndroid\v2.2\Mono.Android.dll" "C:\Program Files\Reference Assemblies\Microsoft\Framework\MonoAndroid\v1.0\mscorlib.dll" "C:\Program Files\Reference Assemblies\Microsoft\Framework\MonoAndroid\v1.0\System.Core.dll" "C:\Program Files\Reference Assemblies\Microsoft\Framework\MonoAndroid\v1.0\System.dll" "C:\Program Files\Reference Assemblies\Microsoft\Framework\MonoAndroid\v1.0\System.Xml.dll" "C:\Program Files\Reference Assemblies\Microsoft\Framework\MonoAndroid\v1.0\System.Xml.Linq.dll" "C:\HelloWorld\ClassLibrary1\bin\Debug\VBClassLibrary.dll"
MANDROID : error : while loading assemblies: System.IO.FileNotFoundException: Could not load assembly 'Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. Perhaps it doesn't exist in the Mono for Android profile? [C:\HelloWorld\HelloWorld.csproj]
File name: 'Microsoft.VisualBasic.dll'
at Monodroid.Tuner.MonoDroidResolver.Resolve (Mono.Cecil.AssemblyNameReference reference) [0x00000] in :0
at Monodroid.Scanner.ComputeListOfAssemblies (Monodroid.Arguments args, System.Collections.Generic.HashSet`1 assemblies, Mono.Cecil.AssemblyDefinition assembly) [0x00000] in :0
at Monodroid.Scanner.ComputeListOfAssemblies (Monodroid.Arguments args, System.Collections.Generic.HashSet`1 assemblies, Mono.Cecil.AssemblyDefinition assembly) [0x00000] in :0
at Monodroid.Scanner.ComputeListOfAssemblies (Monodroid.Arguments args) [0x00000] in :0
monodroid : error 1: System.ArgumentNullException: Argument cannot be null. [C:\HelloWorld\HelloWorld.csproj]
Parameter name: source
at System.Linq.Check.SourceAndSelector (System.Object source, System.Object selector) [0x00000] in :0
at System.Linq.Enumerable.SelectMany[String,String] (IEnumerable`1 source, System.Func`2 selector) [0x00000] in :0
at Monodroid.Droidinator.CopyPackagedResources (System.Collections.Generic.List`1 assemblies) [0x00000] in :0
at Monodroid.Droidinator.CreateApk () [0x00000] in :0
at Monodroid.MainClass.Main (System.String[] argv) [0x00000] in :0
プロジェクト "C:\HelloWorld\HelloWorld.csproj" (SignAndroidPackage ターゲット) のビルドが終了しました -- 失敗。

ビルドに失敗しました。

"C:\HelloWorld\HelloWorld.csproj" (SignAndroidPackage ターゲット) (1) ->
(_CompileAndroidPackage ターゲット) ->
MANDROID : error : while loading assemblies: System.IO.FileNotFoundException: Could not load assembly 'Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. Perhaps it doesn't exist in the Mono for Android profile? [C:\HelloWorld\HelloWorld.csproj]
monodroid : error 1: System.ArgumentNullException: Argument cannot be null. [C:\HelloWorld\HelloWorld.csproj]

0 個の警告
2 エラー


 失敗してしまった。VisualBasic 名前空間アセンブリロードに失敗して怒られる。Mono が C# しか対応していないので、これは仕方ないね。

その他テンプレート

 OpenGL 用プロジェクトテンプレートも用意されています。AndroidiOS 向けのゲームを同時開発できるかも? ちなみに、AndroidiOSWindows Phone 7 向けのアプリケーションを同時開発することもできるようです。サンプルは GitHub - conceptdev/RestaurantGuide: Cross-phone-platform basic restaurant reviews にあります。

総評

 アプリケーションの作成自体は、Java で開発するのと大きな差はないので、Java で入門した後でも大したコスト無しに導入は可能。Mono 面白いなー。公式サイトのアーキテクチャも興味をそそられる。今後は Silverlight や F# の採用もあるようなので、ますます期待。しかし開発ライセンスが安くはないので貧乏会社には辛いところ。こういうのホイホイ購入してくれる新天地を探しています。

*1:Evaluation では Release ビルドに失敗します

*2:よく訓練されたプログラマHoge ではなく Homu を使用する。ほむらちゃほむほむ