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

# はじめに
- エディタ拡張で、ビルド前に動的にコードを生成したくて調べたら、インターフェイスを継承してコールバックを使うという記事がいくつか見つかりました。
    - 前処理は[`IPreprocessBuild.OnPreprocessBuild`](https://docs.unity3d.com/jp/current/ScriptReference/Build.IPreprocessBuild.OnPreprocessBuild.html)で、後処理は[`IPostprocessBuild.OnPostprocessBuild`](https://docs.unity3d.com/jp/current/ScriptReference/Build.IPostprocessBuild.OnPostprocessBuild.html)が紹介されています。
    - ところが、書いてみたら`obsolete`で警告されました。
- そこから色々調べた結果です。

#### 環境
- Unity 2020.3.x

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

## ビルド前処理
- ビルド開始前に呼ばれます。
- インターフェイスを継承したクラスを用意して、コールバックを受けます。
    -  [`IPreprocessBuildWithReport.OnPreprocessBuild` コールバック](https://docs.unity3d.com/ja/current/ScriptReference/Build.IPreprocessBuildWithReport.OnPreprocessBuild.html) (公式スクリプトリファレンス)
-  ビルド前には、`OnEnable ()`が先に呼ばれるので注意する必要があります。

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

```cs: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 => 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の更新
	}

}
```

## ビルド中処理
- シーンがビルドされる毎に呼ばれるようです。
- インターフェイスを継承したクラスを用意して、コールバックを受けます。
    - [`IProcessSceneWithReport.OnProcessScene` コールバック](https://docs.unity3d.com/ja/current/ScriptReference/Build.IProcessSceneWithReport.OnProcessScene.html) (公式スクリプトリファレンス)

### コード例
```cs:Assets/Editor/SceneBuilded.cs
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;

public class SceneBuilded : IProcessSceneWithReport {

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

}
```

## ビルド後処理
- ビルド完了後に呼ばれます。
- インターフェイスを継承したクラスを用意して、コールバックを受けます。
    - [`IPostprocessBuildWithReport.OnProcessScene` コールバック](https://docs.unity3d.com/ja/current/ScriptReference/Build.IPostprocessBuildWithReport.OnPostprocessBuild.html) (公式スクリプトリファレンス)

### コード例
```cs:Assets/Editor/PostBuild.cs
public class PostBuild : IPostprocessBuildWithReport {

	public int callbackOrder => 0;
	public void OnPostprocessBuild (BuildReport report) {
		Debug.Log ($"OnPostprocessBuild for {report.summary.platform} at {report.summary.outputPath}");
	}
}
```