Unityエディタ拡張 ビルド前処理と後処理の今時の書き方


はじめに

  • エディタ拡張で、ビルド前に動的にコードを生成したくて調べたら、インターフェイスを継承してコールバックを使うという記事がいくつか見つかりました。
  • そこから色々調べた結果です。

環境

  • Unity 2018.4.x, 2019.4.x

今時の方法

リンク先の「公式スクリプトリファレンス」にもコード例があります。
以降の例は、ほぼ公式のままなので、リンク先をご覧いただいた方が分かり易いかも知れません。

ビルド前処理

  • 方針
    • 別クラスで定義されている変数を表示するだけのシーンを用意します。
    • エディタ拡張で、ビルド直前に、クラスが定義されたファイルを動的に生成します。
    • 生成されたコードによって、変数は現在日時で初期化されます。
    • 生成されているファイルの初期化子と、実行で表示された日時が一致すれば成功です。
  • このやり方で、実行時には取得できない(あるいは取得の面倒な)PlayerSettingsの要素などをコードに取り込むことが可能です。
Assets/Editor/PreBuild.cs
using System;
using System.IO;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;

public class PreBuild : IPreprocessBuildWithReport {

    public int callbackOrder { get { return 0; } } // ビルド前処理の中での処理優先順位 (0で最高)
    public void OnPreprocessBuild (BuildReport report) {
        Debug.Log ($"IPreprocessBuildWithReport.OnPreprocessBuild for {report.summary.platform} at {report.summary.outputPath}");
        var ScriptPathPrefKey = $"{PlayerSettings.companyName}/{PlayerSettings.productName}/ScriptPath";
        var AssetPath = EditorPrefs.GetString (ScriptPathPrefKey, "Assets/");
        File.WriteAllText (Path.Combine (AssetPath, "Data.cs"), // 要するに、Assets/Data.csに以下を書き出す
$@"public class Data {{
    public static readonly string BuildDateTime = ""{DateTime.Now}""; // コード生成時の日時
}}");
        AssetDatabase.Refresh (); // アセットDBの更新
    }

}

ビルド中処理

Assets/Editor/SceneBuilded.cs
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;

public class SceneBuilded : IProcessSceneWithReport {

    public int callbackOrder { get { return 0; } }
    public void OnProcessScene (UnityEngine.SceneManagement.Scene scene, BuildReport report) {
        Debug.Log ($"IProcessSceneWithReport.OnProcessScene {scene.name} as {report.name}");
    }

}

ビルド後処理

Assets/Editor/PostBuild.cs
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEngine;

public class PostBuild {

    [PostProcessBuild (0)]
    public static void OnPostprocessBuild (BuildTarget target, string pathToBuiltProject) {
        Debug.Log ($"OnPostprocessBuild for {target} at {pathToBuiltProject}");
    }

}

ビルド結果

Console
IPreprocessBuildWithReport.OnPreprocessBuild for StandaloneWindows at D:/development/PreBuildTest/PreBuildTest.win/PreBuildTest.exe
IProcessSceneWithReport.OnProcessScene SampleScene as New Report
OnPostprocessBuild for StandaloneWindows at D:/development/PreBuildTest/PreBuildTest.win/PreBuildTest.exe
Build completed with a result of 'Succeeded' in 12 seconds (12068 ms)