Visual Basic で iOS アプリを書くプロジェクトを作成…できた

Visual Basic で iOS アプリを書くプロジェクトを作成…している途中 | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/5604

昨日の続きで、Xamarin.iOSを使ってVBでコードを書いてiOSアプリを書く、というニッチな話を。
結論から言うと、一応できました。結構、回避策を使っているので、もうちょっとアプローチを考えないといけないのですがブレイクスルーはできた感じ。

■Xamarin.MonoTouch.VisualBasic.targets を作成する

以下の3つのファイルを作成します。

C:\Program Files (x86)\MSBuild\Xamarin\iOS\Xamarin.MonoTouch.VisualBasic.targets

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
	<PropertyGroup>
		<TargetFrameworkIdentifier>MonoTouch</TargetFrameworkIdentifier>
		<TargetFrameworkVersion Condition="'$(TargetFrameworkVersion)' == ''">v1.0</TargetFrameworkVersion>
	</PropertyGroup>
	<Import Project="$(MSBuildBinPath)\Microsoft.VisualBasic.Targets" />
	<Import Project="Xamarin.MonoTouch.Common.targets" />
</Project>

C:\Program Files (x86)\MSBuild\Xamarin\Xamarin.ObjcBinding.VisualBasic.targets

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
        <Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.ObjcBinding.VisualBasic.targets" />
</Project>

C:\Program Files (x86)\MSBuild\Xamarin\iOS\Xamarin.ObjcBinding.VisualBasic.targets

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <UsingTask TaskName="Xamarin.ObjcBinding.Tasks.BTouch" AssemblyFile="Xamarin.ObjcBinding.Tasks.dll" />

  <PropertyGroup>
    <TargetFrameworkIdentifier>MonoTouch</TargetFrameworkIdentifier>
    <TargetFrameworkVersion Condition="'$(OS)' == 'Unix'">v1.0</TargetFrameworkVersion>
    <TargetFrameworkVersion Condition="'$(OS)' != 'Unix'">v4.0</TargetFrameworkVersion>
  </PropertyGroup>

  <Import Project="$(MSBuildBinPath)\Microsoft.VisualBasic.Targets" />
  <Import Project="Xamarin.ObjcBinding.Common.targets" />

  <PropertyGroup>
    <!-- work around a bug in the Mono Microsoft.CSharp.Targets that defaults the compiler to gmcs -->
    <CscToolExe Condition = "'$(OS)' == 'Unix'">vbnc</CscToolExe>

    <!-- Btouch needs CscPath, but when building from within Visual Studio, it and the CscTool{Exe,Path}
         properties will be empty since VS uses the in-process compiler, so fix them. -->
    <CscPath Condition="'$(CscPath)' == '' And '$(OS)' != 'Unix'">$(CscToolPath)$(CscToolExe)</CscPath>
    <CscPath Condition="'$(CscPath)' == '' And '$(OS)' != 'Unix'">$(MSBuildToolsPath)\vbc.exe</CscPath>

    <BaseLibDllPath Condition="'$(OS)' == 'Unix'">/Developer/MonoTouch/usr/lib/mono/2.1/monotouch.dll</BaseLibDllPath>
    <BaseLibDllPath Condition="'$(OS)' != 'Unix'">$(MSBuildExtensionsPath)\Xamarin\iOS\monotouch.dll</BaseLibDllPath>
    <BTouchToolExe Condition="'$(BTouchToolExe)' == '' And '$(OS)' == 'Unix'">/Developer/MonoTouch/usr/bin/btouch</BTouchToolExe>
    <BTouchToolExe Condition="'$(BTouchToolExe)' == '' And '$(OS)' != 'Unix'">$(MSBuildExtensionsPath)\Xamarin\iOS\btouch.exe</BTouchToolExe>
    <GeneratedSourcesFileList Condition="'$(GeneratedSourcesFileListing)' == ''">$(GeneratedSourcesDirectory)\sources.list</GeneratedSourcesFileList>
  </PropertyGroup>

  <!-- Add our own pre-build steps -->
  <PropertyGroup>
    <CompileDependsOn>
      GenerateBindings;
      $(CompileDependsOn)
    </CompileDependsOn>
  </PropertyGroup>

  <!-- Override the CoreCompile Target to use btouch -->
  <Target Name="GenerateBindings"
  	  Inputs="$(MSBuildAllProjects);@(ObjcBindingApiDefinition);@(ObjcBindingCoreSource);@(ReferencePath);@(ObjcBindingNativeLibrary)"
	  Outputs="$(GeneratedSourcesFileList)">

    <BTouch AdditionalLibPaths="$(AdditionalLibPaths)"
    	    AllowUnsafeBlocks="$(AllowUnsafeBlocks)"
	    ApiDefinitions="@(ObjcBindingApiDefinition)"
	    CoreSources="@(ObjcBindingCoreSource)"
	    DefineConstants="$(DefineConstants)"
	    GeneratedSourcesDirectory="$(GeneratedSourcesDirectory)"
	    GeneratedSourcesFileList="$(GeneratedSourcesFileList)"
	    Namespace="$(Namespace)"
	    BTouchToolPath="$(BTouchToolExe)"
	    CompilerPath="$(CscPath)"
	    BaseLibDll="$(BaseLibDllPath)"
	    NoStdLib="$(NoStdLib)">
      <Output TaskParameter="GeneratedSourcesFileList" ItemName="GeneratedSourcesFileList" />
    </BTouch>

    <ReadLinesFromFile File="$(GeneratedSourcesFileList)" >
      <Output TaskParameter="Lines" ItemName="GeneratedSources" />
    </ReadLinesFromFile>

    <CreateItem Include="@(ObjcBindingCoreSource)">
      <Output TaskParameter="Include" ItemName="Compile" />
    </CreateItem>

    <CreateItem Include="@(GeneratedSources)">
      <Output TaskParameter="Include" ItemName="Compile" />
    </CreateItem>

    <CreateItem Include="@(ObjcBindingNativeLibrary)">
      <Output TaskParameter="Include" ItemName="ManifestResourceWithNoCulture" />
    </CreateItem>
  </Target>

