Unityではユーザーが IPreprocessBuildWithReport
インターフェースを実装したスクリプトを書くことで、スクリプトのコンパイルを含めたビルドが始まる前の挙動を変更できる。
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build;Reporting;
namespace Editor {
public class Preprocessor : IPreprocessBuildWithReport {
public int callbackOrder => 0;
public void OnPreprocessBuild(BuildReport report)
{
// Do your stuff
}
}
}
そして、UnityのエディタAPIを使うと、Scripting Define Symbolsを変更できる。
Scripting Define Symbolsはターゲットグループ(e.g. iOS, Android, Standalone,...)ごとに決まっているので、
設定時にはどのグループかの指定が必要になる。
例えばStandalone (macOS/Windows/Linux)に対して DE
FI
NE
を定義したかったら
PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone, "DE;FI;NE")
と記述する。
これらを組み合わせれば、動的にScripting Define Symbolsをビルド時に変更できるが、それを実現するにあたって変な勘違いをしていたので共有
正しいやり方
BuildReport
クラスからビルド設定を取得することができる。
BuildReport.summary.options
プロパティはビットフラグとなっている。
&
演算子で調べたい設定のconst
をぶつけて、結果がnonzero
になることを確認することで設定が有効かを調べられる。
public void OnPreprocessBuild(BuildReport report)
{
var isDev = (report.summary.options & BuildOptions.Development) != 0;
// Set scripting define symbol for 'Standalone (macOS/Windows/Linux)'
PlayerSettings.SetScriptingDefineSymbolsForGroup(
BuildTargetGroup.Standalone, isDev ? "DE;FI;NE" : ""
);
}
間違ったやり方
ちなみに、UnityにはDevelopment Buildを検出するためのDefine、DEVELOPMENT_BUILD
が存在する。これを使おうとして
public void OnPreprocessBuild(BuildReport report)
{
#if DEVELOPMENT_BUILD
PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone, "DE;FI;NE")
#else
PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone, "")
#endif
}
とやっても動作しない。というのも、このSymbolは**「ビルドが開始しないと正しい状態にならない」**からである。このメソッドはビルド前に呼ばれるから、Development BuildをONにした直後は、DEVELOPMENT_BUILD
は未定義という矛盾した状態が発生してしまう。
運用中のコード
場合によっては、Editorで動かす時用にビルド前からScripting Define Symbolsを入れている可能性もある。そんな状況にも対応するために、GetScriptingDefineSymbolsForGroup
を利用し、最初からあるSymbolを一時退避させたり、上乗せしたりすることができる。
実際に個人プロジェクトで運用しているコードがこちら - ここでは、ビルド前に存在していたSymbolは上乗せしている。:
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
namespace Editor
{
public class DefineSwitcher : IPreprocessBuildWithReport, IPostprocessBuildWithReport
{
public int callbackOrder => 0;
private const string DebugDefines = "";
private const string ReleaseDefines = "RELEASE_DEFINE;DISABLE_CHEATS";
private string _previousDefines = "";
/// <summary>
/// Run before a build (including any script compilation)
/// </summary>
/// <param name="report">Get config with this</param>
public void OnPreprocessBuild(BuildReport report)
{
_previousDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone);
var isDev = (report.summary.options & BuildOptions.Development) != 0;
// Set scripting define symbol for 'Standalone (macOS/Windows/Linux)'
PlayerSettings.SetScriptingDefineSymbolsForGroup(
BuildTargetGroup.Standalone, _previousDefines + ";" + (isDev ? DebugDefines : ReleaseDefines)
);
}
/// <summary>
/// Run after a build (including actual app / exe export)
/// </summary>
/// <param name="report">Get config with this</param>
public void OnPostprocessBuild(BuildReport report)
{
// Restore the previous defines
PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone, _previousDefines);
}
}
}