Unity から Export した iOS なアプリの Bundle Display Name を自動設定してみる

# 背景

Unity から出力した iOS プロジェクトに、ローカライズしたアプリ名 (CFBundleDisplayName) を付与するのに苦労したので、その辺のお話しを書き殴る。

<span style="color: #666666;">まぁ、元同僚から「ぼすけて！」って言われたので書いてるのは内緒ｗ <del>べ、別に貴方のためなんかじゃないんだからっ！</del></span>

# 概要

大前提として PostProcessBuild で対応する。

流れとしては以下のような感じ。

1. InfoPlist.strings に各言語でのアプリ名を書き込む
1. `<language>.lproj/` ディレクトリに格納
1. Unity-iPhone.xcodeproj/project.pbxproj を弄る
	1. KnownRegion に言語を追加
	1. 生成した InfoPlist.strings を VariantGroup として束ねる

# 詳細

先ず、事前準備として、 [XCodeEditor for Unity](https://github.com/dcariola/XCodeEditor-for-Unity) という .pbxproj ファイルを弄れるアセットを入れておく。

ただし、上記のリポジトリは最近メンテされてないっぽくて、素のままだと今回やりたい処理ができないので、ちょっと手を入れたモノを [XCodeEditor for Unity (forked by monry)](https://github.com/monry/XCodeEditor-for-Unity) に置いておいたので、今回はコッチを使う。

## InfoPlist.strings に書き込む

内容は

```InfoPlist.strings
CFBundleDisplayName = "アプリ名";
```

ってな感じ。

この辺は頑張って C# ガリガリ書いてください。

## `<language>.lproj/` ディレクトリに格納

まぁ、この辺も普通に C# で書けば良いんじゃないかな。

出力先としては PostProcessBuild に渡される `path + "<language>.lproj/InfoPlist.strings"` とかで良いかと。

## 言語追加しつつ、VariantGroup として束ねる

この投稿のメインテーマ。

基本的には、`PBXVariantGroup` 型の変数にファイルの参照を突っ込んで、.pbxproj に書き込むってな流れ。

XCodeEditor for Unity の改修点としては以下の通り。

* 言語の追加を行うヘルパメソッドを `PBXProject` クラスに追加した
* PBXVariantGroup を PBXGroup のサブクラスとして定義し直した
	* `XCodeEditor.XCProject.AddFile()` の第2引数に PBXGroup のインスタンスを渡せば、その下に追加してくれるような実装になっているので、その処理をそのまま利用するため。

なので、その辺を利用して言語追加しつつ、生成した .strings ファイルをプロジェクトに食わせつつ VariantGroup の子要素として紐付ける感じ。

# コード

色々端折ってるけど、上記を纏めると以下のようなコードになる。はず。

```csharp:PostProcessBuild.cs
using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEditor.XCodeEditor;
using System.Collections;
using System.Collections.Generic;
using System.IO;

public static class PostProcessBuild {

	private static Dictionary<string, string> appNameMap = new Dictionary<string, string>() {
		{ "en", "HogeHoge" },
		{ "ja", "ほげほげ" },
	};

	[PostProcessBuild(100)]
	public static void OnPostProcessBuild(BuildTarget target, string path) {
		// 出力済のディレクトリを XCodeEditor に食わせる
		XCProject project = new XCProject(path);

		// VariantGroup 作成
		PBXVariantGroup infoPlist = project.GetVariantGroup("InfoPlist.strings");
		foreach (KeyValuePair<string, string> entry in appNameMap) {
			// 文字コードを変換しておく
			string appNameConverted = System.Text.Encoding.UTF8.GetString(
				System.Text.Encoding.Convert(
					System.Text.Encoding.Unicode,
					System.Text.Encoding.UTF8,
					System.Text.Encoding.Unicode.GetBytes(entry.Value)
				)
			);

			// 格納用ディレクトリ作成
			if (!Directory.Exists(Path.Combine(path, string.Format("{0}.lproj", entry.Key)))) {
				Directory.CreateDirectory(Path.Combine(path, string.Format("{0}.lproj", entry.Key)));
			}

			// InfoPlist.strings 作成
			StreamWriter w = new StreamWriter(Path.Combine(path, string.Format("{0}.lproj/InfoPlist.strings", entry.Key)), false);
			w.WriteLine(string.Format("CFBundleDisplayName = \"{0}\";", appNameConverted));
			w.Close();

			// KnownRegion に言語を追加
			project.project.AddKnownRegion(entry.Key);

			// ファイルの参照を追加
			project.AddFile(Path.Combine(path, string.Format("{0}.lproj/InfoPlist.strings", entry.Key)), infoPlist, "SOURCE_ROOT", true, false, string.Format("{0}.lproj/InfoPlist.strings", entry.Key));
		}

		// 上書き保存
		project.Save();
	}

}
```

なお、`BuildTarget` による処理の振り分けとか一切やってないので悪しからずｗ

あと、これの処理を連続でキックすると、重複してファイルが追加されてしまうので、その辺は巧いコト回避してくださいな。