📖
【Unity/iOS】Unityからのビルド時に、XCode上の設定を自動で行う
概要
- Unity(UaaLとして利用)をiOSプラットフォームで書き出し、XCodeでビルドする。その際、XCode上で行ういくつかの設定を、Unityからの出力段階でC#コードから自動で行うようにしたい。
設定内容
UnityFrameworkのターゲットに対し、以下4つの変更を行いたい。
- Build SettingsのENABLE_BITCODEをNOに変更する
- Build SettingsのOther Linker Flagsに
-ld64
を追加する - Unity-iPhone/DataフォルダのTarget MembershipをUnity-iPhoneからUnityFrameworkに変更する
- Unity-iPhone/Libraries/Plugins/iOS/NativeCallProxy.hのTarge MembershipのUnityFrameworkにおける設定をProjectからPublicに変更する
これらの変更を行いたい背景
- 1: ボイスチャットライブラリでVivoxを導入したところビルド時にこの設定を行わないとエラーが出力されるようになった。
- 2: XCode15でビルドする際に必要となった。
- 3と4: UaaLを利用する際の必要な設定。UnityのサンプルプロジェクトのREADME参照
3の変更
4の変更
- これらの設定は
Unity-iPhone.xcodeproj/project.pbxproj
ファイルが管理している。よって変更による差分もこのファイルに現れる。
具体的な変更用C#コード
1と2について(Build Settingsの変更)
project.pbxprojに現れる差分について
- ENABLE_BITCODEの差分
-
ENABLE_BITCODE = NO;
が追加
-
- Other Linker Flugsの差分
-
"-ld64"
が追加
-
- 上記の変更が4箇所で行われる。
-
Release
,ReleaseForProfiling
,ReleaseForRunning
,Debug
-
- ビルドが完了した際に呼び出されるEditorスクリプトを作成
#if UNITY_IOS
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEditor.iOS.Xcode;
using System.IO;
using System.Text.RegularExpressions;
namespace MyProject.Editor
{
public static class PostBuildProcessorForiOS
{
[PostProcessBuild]
public static void OnPostProcessBuild(BuildTarget buildTarget, string path)
{
if (buildTarget != BuildTarget.iOS) return;
// Xcodeプロジェクトファイルを読み込み
var projectPath = PBXProject.GetPBXProjectPath(path);
var pbxProject = new PBXProject();
pbxProject.ReadFromFile(projectPath);
var unityFrameworkTargetGuid = pbxProject.GetUnityFrameworkTargetGuid();
// 各種設定の適用
pbxProject.SetBuildProperty(unityFrameworkTargetGuid, "ENABLE_BITCODE", "NO");
pbxProject.AddBuildProperty(unityFrameworkTargetGuid, "OTHER_LDFLAGS", "-ld64");
// 保存
File.WriteAllText(projectPath, pbxProject.WriteToString());
}
}
}
#endif
3について(DataフォルダのTarget Membership)
project.pbxprojに現れる差分について
- GUIDが変更される。この差分はファイルの上の方に出力される
- 9D9DE4EA221D84E60049D9A1 /* Data in Resources */ = {isa = PBXBuildFile; fileRef = AA31BF961B55660D0013FB1B /* Data */; };
+ 871CEA6D2B3FAD7600FD76CB /* Data in Resources */ = {isa = PBXBuildFile; fileRef = AA31BF961B55660D0013FB1B /* Data */; };
- 加えて、以下の画像の箇所も変更される。
- 画像で言う、上側のResource(
1D60588D0D05DD3D006BFB54
)がUnity-iPhone、下側のResource(9D25AB9B213FB47800354C27
)がUnityFrameworkのGUIDと思われる。
- 画像で言う、上側のResource(
- 上記のスクリプトの中の
// Xcodeプロジェクトファイルを読み込み
と// 保存
の間に以下のコードを挟むと実現可能。
var mainTargetGuid = pbxProject.GetUnityMainTargetGuid();
var dataDirGuid = pbxProject.FindFileGuidByProjectPath("Data");
pbxProject.RemoveFileFromBuild(mainTargetGuid, dataDirGuid);
pbxProject.AddFileToBuild(unityFrameworkTargetGuid, dataDirGuid);
- ただし、ビルドした後の挙動としては問題がないのだが、XCode上で一度Dataの設定を変更し(例えばチェックボックスを外すなど)、再度戻した時に、GUIDが変更されるなどの差分が発生する。
- 現状、そのことによる影響が判明していないため、自分自身はDataの自動変更はいったんコメントアウトしている。
4について(NativeCallProxy.hをPublicに変更)
project.pbxprojに現れる差分について
- F00448D59F32A5359C57B609 /* NativeCallProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = B813F2A4838599F922071197 /* NativeCallProxy.h */; };
+ F00448D59F32A5359C57B609 /* NativeCallProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = B813F2A4838599F922071197 /* NativeCallProxy.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 以下のコードを、「1と2について」のコードの
// 保存
の後に貼り付ける - XCodeのプラグインに、headerにpublicを追加するようなAPIを持っていないため、正規表現で置換する原始的な方法をとっている
// NativeCallProxy.hをpublicに変更する
var projectContent = File.ReadAllText(projectPath);
string pattern = @"(\/\* NativeCallProxy\.h in Headers \*\/ = \{isa = PBXBuildFile; fileRef = .*?\/\* NativeCallProxy\.h \*\/; )};";
string replacement = @"$1settings = {ATTRIBUTES = (Public, ); }; };";
projectContent = Regex.Replace(projectContent, pattern, replacement, RegexOptions.Singleline);
// 保存
File.WriteAllText(projectPath, projectContent);
一応最後に全体のコード
#if UNITY_IOS
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEditor.iOS.Xcode;
using System.IO;
using System.Text.RegularExpressions;
namespace MyProject.Editor
{
public static class PostBuildProcessorForiOS
{
[PostProcessBuild]
public static void OnPostProcessBuild(BuildTarget buildTarget, string path)
{
if (buildTarget != BuildTarget.iOS) return;
// Xcodeプロジェクトファイルを読み込み
var projectPath = PBXProject.GetPBXProjectPath(path);
var pbxProject = new PBXProject();
pbxProject.ReadFromFile(projectPath);
var unityFrameworkTargetGuid = pbxProject.GetUnityFrameworkTargetGuid();
// 各種設定の適用
pbxProject.SetBuildProperty(unityFrameworkTargetGuid, "ENABLE_BITCODE", "NO");
pbxProject.AddBuildProperty(unityFrameworkTargetGuid, "OTHER_LDFLAGS", "-ld64");
// NOTE: 問題なく起動するが、XCode上でDataのTarget Membershipを一度他に変えて戻すと、GUID等に差分が生じる。
// 影響が不明なので、いったん自動でのTarget Membership変更は行わないこととする
// DataディレクトリをUnityFrameworkに変更
// var mainTargetGuid = pbxProject.GetUnityMainTargetGuid();
// var dataDirGuid = pbxProject.FindFileGuidByProjectPath("Data");
// pbxProject.RemoveFileFromBuild(mainTargetGuid, dataDirGuid);
// pbxProject.AddFileToBuild(unityFrameworkTargetGuid, dataDirGuid);
// 保存
File.WriteAllText(projectPath, pbxProject.WriteToString());
// NativeCallProxy.hをpublicに変更する
var projectContent = File.ReadAllText(projectPath);
string pattern = @"(\/\* NativeCallProxy\.h in Headers \*\/ = \{isa = PBXBuildFile; fileRef = .*?\/\* NativeCallProxy\.h \*\/; )};";
string replacement = @"$1settings = {ATTRIBUTES = (Public, ); }; };";
projectContent = Regex.Replace(projectContent, pattern, replacement, RegexOptions.Singleline);
// 保存
File.WriteAllText(projectPath, projectContent);
}
}
}
#endif
参考
Discussion