</Project>

■*.sln と *.vbproj を書き換える

どうやら、mac にデプロイしていなさそうの勘はあたりで、デプロイ(配置)するようにしたら通りました。
*.sln に以下になるように追加。「Deploy.0」が配置の実行にあたります。91DDFB1F-30BD-472E-9022-0D0E29A8A301 は VB プロジェクトの GUID です。

{91DDFB1F-30BD-472E-9022-0D0E29A8A301}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{91DDFB1F-30BD-472E-9022-0D0E29A8A301}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{91DDFB1F-30BD-472E-9022-0D0E29A8A301}.Debug|iPhoneSimulator.Deploy.0 = Debug|iPhoneSimulator

*.proj のほうは、以下になるように書き換えます。ProjectTypeGuids はプロジェクトの種類を設定するもので、6BC8ED88-2882-458C-8E55-DFD12B67127B は、Xamarin.iOS の C# の GUID です。このままだと C# のコンパイラが走ってしまうのでコメントアウトしています。が、このコメントを消してしまう(ProjectTypeGuids自体を削除する)とデプロイできません。変ですね(苦笑)。まあ、*.vbproj の読み込み部分が変らしいので、これはこれで使わせてもらいます。

<ProjectGuid>{91DDFB1F-30BD-472E-9022-0D0E29A8A301}</ProjectGuid>
<!--
<ProjectTypeGuids>{6BC8ED88-2882-458C-8E55-DFD12B67127B};{F184B08F-C81C-45F6-A57F-5ABD9991F28F}</ProjectTypeGuids>
-->

