UnityでのXcode設定をUnityEditorのスクリプトだけで自動化する

Unityが出力したiOS用プロジェクトの手動編集をなんとかしたいと考えていたら、同じような人がやはり多いようでいろいろな方法がブログエントリで紹介されていました。

調べた感じではCodeEditor-for-UnityxcodeprojというRubyのgemを使う方法が多くみられました。前者のライブラリは最近はメンテされていないようですし、後者の場合Rubyが必要になるということで広く導入しにくい(関係者全員にxcodeproj gem入れろとはいえない)ので別の方法がない限りできないかなーと思っていたら、なんとBitbucketにリポジトリを発見しました。

Unity-Technologies / XcodeAPI — Bitbucket https://bitbucket.org/Unity-Technologies/xcodeapi

Unity-Technologiesというアカウント名から察するに公式のツールだと考えて良さそうです。

このコードを使ってXcodeプロジェクト出力後にフレームワークを追加したり設定を変更するような処理を書いてみようと思います。

なお他の手段でできることがこのXcodeAPIではまだできないということがあるかもしれないのでその点は注意してください。

導入

準備はほとんど要らなくて、リポジトリからダウンロードしたファイルをUnityのプロジェクト内、Assets以下の好きなところに突っ込んでおけば大丈夫です。

ビルド後の処理を書く

Assets/Editorあたりのディレクトリに、例えばModifyXcodeProject.csという感じのスクリプトを配置します。

using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEditor.iOS.Xcode; // ←さっきいれたXcodeAPI
using System.Collections;
using System.IO;

public class XcodeProjectMod : MonoBehaviour
{

    // ちょっとしたユーティリティ関数(http://goo.gl/fzYig8を参考)
    internal static void CopyAndReplaceDirectory(string srcPath, string dstPath)
    {
        if (Directory.Exists(dstPath))
            Directory.Delete(dstPath);
        if (File.Exists(dstPath))
            File.Delete(dstPath);

        Directory.CreateDirectory(dstPath);

        foreach (var file in Directory.GetFiles(srcPath))
            File.Copy(file, Path.Combine(dstPath, Path.GetFileName(file)));

        foreach (var dir in Directory.GetDirectories(srcPath))
            CopyAndReplaceDirectory(dir, Path.Combine(dstPath, Path.GetFileName(dir)));
    }

    [PostProcessBuild]
    public static void OnPostprocessBuild(BuildTarget buildTarget, string path)
    {
        if (buildTarget == BuildTarget.iPhone)
        {
            string projPath = PBXProject.GetPBXProjectPath(path);
            PBXProject proj = new PBXProject();
            
            proj.ReadFromString(File.ReadAllText(projPath));
            string target = proj.TargetGuidByName("Unity-iPhone");

            // システムのフレームワークを追加
            proj.AddFrameworkToProject(target, "AssetsLibrary.framework", false);
            
            // 自前のフレームワークを追加
            CopyAndReplaceDirectory("Assets/Lib/mylib.framework", Path.Combine(path, "Frameworks/mylib.framework"));
            proj.AddFileToBuild(target, proj.AddFile("Frameworks/mylib.framework", "Frameworks/mylib.framework", PBXSourceTree.Source));

            // ファイルを追加
            var fileName = "my_file.xml";
            var filePath = Path.Combine("Assets/Lib", fileName);
            File.Copy(filePath, Path.Combine(path, fileName));
            proj.AddFileToBuild(target, proj.AddFile(fileName, fileName, PBXSourceTree.Source));

            // Yosemiteでipaが書き出せないエラーに対応するための設定
            proj.SetBuildProperty(target, "CODE_SIGN_RESOURCE_RULES_PATH", "$(SDKROOT)/ResourceRules.plist");

            // フレームワークの検索パスを設定・追加
            proj.SetBuildProperty(target, "FRAMEWORK_SEARCH_PATHS", "$(inherited)");
            proj.AddBuildProperty(target, "FRAMEWORK_SEARCH_PATHS", "$(PROJECT_DIR)/Frameworks");
            
            // 書き出し
            File.WriteAllText(projPath, proj.WriteToString());
        }
    }
}

iOSプロジェクト書き出し後に[PostProcessBuild]属性を付けたメソッドが呼ばれます。そこでXcodeプロジェクトの本体である.pbxprojを編集するためのコードを書けばOKです。

上のコードでは

これらのことをやっています。

このコードもXcodeAPIもソース管理に入れてしまえば誰でも使うことができるので他の方法よりも良いかもしれません。