IPostprocessBuildWithReport で取得できるビルド情報が一部誤っている
IPostprocessBuildWithReport とは
IPostprocessBuildWithReport は Unity のビルド完了直後に実行されるコールバック関数が定義されたインターフェースです。このインターフェースを実装することでビルド後の処理をカスタマイズできます。
以下に、IPostprocessBuildWithReport
を使用してビルド後にログを出力するサンプルコードを示します。
using UnityEngine;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
public class Postprocessor : IPostprocessBuildWithReport
{
public int callbackOrder => 0;
public void OnPostprocessBuild(BuildReport report) // report にはビルドに関する情報が含まれている
{
Debug.Log("Build completed with " + report.summary.result);
}
}
OnPostprocessBuild()
がビルド完了直後に実行されるコールバック関数で、引数にはビルドに関する情報が含まれています。
callbackOrder で実行順を定義でき、小さい値の方が先に実行されます。
上記のコードを記述し、実際にビルドを実行してみると以下のように出力されます。
Build completed with Unknown
ビルドが確実に成功している場合にも report.summary.result
には BuildResult.Unknown が入っています。
しかし本来であればビルド結果に応じた値、つまり成功時は Succeeded
、失敗時は Failed
、キャンセル時は Cancelled
が入っているはずです。
ちなみに UnityEditor の Build Settings > Build からビルドを実行した場合も、batachmode でビルドを実行した場合も、callbackOrder
をあらゆる値に変更した場合も結果は同様でした。
以上のように IPostprocessBuildWithReport
により取得できるビルド情報には誤った情報が含まれています。
また、私が調べた範囲では BuildReport.summary.result の他にも以下の値が誤っていました。
この問題は既に以下の issue で報告されていますが、残念ながら Won't Fix とのことです。
- Unity Issue Tracker - [BuildReport] report in IPostProcessBuildWithReport provides incorrect information
- Unity Issue Tracker - [BuildReport] summary.result in IPostprocessBuildWithReport always return "Unknown"
回避方法
この問題の回避方法を 2 つ紹介します。
1. BuildPipeline.BuildPlayer() の戻り値からビルド情報を取得する
1 つ目の回避方法は BuildPipeline.BuildPlayer() の戻り値からビルド情報を取得する、という方法です。
以下にサンプルコードを示します。
using UnityEditor;
using UnityEngine;
using UnityEditor.Build.Reporting;
public class BuildPlayerExample
{
[MenuItem("Build/StandaloneOSX")]
public static void Build()
{
var buildPlayerOptions = new BuildPlayerOptions
{
scenes = new[] { "Assets/Scenes/SampleScene.unity" },
locationPathName = "Outputs",
target = BuildTarget.StandaloneOSX,
options = BuildOptions.Development,
};
// 正しいビルド情報が返ってくる
var report = BuildPipeline.BuildPlayer(buildPlayerOptions);
// Build completed with Succeeded
Debug.Log("Build completed with " + report.summary.result);
}
}
ただし、この場合は BuildPipeline.BuildPlayer()
の実行結果を受け取れるように上記のように MenuItem などでビルド実行のための導線を作る必要があります。
2. Library/LastBuild.buildreport からビルド情報を取得する
ビルド情報はビルド終了時に Library/LastBuild.buildreport
へ出力されるので、このファイルを読み込む、というのが 2 つ目の方法です。
以下にサンプルコードを示します。
using System.IO;
using UnityEditor;
using UnityEditor.Build.Reporting;
using UnityEngine;
public sealed class BuildReportLoader
{
private readonly string _buildReportDir =
$"{Path.Combine(Application.dataPath, LastBuildReportsDirectoryName)}";
private readonly string _lastBuildReportsAssetPath =
$"{Path.Combine("Assets", LastBuildReportsDirectoryName, LastBuildReportFileName)}";
private const string LastBuildReportsDirectoryName = "LastBuildReports";
private const string LibraryDirectoryName = "Library";
private const string LastBuildReportFileName = "LastBuild.buildreport";
public void LoadBuildReport()
{
var projectRootPath = Directory.GetParent(Application.dataPath)?.FullName;
if (string.IsNullOrEmpty(projectRootPath))
{
return;
}
var lastBuildReportPath = $"{Path.Combine(projectRootPath, LibraryDirectoryName, LastBuildReportFileName)}";
if (!File.Exists(lastBuildReportPath))
{
return;
}
if (!Directory.Exists(_buildReportDir))
{
Directory.CreateDirectory(_buildReportDir);
}
File.Copy(lastBuildReportPath, _lastBuildReportsAssetPath, true);
AssetDatabase.ImportAsset(_lastBuildReportsAssetPath);
var report = AssetDatabase.LoadAssetAtPath<BuildReport>(_lastBuildReportsAssetPath);
Debug.Log("Build completed with " + report.summary.result);
}
}
上記のコードでは Library/LastBuild.buildreport
を読み込むために、ファイルを一旦 Assets
内へコピーしてから AssetDatabase.LoadAssetAtPath()
で読み込むようにしています。
ちなみに BuildReportInspector や GhaUnityBuildReporter ではこの方法でビルド情報を取得しています。
Discussion