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 ファイルも入っています。
VisualBasic.dll を外してしまったために、VB 特有の関数が使えなくなっています。ですが、mono にも vbnc という VB コンパイラがあるので、VisualBasic.dll はあるハズなんですよね。そのあたりをうまく整合性をあわせてやれば、もうちょっと汎用性がある形でできると思うのですが。このあたりは、Android版を作りながら考える予定。
追記 2014/03/26
プロジェクトテンプレートにしてみました。

