콘텐츠로 이동

Unity Scriptable Build Pipeline — 커스텀 빌드 자동화

Scriptable Build Pipeline(SBP)은 Unity의 빌드 파이프라인을 C# 코드로 완전히 제어할 수 있는 패키지입니다. Addressables가 내부적으로 SBP를 사용하며, 커스텀 빌드 단계 삽입, 증분 빌드(incremental build), 빌드 캐시 등을 지원합니다.


Package Manager → Unity Registry →
Scriptable Build Pipeline → Install

using UnityEditor;
using UnityEditor.Build.Pipeline;
using UnityEngine;
public static class BuildScript
{
[MenuItem("Build/Build AssetBundles (SBP)")]
public static void BuildBundles()
{
var bundleBuilds = ContentBuildInterface.GenerateAssetBundleBuilds();
var buildParams = new BundleBuildParameters(
EditorUserBuildSettings.activeBuildTarget,
EditorUserBuildSettings.selectedBuildTargetGroup,
"Assets/StreamingAssets/Bundles");
// 증분 빌드 캐시 활성화
buildParams.UseCache = true;
buildParams.CacheServerHost = "cache.example.com";
buildParams.CacheServerPort = 8126;
var content = new BundleBuildContent(bundleBuilds);
var result = ContentPipeline.BuildAssetBundles(
buildParams, content, out var manifest);
if (result >= ReturnCode.Success)
Debug.Log($"빌드 성공: {manifest.GetAllAssetBundles().Length}개 번들");
else
Debug.LogError($"빌드 실패: {result}");
}
}

using UnityEditor.Build.Pipeline;
using UnityEditor.Build.Pipeline.Interfaces;
using UnityEditor.Build.Pipeline.Utilities;
// 커스텀 빌드 태스크 정의
public class LogBuildTask : IBuildTask
{
public int Version => 1;
public ReturnCode Run()
{
var context = BuildContext.GetContextObject<IBundleBuildContent>();
Debug.Log($"[Build] 빌드 시작: {context.BundleLayout.Count}개 번들");
return ReturnCode.Success;
}
}
// 빌드 태스크 파이프라인 커스터마이징
public static class CustomBuildPipeline
{
public static ReturnCode BuildWithCustomTasks()
{
// 기본 태스크 목록 가져오기
var tasks = DefaultBuildTasks.Create(
DefaultBuildTasks.Preset.AssetBundleBuiltInShaderExtraction);
// 시작 전 커스텀 태스크 삽입
tasks.Insert(0, new LogBuildTask());
var buildParams = new BundleBuildParameters(
BuildTarget.StandaloneWindows64,
BuildTargetGroup.Standalone,
"Assets/StreamingAssets/Bundles");
var content = new BundleBuildContent(
ContentBuildInterface.GenerateAssetBundleBuilds());
return ContentPipeline.BuildAssetBundles(
buildParams, content, out _, tasks);
}
}

using UnityEditor;
using UnityEditor.Build.Reporting;
using System;
public static class PlayerBuildScript
{
// CI/CD에서 호출
public static void BuildFromCommandLine()
{
var args = Environment.GetCommandLineArgs();
string outputPath = GetArg(args, "-outputPath") ?? "Builds/Game";
string version = GetArg(args, "-version") ?? "1.0.0";
PlayerSettings.bundleVersion = version;
var options = new BuildPlayerOptions
{
scenes = GetEnabledScenes(),
locationPathName = outputPath,
target = BuildTarget.StandaloneWindows64,
options = BuildOptions.None,
};
var report = BuildPipeline.BuildPlayer(options);
if (report.summary.result == BuildResult.Succeeded)
{
Console.WriteLine($"[BUILD] 성공: {report.summary.totalSize / 1024 / 1024} MB");
EditorApplication.Exit(0);
}
else
{
Console.WriteLine($"[BUILD] 실패: {report.summary.totalErrors} 오류");
EditorApplication.Exit(1);
}
}
static string[] GetEnabledScenes()
{
return Array.ConvertAll(
EditorBuildSettings.scenes,
s => s.path);
}
static string? GetArg(string[] args, string name)
{
for (int i = 0; i < args.Length - 1; i++)
if (args[i] == name) return args[i + 1];
return null;
}
}

using UnityEditor.Build.Reporting;
public static class BuildAnalyzer
{
[MenuItem("Build/Analyze Last Build")]
static void Analyze()
{
var report = BuildReport.GetLatestReport();
if (report == null) { Debug.LogError("빌드 리포트 없음"); return; }
Debug.Log($"빌드 시간: {report.summary.totalTime.TotalSeconds:F1}");
Debug.Log($"빌드 크기: {report.summary.totalSize / 1024 / 1024} MB");
// 가장 큰 에셋 Top 10
var files = report.GetFiles();
Array.Sort(files, (a, b) => b.size.CompareTo(a.size));
Debug.Log("=== Top 10 큰 에셋 ===");
for (int i = 0; i < Math.Min(10, files.Length); i++)
Debug.Log($"{files[i].size / 1024} KB {files[i].path}");
}
}

Terminal window
# GitHub Actions / Jenkins에서 Unity 빌드
Unity \
-batchmode \
-nographics \
-projectPath /path/to/project \
-executeMethod PlayerBuildScript.BuildFromCommandLine \
-outputPath Builds/Game \
-version 1.2.3 \
-logFile build.log \
-quit

// Unity Accelerator 또는 로컬 캐시 서버 연동
var buildParams = new BundleBuildParameters(...);
buildParams.UseCache = true;
buildParams.CacheServerHost = Environment.GetEnvironmentVariable("CACHE_SERVER") ?? "localhost";
buildParams.CacheServerPort = 8126;

Scriptable Build Pipeline은 빌드를 코드로 제어하고, 태스크를 삽입하며, 증분 빌드로 시간을 줄이는 데 핵심입니다. CI/CD에서 -executeMethod로 빌드 스크립트를 호출하고 BuildReport로 크기와 시간을 모니터링하면 빌드 파이프라인의 완전한 자동화가 가능합니다.