[Xamarin] DebugビルドとReleaseビルドでアプリケーションID(Bundle ID)とアプリ名を切り替える

Xamarin製のAndroidとiOSアプリについて、DebugビルドとReleaseビルドでアプリケーションID(BundleID)を変えて別アプリにしてみました。
2020.12.11

数年前に作成し、たまに更新しているXamarin製の個人作アプリがあります。 シンプルなアプリなのでDebugとRelease用に分けないで開発していましたが、通信してデータ取得するようになると、下記のように開発したくなりました。

  • Debug用アプリ:WebAPI(Dev)を使う
  • Release用のアプリ:WebAPI(Prod)を使う

WebAPIをデプロイするとき、Debug用のアプリをビルド&インストールして動作確認したあと、Release用のアプリをビルド&インストールするのがめんどくさいのです……。 最初からDebug用とRelease用のアプリが2つあれば楽ちんですよね!

本記事はXamarin Advent Calendar 2020の11日目です。

まずは基本となるアプリを作成する

プロジェクトを新規作成する

適当なプロジェクトを新規作成します。

Xamarinプロジェクトを新規作成する

Xamarinプロジェクトを新規作成する

アプリのテンプレートはポップアップを選択します。

アプリのテンプレートでポップアップを選択する

Androidアプリの場合

AndroidManifest.xmlをRelease用とDebug用に分ける

既存のAndroidManifest.xmlを複製し、Release用とDebug用とします。

cp BuildSample.Android/Properties/AndroidManifest.xml BuildSample.Android/Properties/AndroidManifest_release.xml
mv BuildSample.Android/Properties/AndroidManifest.xml BuildSample.Android/Properties/AndroidManifest_debug.xml

Debug用のAndroidManifest.xmlにあるアプリケーションIDとアプリ名を編集する

AndroidManifest_debug.xmlpackageを編集して、アプリケーションIDにdebugを含めるようにします。

  • 変更前: com.companyname.buildsample
  • 変更後: com.companyname.buildsample.debug

AndroidManifest_debug.xml

-<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.buildsample">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.buildsample.debug">

続いて、アプリ名をDebugにして分かりやすいようにします。これは設定画面のアプリ一覧で表示されるようです。

  • 変更前: BuildSample.Android
  • 変更後: Debug

AndroidManifest_debug.xml

-<application android:label="BuildSample.Android" android:theme="@style/MainTheme"></application>
+<application android:label="Debug" android:theme="@style/MainTheme"></application>

MainActivityのAndroidアプリ名をDebugにする

MainActivityにあるLabelも修正します。これは通常時のアプリ名として表示されるようです。 下記は強引に切り分けていますが、Labelの記述を削除してもOKです。むしろAndroidManifestのみになるため、削除するほうが良いかもですね。

MainActivity.cs

--- a/BuildSample.Android/MainActivity.cs
+++ b/BuildSample.Android/MainActivity.cs
  namespace BuildSample.Droid
  {
+ #if DEBUG
-     [Activity(Label = "BuildSample", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize )]
+ #else
+     [Activity(Label = "Debug", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize )]
+ #endif
      public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
      {
          ...
      }
  }

今回は行いませんが、アイコンも変えるとより分かりやすくなります。

BuildSample.Android.csprojでAndroidManifest.xmlを使い分ける

BuildSample.Android.csprojをエディタで開き、AndroidManifest関連を修正します。

PropertyGrouタグの修正

  1. <PropertyGroup>にある<AndroidManifest>...</AndroidManifest>を削除
  2. <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "><AndroidManifest>...debug用...</AndroidManifest>を追加
  3. <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "><AndroidManifest>...release用...</AndroidManifest>を追加

BuildSample.Android.csproj

--- a/BuildSample.Android/BuildSample.Android.csproj
+++ b/BuildSample.Android/BuildSample.Android.csproj

  <PropertyGroup>
    ...
-   <AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
    ...
  </PropertyGroup>

  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    ...
+   <AndroidManifest>Properties\AndroidManifest_debug.xml</AndroidManifest>
    ...
  </PropertyGroup>

  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+   <AndroidManifest>Properties\AndroidManifest_release.xml</AndroidManifest>
  </PropertyGroup>

ItemGroupタグの修正

  1. <ItemGroup>にある<None Include="Properties\AndroidManifest.xml" />を削除
  2. Debug用の<ItemGroup>を追加
  3. Release用の<ItemGroup>を追加

BuildSample.Android.csproj

--- a/BuildSample.Android/BuildSample.Android.csproj
+++ b/BuildSample.Android/BuildSample.Android.csproj

  <ItemGroup>
-   <None Include="Properties\AndroidManifest.xml" />
  </ItemGroup>

+ <ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+   <None Include="Properties\AndroidManifest_debug.xml" />
+ </ItemGroup>

+ <ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+   <None Include="Properties\AndroidManifest_release.xml" />
+ </ItemGroup>

動作確認(Android)

Debug用とRelease用のアプリが分かれています。

Debug用とRelease用のアプリ

iOSアプリの場合

AndroidみたいにInfo.plistの名前を変更して使い分けると、ビルドエラーが発生します。

Info.plistが無いのでビルドエラー

そのため、Debug用とRelease用を用意しておき、ビルド時にInfo.plistに置き換えることにします。

Info.plistをRelease用とDebug用に分ける

Debug用とRelease用のInfo.plistを作ります。

cp BuildSample.iOS/Info.plist BuildSample.iOS/Info_Debug.plist
cp BuildSample.iOS/Info.plist BuildSample.iOS/Info_Release.plist

オリジナルのInfo.plistは残しておき、Debug用と同じ内容にしておきます。こうすることによって、開発時のDebugビルドでGit差分が出ないようにします。 Debugビルドするたびに「Info.plistが更新された」「Info.plistが新しくできた」というGit差分が出たらめんどくさいからです。

Debug用のBundle IDを変更する

info.plistInfo_Debug.plistにあるBundle IDをデバッグ用に変更します。

 <dict>
 	 ...
- 	 <string>xxx.yyy.zzz.buildsample</string>
+ 	 <string>xxx.yyy.zzz.buildsample.debug</string>
     ...
 </dict>

Debug用のアプリ名にする

Info.plistInfo_Debug.plistにあるアプリ名をデバッグ用に変更します。

 <dict>
 	 ...
	 <key>CFBundleDisplayName</key>
-	 <string>BuildSample</string>
+	 <string>Debug</string>
     ...
 </dict>

ビルド時にInfo.plistを上書きする

ビルド時にInfo_Debug.plistInfo_Release.plistのどちらかをInfo.plistに上書きする処理を作成します。共通プロジェクトのプロパティを開き、「ビルド前イベントのコマンドライン」に下記を追加します。 細かいPathは各自の環境に合わせてください。

cp "$(SolutionDir)$(ProjectName).iOS\Info_$(ConfigurationName).plist" "$(SolutionDir)$(ProjectName).iOS\Info.plist"
touch "$(SolutionDir)$(ProjectName).iOS\Info.plist"

ビルドイベントを設定する

動作確認(iOS)

Debug用とRelease用のアプリが分かれました!

Debug用とRelease用のアプリ

さいごに

1年以上前にGoogleServiceのJSONファイルで似たようなことをやっていたのですが、今更ながら気づいて試してみました。 参考になれば幸いです。