search
LoginSignup
1

More than 1 year has passed since last update.

posted at

Unity3Dのビルド設定により動的にScripting Define Symbolsを変更

Unityではユーザーが IPreprocessBuildWithReport インターフェースを実装したスクリプトを書くことで、スクリプトのコンパイルを含めたビルドが始まる前の挙動を変更できる。

Assets/Editor/Preprocessor.cs
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は上乗せしている。:

DefineSwitcher

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);
        }
    }
}

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
1