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
プロジェクトテンプレートにしてみました。