背景
Unity から出力した iOS プロジェクトに、ローカライズしたアプリ名 (CFBundleDisplayName) を付与するのに苦労したので、その辺のお話しを書き殴る。
まぁ、元同僚から「ぼすけて!」って言われたので書いてるのは内緒w べ、別に貴方のためなんかじゃないんだからっ!
概要
大前提として PostProcessBuild で対応する。
流れとしては以下のような感じ。
- InfoPlist.strings に各言語でのアプリ名を書き込む
-
<language>.lproj/
ディレクトリに格納 - Unity-iPhone.xcodeproj/project.pbxproj を弄る
- KnownRegion に言語を追加
- 生成した InfoPlist.strings を VariantGroup として束ねる
詳細
先ず、事前準備として、 XCodeEditor for Unity という .pbxproj ファイルを弄れるアセットを入れておく。
ただし、上記のリポジトリは最近メンテされてないっぽくて、素のままだと今回やりたい処理ができないので、ちょっと手を入れたモノを XCodeEditor for Unity (forked by monry) に置いておいたので、今回はコッチを使う。
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 の子要素として紐付ける感じ。
コード
色々端折ってるけど、上記を纏めると以下のようなコードになる。はず。
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
による処理の振り分けとか一切やってないので悪しからずw
あと、これの処理を連続でキックすると、重複してファイルが追加されてしまうので、その辺は巧いコト回避してくださいな。