
这篇文章简要介绍了如何使用Unity的Scriptable Build Pipeline(SBP)建立构建流程。
什么是Scriptable Build Pipeline?
使用Scriptable Build Pipeline(可编写脚本的构建管道),可以自由构建构建流,比如资产包。
可以自定义构建AssetBundle之间的依赖关系以及输出描述依赖关系的文件的过程。
Unity还预定义了一个使用它的默认构建管道,可寻址资产系统使用它,与传统的不可定制的流水线相比,似乎性能有所提高,增量构建也有所改进。
PS:Scriptable Build Pipeline只适用于Unity 2018.3或更高版本。
安装SBP
从包管理器安装Scriptable Build Pipeline。

了解IBuildTask
现在看看如何使用Scriptable Build Pipeline。
首先,IBuildTask需要了解界面,构建一个AssetBundle可以分为几个阶段,例如:
- 更改平台(iOS、Android等)
- 收集资产之间的依赖关系
- 根据依赖信息构建 AssetBundle
在Scriptable Build Pipeline中,创建了一个实现每个阶段的IBuildTask类,然后,传递的列表如下所示,以运行每个阶段。
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEditor.Build.Pipeline.Interfaces;
using UnityEditor.Build.Pipeline;
public static class Example
{
[MenuItem("Example/Build")]
private static void Build()
{
// 按执行顺序创建和注册 IBuildTasks
var tasks = new List<IBuildTask>
{
new LogPlatform()
};
// (This will be explained in the next section)
var contexts = new BuildContext();
// run IBuildTask
var returnCode = BuildTasksRunner.Run(tasks, contexts);
Debug.Log(returnCode);
}
}
// 一个只输出当前平台的 BuildTask
public class LogPlatform : IBuildTask
{
public int Version => 1;
public ReturnCode Run()
{
Debug.Log(EditorUserBuildSettings.activeBuildTarget);
return ReturnCode.Success;
}
}
可以看到运行它会记录当前平台。

了解IContextObject
接下来,IBuildTask考虑像上一节那样传递参数。
在这种情况下,使用Scriptable Build Pipeline提供的DI机制。
具体如下,IContextObject将参数保存在执行的类中,IBuildTask进行DI。
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEditor.Build.Pipeline.Interfaces;
using UnityEditor.Build.Pipeline;
using UnityEditor.Build.Pipeline.Injector;
public static class Example
{
[MenuItem("Example/Build")]
private static void Build()
{
var tasks = new List<IBuildTask>
{
// 切换平台
new SwitchPlatform(),
// 记录当前平台
new LogPlatform()
};
var contexts = new BuildContext();
// 为 SwitchPlatform 添加上下文
var switchPlatformContext = new SwitchPlatformContext(BuildTargetGroup.Android, BuildTarget.Android);
contexts.SetContextObject(switchPlatformContext);
var returnCode = BuildTasksRunner.Run(tasks, contexts);
Debug.Log(returnCode);
}
}
public class LogPlatform : IBuildTask
{
public int Version => 1;
public ReturnCode Run()
{
Debug.Log(EditorUserBuildSettings.activeBuildTarget);
return ReturnCode.Success;
}
}
// BuildTask 切换平台
public class SwitchPlatform : IBuildTask
{
// 将 InjectContext 添加到 DI 目标字段
// 如果 DI 是任意的,则将第二个参数设置为 true
[InjectContext(ContextUsage.In)]
private readonly ISwitchPlatformContext _context = null;
public int Version => 1;
public ReturnCode Run()
{
return EditorUserBuildSettings.SwitchActiveBuildTarget(_context.Group, _context.Target)
? ReturnCode.Success
: ReturnCode.Error;
}
}
// SwitchPlatform 上下文接口
public interface ISwitchPlatformContext : IContextObject
{
BuildTargetGroup Group { get; }
BuildTarget Target { get; }
}
// SwitchPlatform 的上下文实现类
public class SwitchPlatformContext : ISwitchPlatformContext
{
public BuildTargetGroup Group { get; }
public BuildTarget Target { get; }
public SwitchPlatformContext(BuildTargetGroup group, BuildTarget target)
{
Group = group;
Target = target;
}
}
如果运行它,可以确认日志输出是在平台切换过程运行后执行的。

