こんにちは。エンジニアの伊藤です。
Xamarin のアプリを Jenkins などでビルドする場合、コマンドラインからビルドしたいことがあると思います。.NET 系のエンジニアには、.csproj ファイルは MSBuild というビルドエンジンのビルド構成ファイルそのものであるというのはよく知られており、これを msbuild コマンドや、xbuild コマンドに与えることでビルドができます。
今回は、Mac で xbuild コマンドを使う方法で、Xamarin.iOS / Xamarin.Android のアプリをビルドする方法をご紹介します。
基本のビルド
Xamarin.iOS でビルドして、ipa ファイルを作成するには、以下のようなコマンドを作成します。この例では Configuration は Release を指定していますが、ビルドしたい構成を指定してください。(この記事の中では \ をつけて改行を入れて折り返していますが、実際は \ をつけずに 1 行で書くことも問題なくできます)
また、「ビルドする csproj ファイルまたは sln ファイル」の部分は、カレントディレクトリに csproj ファイルや sln ファイルが 1 つしかない場合は省略することができます。
xbuild /p:Configuration=Release /p:Platform=iPhone \ /p:BuildIpa=true (ビルドする csproj ファイルまたは sln ファイル)
Xamarin.iOS のアプリビルド時に、`lipo: error: unable to find utility “lipo”, not a developer tool or in PATH` というログが出力されてビルドが失敗することがあります。これは、Xcode のパスが解決できない場合に表示されます。以下のように、DEVELOPER_DIR 環境変数をセットするとこの問題を解消できます。
export DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer"
また、iOS の csproj ファイルを指定してビルドした場合、`’OutputPath’ property is not set for this project.` のようなエラーが出ることがあります。これは、参照している PCL のプロジェクトの Platform に iPhone の指定がないから、ということが多いです。sln ファイルを指定してビルドするとこれを回避できます。
Xamarin.Android で APK ファイルをビルドするときは、以下のようなコマンドを使います。こちらは Xamarin.Android の csproj ファイルを指定しないといけないことに注意してください。
xbuild /p:Configuration=Release /t:SignAndroidPackage \ (ビルドする Xamarin.Android の csproj ファイル)
例えば、Xamarin.Forms のアプリから、IPA も APK も生成したい場合、以下の 2 つのコマンドを使うこととなります。
$ xbuild /p:Configuration=Release /p:Platform=iPhone \ /p:BuildIpa=true MyFormsApp.sln $ xbuild /p:Configuration=Release /t:SignAndroidPackage \ Droid/MyFormsApp.Droid.csproj
設定をコマンドラインで上書きする
実は、xbuild のコマンドラインの /p:XXX=YYY は、csproj の中にある XXX の値を YYY に上書きするという指定なのです。csproj を開いてみると、このような設定が見えます。
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'InHouse|iPhone' "> <DebugSymbols>true</DebugSymbols> <Optimize>true</Optimize> <OutputPath>bin\iPhone\InHouse</OutputPath> <DefineConstants></DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> <ConsolePause>false</ConsolePause> <CodesignKey>iPhone Distribution: Fenrir Inc.</CodesignKey> <MtouchUseSGen>true</MtouchUseSGen> <MtouchUseRefCounting>true</MtouchUseRefCounting> <MtouchFloat32>true</MtouchFloat32> <CodesignEntitlements>Entitlements.plist</CodesignEntitlements> <MtouchLink>SdkOnly</MtouchLink> <MtouchArch>ARMv7, ARM64</MtouchArch> <MtouchHttpClientHandler>NSUrlSessionHandler</MtouchHttpClientHandler> <MtouchTlsProvider>Default</MtouchTlsProvider> <PlatformTarget>x86</PlatformTarget> <MtouchNoSymbolStrip>true</MtouchNoSymbolStrip> <MtouchUseLlvm>true</MtouchUseLlvm> <MtouchUseThumb>true</MtouchUseThumb> <CodesignProvision>3a836f0a-cc98-4283-8159-1f26826de6ed</CodesignProvision> <BuildIpa>true</BuildIpa> </PropertyGroup>
例えば、Xamarin.iOS の署名設定をコマンドラインから変えたいということがあると思います。プロビジョニングプロファイルの指定が CodesignProvision、署名する鍵の名前が CodesignKey ですので、このようにすれば良いでしょう。
xbuild /p:Configuration=Release /p:Platform=iPhone /p:BuildIpa=true\ /p:CodesignProvision=3a836f0a-cc98-4283-8159-1f26826de6ed \ /p:CodesignKey="iPhone Distribution: Fenrir Inc." MyFormsApp.sln
シェルで無理矢理解決する
MSBuild の機能だけだとイマイチ満足に目的を達成できないことがあります。例えば、ビルド構成ごとに iOS アプリの Bundle Identifier を書き換えたい時などです。カスタムタスクを作るというのが MSBuild 的には正攻法だとは思いますが、手っ取り早くシェルスクリプトを書いてなんとかしてしまうこともできます。残念ながら Mac の Xamarin Studio ではこれを編集することができないので、csproj ファイルを直接テキストエディタで開いて、PreBuildEvent を書くことで対応できます。
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhone' "> <!-- 中略 --> <PreBuildEvent>[コマンド]</PreBuildEvent> </PropertyGroup>
また、Condition 属性を合わせて使うことで、Windows と Mac で違うコマンドを実行させることもできるでしょう。
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhone' "> <!-- 中略 --> <PreBuildEvent Condition="$(OS) == 'Windows_NT'">[Windows でビルドするときに実行するコマンド]</PreBuildEvent> <PreBuildEvent Condition="$(OS) != 'Windows_NT'">[Windows 以外でビルドするときに実行するコマンド]</PreBuildEvent> </PropertyGroup>
Xamarin Studio や Visual Studio などの IDE も内容を変更してしまうというところで少し不安だったのですが、実際に直接編集したりしてみると仕組みを理解する手助けになりました。git の変更履歴でも確認できるので、そこまで心配することもないですし、実際にやってみると IDE は変更した値しか反映していないことがわかりました。
MSBuild リファレンスなども参考に、色々試してみてはいかがでしょうか。
フェンリルのオフィシャル Twitter アカウントでは、フェンリルプロダクトの最新情報などをつぶやいています。よろしければフォローしてください!