(PR)Xamarin.Formsアプリケーションの共通プロジェクトで、ビルドイベント時にmsbuildの変数を参照する方法

Xamarin.FormsアプリケーションでAPI keyなど、Gitレポジトリーにコミットしたくない情報を管理したい時があります。

この場合、定数を記述したソースファイルをGitレポジトリーにコミットせずに、Visual StudioのビルドイベントやCIによるビルド時の処理で、ファイルをリネームした後ビルドするというプラクティスがあります。

qiita.com

この場合、プロジェクトの.csprojに次のような記述を追加します。

<PropertyGroup Condition=" '$(OS)' == 'Windows_NT' ">
  <PreBuildEvent>if not exist "$(ProjectDir)Models\Env.cs" copy /Y "$(ProjectDir)Models\Env.cs.sample" "$(ProjectDir)Models\Env.cs"</PreBuildEvent>
</PropertyGroup>
<PropertyGroup Condition=" '$(OS)' != 'Windows_NT' And '$(Configuration)'!='appcenter' ">
  <PreBuildEvent>rsync -u "$(ProjectDir)Models/Env.cs.sample" "$(ProjectDir)Models/Env.cs"</PreBuildEvent>
</PropertyGroup>

しかし、この記述を、プラットフォーム(Android/iOS等)に対する共通プロジェクトに対して記述した場合、次のようなエラーが発生し、ビルドに失敗します。

1>------ すべてのリビルド開始: プロジェクト:CalendarViewer, 構成: Debug Any CPU ------
1>指定されたパスが見つかりません。
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets(1336,5): error MSB3073: コマンド "if not exist "Models\Env.cs" copy /Y "Models\Env.cs.sample" "Models\Env.cs"" はコード 1 で終了しました。
1>プロジェクト "CalendarViewer.csproj" のビルドが終了しました -- 失敗。

f:id:setoazusa:20190412141724p:plain

これは、Xamarin.Formsアプリケーションの共通プロジェクト(ここではCalenadarViewer.csproj)は .NET.Sdkプロジェクトであり、そのままでは.csprojで記述している${ProjectDir}等のmsbuildの変数が参照できないためです(下記リンク先参考)

stackoverflow.com

github.com

この問題に対応するには、.csprojの次の部分を、このように修正します。

  • 修正前
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <ProduceAssemblyReference>true</ProduceAssemblyReference>
    <Configurations>Debug;Release;appcenter</Configurations>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <DebugType>pdbonly</DebugType>
    <DebugSymbols>true</DebugSymbols>
  </PropertyGroup>
(以降略)
  • 修正後
<Project>
  <Import Sdk="Microsoft.NET.Sdk" Project="Sdk.props" />
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <ProduceAssemblyReference>true</ProduceAssemblyReference>
    <Configurations>Debug;Release;appcenter</Configurations>
  </PropertyGroup>
  <Import Sdk="Microsoft.NET.Sdk" Project="Sdk.targets" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <DebugType>pdbonly</DebugType>
    <DebugSymbols>true</DebugSymbols>
</PropertyGroup>
(以降略)

このことにより、ビルドイベント内でmsbuildの変数$(ProjectDir)が参照可能になり、 Visual Studio上でのビルドが成功するようになります。

f:id:setoazusa:20190412141845p:plain

Microsoftの運営するアプリケーション向けの開発サービスであるVisual Studio App Centerでは、 .csprojと同じ階層にappcenter-pre-build.shを作成し、スクリプト内でファイルのリネームを行うことにより、同様の処理を行うことが出来ます。

#!/usr/bin/env bash

set -x

if [ $APPCENTER_BRANCH = "master" ]; then
  cp -f ../CalendarViewer/Models/Env.cs.prod ../CalendarViewer/Models/Env.cs
else
  cp -f ../CalendarViewer/Models/Env.cs.dev ../CalendarViewer/Models/Env.cs
fi

なお、App Center上でビルドスクリプトの処理を有効にするには、次の画面の通り、App Centerがスクリプトを認識して、「Build Script」の項目に表示されている状態で、一度「Save」ないし「Save & Build」のボタンを選択して、ビルドスクリプトの設定を有効にすることが必要です。

f:id:setoazusa:20190412142005p:plain

以上、今度2019/4/14開催される技術書典6 に出展する新刊「Visual Studio App CenterではじめてのXamarin.FormsCI/CD」に書いた内容の解説でした。BOOTHで通信販売も開始しているのでよろしくお願いします!

techbookfest.org

fieldnotes.booth.pm