【Unity】最後のビルドをエディタから実行する

# 概要
最後のビルドの動作を見たいときに、出力フォルダを開くのがめんどくさかったり、そもそも出力フォルダがどれだったか分からなくなるので、エディタ拡張で最後のビルドを実行する機能を作りました。
その過程で躓いたところも備忘録的にまとめます。

さくっと機能を使いたい方は、UnityPackageManagerで以下URLを「Add package from git URL...」してください。
`https://github.com/udonba/Unity-RunLastBuild.git?path=Packages/RunLastBuild`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232140/c5e1ca1e-3465-754d-e988-7945e2d7c678.png)


# 機能
- ビルドすると自動でその出力パスを記録する
- エディタのメニューから最後のビルドを実行できる（Run Last Build）
- 実行ファイル(.exe)なら実行し、それ以外なら出力フォルダを開く

ビルドする際は通常の操作と同じで、特別な操作は必要ありません。
通常のビルド処理に相乗りするようにしています。



# 解説
以下の組み合わせで実装します。
- ビルド結果（ビルドした実行ファイルのパス）を取得する
- パスをエディタに保持する
- エディタから外部ファイルを実行する

## ビルド結果を取得する
ビルド結果を取得するには、２つの方法があります。
① ビルド処理自体を[`BuildPipeline.BuildPlayer`](https://docs.unity3d.com/2020.3/Documentation/ScriptReference/BuildPipeline.BuildPlayer.html)で自作し、その結果を受け取る
② [`IPostprocessBuildWithReport`](https://docs.unity3d.com/2020.3/Documentation/ScriptReference/Build.IPostprocessBuildWithReport.html)インターフェースを実装し、ビルド後のコールバックで結果を取得する

今回は後者②の方法でやりました。

### IPostprocessBuildWithReportでビルド結果を取得する
このインターフェースで実装する`OnPostprocessBuild`は、引数の[BuildReport](https://docs.unity3d.com/2020.3/Documentation/ScriptReference/Build.Reporting.BuildReport.html)型にビルド結果が格納されています。`IPostprocessBuildWithReport`インターフェースを実装すればビルド後に呼び出されます。
この中身を見れば、ビルド結果を使っていろいろできます。

今回は実行ファイルのパスだけ分かれば十分なので、`report.summary.outputPath`を使います。

``` C#
void IPostprocessBuildWithReport.OnPostprocessBuild(BuildReport report)
{
    // 出力パスを保存
    SaveOutputPath(report.summary.outputPath);
}
```

## パスをエディタに保存する
ビルドの出力パスの取得はできました。次はこのパス文字列を、エディタに保持してもらいます。
ScriptableObjectを作成してこれに書き込みます。今回はstring型1個だけのシンプルなものを作成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232140/3dd88351-da8b-5a61-3c8c-44795c6684fd.png)

エディタに保持するだけなら、EditorPrefsを使う方法もあり、こっちの方が実装も楽です。しかし、EditorPrefsはプロジェクトを横断して設定を保持します。（[参考記事](https://kan-kikuchi.hatenablog.com/entry/EditorPrefs)）
今回はプロジェクトごとに別個にビルドを保持させたかったので、ScriptableObjectを採用しました。

## エディタから外部ファイルを実行する
`Application.OpenURL`を使用します。

保存されたビルド出力のパスをScriptableObjectから読み込み、これに渡してあげることで、表題の機能が実装できます。

（うろ覚えですがmac環境だと`Process.Start`を使うのがめんどくさかった記憶があるので、`Application.OpenURL`を使っています。）


# 躓いたところ

## report.summary.resultがビルド成否と一致しないバグ
ビルドが成功したときだけ処理したかったのですが、`BuildReport`にちゃんと結果が入ってませんでした。どうやらそういうバグが残っているようです。
`IPostprocessBuildWithRepor`がそもそもビルドが成功したときしかコールバックされなかったので、今回は影響はありませんでした。

参考：[[BUILDREPORT] REPORT IN IPOSTPROCESSBUILDWITHREPORT PROVIDES INCORRECT INFORMATION](https://issuetracker.unity3d.com/issues/buildreport-report-in-ipostprocessbuildwithreport-provides-incorrect-information)

## Packages下にあるScriptableObjectを読み込む際は、Assets下とパスの形態が異なる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232140/779eae17-2a96-03e9-377e-53c6a35e7db2.png)
↑ エディタのProjectビューでは`Packages/RunLastBuild/Editor/LastBuildInfo.asset`にファイルがあるように見えますが、このパスを`AssetDatabase.LoadAssetAtPath`メソッドに渡しても読み込めません。
Packages下のファイルをLoadAssetAtPathするには、`Packages/com.udonba.runlastbuild/Editor/LastBuildInfo.asset`のようなパスを渡してあげる必要があります。

参考：[Using AssetDatabase.LoadAssetAtPath inside packages.](https://forum.unity.com/threads/using-assetdatabase-loadassetatpath-inside-packages.903764/)


# 参考記事・その他
- [Unity-RunLastBuild](https://github.com/udonba/Unity-RunLastBuild)
- [プロジェクトをまたいでデータを保存するEditorPrefs【Unity】【エディタ拡張】](https://kan-kikuchi.hatenablog.com/entry/EditorPrefs)
- [BuildPipeline.BuildPlayer](https://docs.unity3d.com/2020.3/Documentation/ScriptReference/BuildPipeline.BuildPlayer.html)
- [IPostprocessBuildWithReport](https://docs.unity3d.com/2020.3/Documentation/ScriptReference/Build.IPostprocessBuildWithReport.html)
- [[BUILDREPORT] REPORT IN IPOSTPROCESSBUILDWITHREPORT PROVIDES INCORRECT INFORMATION](https://issuetracker.unity3d.com/issues/buildreport-report-in-ipostprocessbuildwithreport-provides-incorrect-information)
- [Using AssetDatabase.LoadAssetAtPath inside packages.](https://forum.unity.com/threads/using-assetdatabase-loadassetatpath-inside-packages.903764/)