(:3[kanのメモ帳]

個人ゲーム開発者kan.kikuchiのメモ的技術ブログ。月木更新でUnity関連がメイン。

(:3[kanのメモ帳]


本ブログの運営者kan.kikuchiが個人で開発したゲームです!

    

XcodeAPIの使い方【Unity】【XcodeAPI】【エディタ拡張】


このエントリーをはてなブックマークに追加



この記事でのバージョン
Unity 5.1.0f3 Personal

はじめに

以前、XcodeAPIを使って諸々の設定をするXcodeProjectUpdaterというものを作ったのですが、




文量が多くなってしまったため、XcodeAPIを実際にどう使っているかという説明を省きました。

なので今回は、そのXcodeAPIの説明となります。


説明には上記XcodeProjectUpdaterのコードを使いますので、

そちらを参照しながら読むと分かり易いと思います。


OnPostprocessBuild

XcodeAPIはXcodeプロジェクトを作成した後、そのプロジェクトに対して使います。


Xcodeプロジェクトを作成した後、

つまりビルドが終わった後に処理されるのがOnPostprocessBuildというメソッドです。

(と言うよりPostProcessBuildを上部に付けたメソッド?)

//ビルド後に呼ばれる buildTargetがビルドしたプラットフォーム、プロジェクトを出力したパス
[PostProcessBuild (100)] //100の所で実行順を指定、小さい方が先に実行
private static void OnPostprocessBuild(BuildTarget buildTarget, string buildPath){

}


OnPostprocessBuildは複数あっても問題ないので、AssetStoreで買った物など、

複数の設定スクリプトがある場合は実行順序を考慮に入れる必要があります。


その時はPostProcessBuildの後に続く数字で実行順を指定しましょう。(なくても可)


Xcodeプロジェクトの読み込み

XcodeAPIではPBXProjectというクラスでXcodeプロジェクトを編集します。


Unity - Scripting API:PBXProject


Xcodeプロジェクトとは拡張子が.xcodeprojになってるやつの事です。


f:id:kan_kikuchi:20151013135437p:plain


Xcodeプロジェクトの読み込み方は以下の通りです。

//Xcodeプロジェクトへのパスを取得 buildPathはOnPostprocessBuildの引数
string pbxProjPath = PBXProject.GetPBXProjectPath(buildPath);

//インスタンスを作成
PBXProject pbxProject = new PBXProject();

//プロジェクトの読み込み 
pbxProject.ReadFromString(File.ReadAllText(pbxProjPath));


プロジェクトファイルのパスを作成し、

それをPBXProjectのインスタンスに読み込ませるといった形です。


Xcodeプロジェクトのプロパティ設定

PBXProjectを使ったプロパティの設定方法は以下の通りです。

//プロパティ設定時に必要となるターゲットIDの取得
string targetGuid = pbxProject.TargetGuidByName(PBXProject.GetUnityTargetName());

//コンパイラフラグ設定
//fileGuidが設定したいファイルのID compileFlagsが設定するコンパイラフラグ
string fileGuid = pbxProject.FindFileGuidByProjectPath(targetPath);//targetPathが設定したいファイルへのパス
pbxProject.SetCompileFlagsForFile(string targetGuid, string fileGuid, List<string> compileFlags);

//フレームワーク追加
//frameworkにフレームワークの名前を拡張子付きで設定、weak は true だと required、false だと optional になる
pbxProject.AddFrameworkToProject(string targetGuid, string framework, bool weak);

//その他のプロパティ設定
//nameが変更したいプロパティ名、valueがプロパティに設定する値
pbxProject.AddBuildProperty(string targetGuid, string name, string value); //新規
pbxProject.SetBuildProperty(string targetGuid, string name, string value);  //上書き
pbxProject.UpdateBuildProperty(string targetGuid, string name, string[] addValues, string[] removeValues); //複数更新

//書き出し
//pbxProjPathは読み込んだ時と同じやつ
File.WriteAllText(pbxProjPath, pbxProject.WriteToString());


XcodeAPIを使えばこれらのメソッドを使うだけで、

プロジェクトの設定を変えられるわけですね。簡単!


ただし、一つ注意点があり、

valueで真偽値を設定する場合、"true" or "false"では無く、"YES" or "NO"になります。

//BitCodeの設定
pbxProject.SetBuildProperty(targetGuid, XcodeProjectSetting.ENABLE_BITCODE_KEY, setting.EnableBitCode ? "YES" : "NO"); 


"YES"という文字列でなければ、全て偽となるようです。


Xcodeプロジェクトのプロパティ名

先ほどXcodeプロジェクトのプロパティを変更する際に、nameでプロパティ名を指定していました。


10.27追記

このプロパティ名の確認方法ですが、以前書いた方法より簡単なものがありました。


f:id:kan_kikuchi:20151027135147p:plain


画像の通り、項目を選んでQuick Helpという所で確認できます。

10.27追記終わり


このプロパティ名は、プロジェクトファイルを右クリックし、パッケージ内容を表示

した中にあるproject.pbxprojに書いてあります。

f:id:kan_kikuchi:20151014135844p:plain
f:id:kan_kikuchi:20151014140137p:plain


このproject.pbxprojをテキストエディタなどで開き、それっぽい単語で検索すると


f:id:kan_kikuchi:20151014140351p:plain


ENABLE_BITCODEなど、プロパティ名を見つける事ができます。


見ての通りちょっと面倒です。

もしや他に正攻法が……?


ファイル及びディレクトリのコピー

C#でのディレクトリ及びファイルのコピーについては以下の記事をご参照ください。

ファイルをコピーするメソッドはあるけどディレクトリをコピーするメソッドは無いよってだけですが。



また、ここの説明で使うコードはXcodeProjectUpdaterDirectoryProcessor.csにあります。


Xcodeのプロジェクトへファイル及びディレクトリのコピー するには、

ただファイルをコピーするだけでなく

AddFileToBuildを使ってプロジェクトに追加しなくてはなりません。

//ファイルのコピー
//filePathが元あった場所、copyPathがコピーする先
File.Copy(filePath, copyPath); 

//プロジェクトへファイルの追加(ディレクトリもAddFileToBuildを使う)
pbxProject.AddFileToBuild(targetGuid, pbxProject.AddFile(relativePath, relativePath, PBXSourceTree.Source)); 


copyPathとrelativePathは同じ場所を示しているのですが、

copyPathはコピー先への絶対パスで、

relativePathはビルドしたディレクトリからのコピー先への相対パス になります。


例をあげると以下のような感じです。

copyPath
/Users/UserName/Documents/UnityProject/iOS/CopyToXcode/Test1/test1.txt

relativePath
Test1/test1.txt


コピーの方法は以上ですが、コピーの際にいくつか注意点があります。


まず、ディレクトリ内の全ファイルをコピーさせると、

余分なファイルまでXcodeプロジェクトに入ってしまうので、以下のようにするといいかもしれません。

//.metaファイルはコピーしない
string extension = Path.GetExtension (filePath);
if(extension == ExtensionName.META){
  continue;
} 

//隠しファイルはコピーしない .DS_Storeとか
if(fileName[0] == '.'){
  continue;
}


また、ディレクトリ内全コピーだとフレームワークなどもディレクトリ扱いになってしまうので、

.Framework.bundleがついてるディレクトリは内部のファイルを一つずつ追加せず、

全ファイルコピーした後、ディレクトリごと追加する必要があります。


さらにプロジェクトに追加したたけだけでは、

フレームワークパスなどディレクトリへのパスを設定されないので

自力でやる必要があります。


フレームワークサーチパス設定例

pbxProject.AddBuildProperty(
  targetGuid, 
  "FRAMEWORK_SEARCH_PATHS""$(PROJECT_DIR)/" + currentDirectoryPath
); 

Xcode上でのフレームワークサーチパスの場所

f:id:kan_kikuchi:20151015135054p:plain


ライブラリーサーチパス設定例

pbxProject.AddBuildProperty(
  targetGuid, 
 "LIBRARY_SEARCH_PATHS" 
  "$(PROJECT_DIR)/" + currentDirectoryPath
); 

Xcode上でのライブラリーサーチパスの場所

f:id:kan_kikuchi:20151015135049p:plain


一度作ると便利ですが、結構面倒ですね……。


Info.plist読み込み

PBXProjectではInfo.plist部分の設定は変更できません。

なので、Info.plistの編集にはPlistDocumentを使います。


Unity - Scripting API:PlistDocument


また、ここの説明で使うコードはXcodeProjectUpdaterInfoPlistProcessor.csにあります。


plistの読み込み方は以下の通りです。

//Xcodeプロジェクトへのパスを取得 buildPathはOnPostprocessBuildの引数
string plistPath = Path.Combine(buildPath, "Info.plist" );

//インスタンスを作成
PlistDocument plist = new PlistDocument() ;

//plistの読み込み 
plist.ReadFromFile(plistPath) ;


流れはXcodeプロジェクトの時と全く同じです。


Info.plist編集

まず、plist.rootでInformation Property Listを取得できます。

Listという名前だけどDictionaryです。


f:id:kan_kikuchi:20151016135232p:plain


さらにplist.root["Key"]で各要素を取得し、.As◯◯でPlistElement◯◯型に変換します。

例えば、URL typesのURL identifier を取得する場合は以下のようになります。


f:id:kan_kikuchi:20151016135539p:plain

PlistElementArray urlTypes = plist.root["CFBundleURLTypes"].AsArray();
PlistElementDict  itmeDict = urlTypes.values[0].AsDict();
string identifier = itmeDict ["CFBundleURLName"].AsString ();  


ただし、要素が存在しないとエラーがでます

また、ただCreateをすると既にあるデータに上書きしてしまうので、

ContainsKeyを使って要素が存在するかを判断する必要があります。

PlistElementArray urlTypes;

//keyがあれば取得
if(plist.root.values.ContainsKey("CFBundleURLTypes")){
  urlTypes = plist.root["CFBundleURLTypes"].AsArray();
}
//keyが無ければ新規作成
else{
  urlTypes = plist.root.CreateArray ("CFBundleURLTypes");
} 


最後に、編集が終わったらplist.WriteToFile(plistPath); で書き出します。


Info.plistのkey

10.27追記

各要素のkeyを以前書いた方法より簡単に確認する方法ありました。


f:id:kan_kikuchi:20151027135338j:plain


画像の通り、項目を選んでQuick Helpという所で確認できます。

10.27追記終わり


各要素のkeyは、Info.plistをテキストエディタで開いて

<key></key>で囲まれている所に記載されています。


f:id:kan_kikuchi:20151016140038p:plain


Xcodeプロジェクトと比べて、こっちは簡単に確認できます。


おわりに

XcodeProjectUpdaterで使ってるXcodeAPIの機能は以上です。

他にも機能はありそうなんですが、現状これらの機能で困ってはいない感じです(:3っ)∋〜。