查看实际使用IBuildTask的地方
到目前为止已经了解了,IBuildTask看一下实际制作的部分。BuildTask是围绕Addressables中的UnityEditor.Build.Pipeline创建的。
如果只提取创建资产包的BuildTask的部分,它看起来如下所示。
static IList<IBuildTask> AssetBundleCompatible()
{
var buildTasks = new List<IBuildTask>();
// 设置
buildTasks.Add(new SwitchToBuildPlatform());
buildTasks.Add(new RebuildSpriteAtlasCache());
// 玩家脚本
buildTasks.Add(new BuildPlayerScripts());
buildTasks.Add(new PostScriptsCallback());
// 依赖性
buildTasks.Add(new CalculateSceneDependencyData());
#if UNITY_2019_3_OR_NEWER
buildTasks.Add(new CalculateCustomDependencyData());
#endif
buildTasks.Add(new CalculateAssetDependencyData());
buildTasks.Add(new StripUnusedSpriteSources());
buildTasks.Add(new PostDependencyCallback());
// 包装
buildTasks.Add(new GenerateBundlePacking());
buildTasks.Add(new GenerateBundleCommands());
buildTasks.Add(new GenerateSubAssetPathMaps());
buildTasks.Add(new GenerateBundleMaps());
buildTasks.Add(new PostPackingCallback());
// 写作
buildTasks.Add(new WriteSerializedFiles());
buildTasks.Add(new ArchiveAndCompressBundles());
buildTasks.Add(new AppendBundleHash());
buildTasks.Add(new PostWritingCallback());
// 生成清单文件
// TODO:IMPL 清单生成
return buildTasks;
}
可以看到按照执行顺序注册了大量的BuildTasks,为了自己创建构建流程,必须在此处创建流程。
查看实际使用IContextObject的位置
接下来,看看IContextObject实际用在什么地方。
寻找它的好地方是UnityEditor.Build.Pipeline周围,此方法的摘录如下所示:
buildContext = new BuildContext(contextObjects);
buildContext.SetContextObject(parameters);
buildContext.SetContextObject(content);
buildContext.SetContextObject(result);
buildContext.SetContextObject(interfacesWrapper);
buildContext.SetContextObject(progressTracker);
buildContext.SetContextObject(buildCache);
// 如果 IDeterministicIdentifiers 与 contextObjects 一起传入,则不要添加默认值
if (!buildContext.ContainsContextObject(typeof(IDeterministicIdentifiers)))
buildContext.SetContextObject(new Unity5PackedIdentifiers());
buildContext.SetContextObject(new BuildDependencyData());
buildContext.SetContextObject(new BundleWriteData());
buildContext.SetContextObject(BuildCallbacks);
还确认许多IContextObject已为DI注册。
仅需要定制一部分
这是关于如何使用脚本化构建管道建立构建流程的快速总结。
然而,实际上,不是从头开始建立构建流程,而是可能存在仅定制一部分就足够的情况。在这种情况下,CompatibilityBuildPipeline.BuildAssetBundles可以通过调整给定的参数来进行可选设置,如下所示。
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEditor.Build.Content;
using UnityEditor.Build.Pipeline;
public class Example
{
public static bool BuildAssetBundles(string outputPath, bool forceRebuild, bool useChunkBasedCompression,
BuildTarget buildTarget)
{
// 设置选项
var options = BuildAssetBundleOptions.None;
if (useChunkBasedCompression)
{
options |= BuildAssetBundleOptions.ChunkBasedCompression;
}
if (forceRebuild)
{
options |= BuildAssetBundleOptions.ForceRebuildAssetBundle;
}
// 获取 AssetBundle 构建信息
// 这不是Addressables,而是旧方法中收集AssetBundle名称的API,因此请根据需要进行更改
var bundles = ContentBuildInterface.GenerateAssetBundleBuilds();
// 仅将可寻址名称从完整路径更改为文件名
for (var i = 0; i < bundles.Length; i++)
{
bundles[i].addressableNames = bundles[i].assetNames.Select(Path.GetFileNameWithoutExtension).ToArray();
}
var manifest = CompatibilityBuildPipeline.BuildAssetBundles(outputPath, bundles, options, buildTarget);
return manifest != null;
}
}
…
以上是关于Unity如何使用Scriptable Build Pipeline建立构建流程的全部内容,如果你有任何反馈,请随时在本页面下方留言。