😎

IPostprocessBuildWithReport で取得できるビルド情報が一部誤っている

2024/05/01に公開

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 とのことです。

回避方法

この問題の回避方法を 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() で読み込むようにしています。

ちなみに BuildReportInspectorGhaUnityBuildReporter ではこの方法でビルド情報を取得しています。

GitHubで編集を提案

Discussion