ここに出てくる GUID は、*.sln の上のほうにある Project 部分に対応します。

Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "HelloVB", "HelloVBHelloVB.vbproj", "{91DDFB1F-30BD-472E-9022-0D0E29A8A301}"
EndProject

ProjectGuid 関連はこちらへ。おそらく、Visual Basic 用のGUIDを自作すればOKかと思います。

VSの「プロジェクトの種類がこのインストールでサポートされていません」(ProjectTypeGuids) – あおきのTechメモ
http://d.hatena.ne.jp/aoki1210/20090912/p1
INFO: List of known project type Guids
http://www.mztools.com/Articles/2008/MZ2008017.aspx

■Microsoft.VisualBasic.dll を外す

先の方法で、無事 mac へのデプロイはできたのですが、こんどは VisualBasic.dll がロードできなくて iOS シミュレータを立ち上げる前にこけます。具体的には Visual Studio に出てくる出力をみると、以下な感じで、何かが load できていません。

Loaded assembly: /Users/masuda/Library/Caches/Xamarin/mtbs/builds/HelloVB/91ddfb1f-30bd-472e-9022-0d0e29a8a301/assemblies/HelloVB.exe
2014-03-25 03:06:09.981 HelloVB[9011:70b] Could not load 'HelloVB' for registration: System.Reflection.ReflectionTypeLoadException: The classes in the module cannot be loaded.
  at (wrapper managed-to-native) System.Reflection.Assembly:GetTypes (System.Reflection.Assembly,bool)
  at System.Reflection.Assembly.GetTypes () [0x00000] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Reflection/Assembly.cs:351
  at MonoTouch.Registrar.OldDynamicRegistrar.RegisterAssembly (System.Reflection.Assembly a) [0x00000] in /Developer/MonoTouch/Source/monotouch/src/ObjCRuntime/OldDynamicRegistrar.cs:67
Loaded assembly: /Developer/MonoTouch/usr/lib/mono/2.1/System.Xml.dll [External]
2014-03-25 03:06:09.983 HelloVB[9011:70b] This could be due to an outdated assembly kept by the simulator, location: /Users/masuda/Library/Caches/Xamarin/mtbs/builds/HelloVB/91ddfb1f-30bd-472e-9022-0d0e29a8a301/assemblies/HelloVB.exe
Missing method SetProjectError in assembly /Users/masuda/Library/Caches/Xamarin/mtbs/builds/HelloVB/91ddfb1f-30bd-472e-9022-0d0e29a8a301/assemblies/HelloVB.exe, type Microsoft.VisualBasic.CompilerServices.ProjectData
An unhandled exception occured.

多分、C# にない VisualBasic.dll を参照していると思われるので、*.vbproj から以下の設定で VisualBasic.dll を参照しないようにします。

  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">iPhoneSimulator</Platform>
...
	<NoVBRuntimeReference>true</NoVBRuntimeReference>
  </PropertyGroup>

VBなのに VisualBasic.dll を参照しないので、いくつか VB 特有の機能が失われますが、ひとまず。
VisualBasic.dll を参照していないので、My Project 回りの *.vb でコンパイルエラーが出るので、コメントアウトしていまいます。

■デバッグ実行する

うまくできると、こんな風にデバッグ実行ができます。

■サンプルはこちら

Xamarin の Hello World を VB に直したサンプルです。先の *.targets ファイルも入っています。

http://1drv.ms/1jnqkR7

VisualBasic.dll を外してしまったために、VB 特有の関数が使えなくなっています。ですが、mono にも vbnc という VB コンパイラがあるので、VisualBasic.dll はあるハズなんですよね。そのあたりをうまく整合性をあわせてやれば、もうちょっと汎用性がある形でできると思うのですが。このあたりは、Android版を作りながら考える予定。

追記 2014/03/26
プロジェクトテンプレートにしてみました。

http://1drv.ms/1l0Ssqs

カテゴリー: VB, Xamarin パーマリンク