Unity實現(xiàn)批量Build打包詳解
一般來講如果項目是PC或Android、IOS端不會有批量Build打包這樣的需求,但如果項目是WebGL端可能會遇到這樣的需求:不同場景打包成不同的包體,入口是前端在頁面中布局的,點擊鏈接打開相應的程序。依次手動打包比較繁瑣而且需要等待很長時間,因此寫了批量Build這樣的功能,下班時點擊Build經(jīng)歷漫長的夜晚,第二天上班時包體已經(jīng)都打好了。

核心API是UnityEditor.BuildPipeline類中的BuildPlayer,調(diào)用該方法傳入相應參數(shù)即可實現(xiàn)打包,我們要做的是做一個配置文件,在其中配置打包不同包體對應的數(shù)據(jù),包含打包的場景、名稱和平臺等。首先構建可序列化類:
/// <summary>
/// 打包任務
/// </summary>
[Serializable]
public sealed class BuildTask
{
/// <summary>
/// 名稱
/// </summary>
public string ProductName;
/// <summary>
/// 目標平臺
/// </summary>
public BuildTarget BuildTarget;
/// <summary>
/// 打包路徑
/// </summary>
public string BuildPath;
/// <summary>
/// 打包場景
/// </summary>
public List<SceneAsset> SceneAssets = new List<SceneAsset>(0);
}
使用ScriptableObject構建配置:
/// <summary>
/// 打包配置表
/// </summary>
[CreateAssetMenu(fileName = "New Build Profile", menuName = "Build Profile")]
public sealed class BuildProfile : ScriptableObject
{
/// <summary>
/// 打包任務列表
/// </summary>
public List<BuildTask> BuildTasks = new List<BuildTask>(0);
}

有了BuildProfile后,配置打包列表,批量打包要做的就是遍歷該列表依次調(diào)用BuildPipeline中的BuildPlayer方法。創(chuàng)建Editor類,重寫B(tài)uildProfile的Inspector面板,編寫打包功能,以及添加、移除打包項等菜單。
[CustomEditor(typeof(BuildProfile))]
public sealed class BuildProfileInspector : Editor
{
private readonly Dictionary<BuildTask, bool> foldoutMap = new Dictionary<BuildTask, bool>();
private Vector2 scroll = Vector2.zero;
private BuildProfile profile;
private void OnEnable()
{
profile = target as BuildProfile;
}
public override void OnInspectorGUI()
{
GUILayout.BeginHorizontal();
{
if (GUILayout.Button("新建", "ButtonLeft"))
{
Undo.RecordObject(profile, "Create");
var task = new BuildTask()
{
ProductName = "Product Name",
BuildTarget = BuildTarget.StandaloneWindows64,
BuildPath = Directory.GetParent(Application.dataPath).FullName
};
profile.BuildTasks.Add(task);
}
if (GUILayout.Button("展開", "ButtonMid"))
{
for (int i = 0; i < profile.BuildTasks.Count; i++)
{
foldoutMap[profile.BuildTasks[i]] = true;
}
}
if (GUILayout.Button("收縮", "ButtonMid"))
{
for (int i = 0; i < profile.BuildTasks.Count; i++)
{
foldoutMap[profile.BuildTasks[i]] = false;
}
}
GUI.color = Color.yellow;
if (GUILayout.Button("清空", "ButtonMid"))
{
Undo.RecordObject(profile, "Clear");
if (EditorUtility.DisplayDialog("提醒", "是否確定清空列表?", "確定", "取消"))
{
profile.BuildTasks.Clear();
}
}
GUI.color = Color.cyan;
if (GUILayout.Button("打包", "ButtonRight"))
{
if (EditorUtility.DisplayDialog("提醒", "打包需要耗費一定時間,是否確定開始?", "確定", "取消"))
{
StringBuilder sb = new StringBuilder();
sb.Append("打包報告:\r\n");
for (int i = 0; i < profile.BuildTasks.Count; i++)
{
EditorUtility.DisplayProgressBar("Build", "Building...", i + 1 / profile.BuildTasks.Count);
var task = profile.BuildTasks[i];
List<EditorBuildSettingsScene> buildScenes = new List<EditorBuildSettingsScene>();
for (int j = 0; j < task.SceneAssets.Count; j++)
{
var scenePath = AssetDatabase.GetAssetPath(task.SceneAssets[j]);
if (!string.IsNullOrEmpty(scenePath))
{
buildScenes.Add(new EditorBuildSettingsScene(scenePath, true));
}
}
string locationPathName = $"{task.BuildPath}/{task.ProductName}";
var report = BuildPipeline.BuildPlayer(buildScenes.ToArray(), locationPathName, task.BuildTarget, BuildOptions.None);
sb.Append($"[{task.ProductName}] 打包結果: {report.summary.result}\r\n");
}
EditorUtility.ClearProgressBar();
Debug.Log(sb.ToString());
}
return;
}
GUI.color = Color.white;
}
GUILayout.EndHorizontal();
scroll = GUILayout.BeginScrollView(scroll);
{
for (int i = 0; i < profile.BuildTasks.Count; i++)
{
var task = profile.BuildTasks[i];
if (!foldoutMap.ContainsKey(task)) foldoutMap.Add(task, true);
GUILayout.BeginHorizontal("Badge");
GUILayout.Space(12);
foldoutMap[task] = EditorGUILayout.Foldout(foldoutMap[task], $"{task.ProductName}", true);
GUILayout.Label(string.Empty);
if (GUILayout.Button(EditorGUIUtility.IconContent("TreeEditor.Trash"), "IconButton", GUILayout.Width(20)))
{
Undo.RecordObject(profile, "Delete Task");
foldoutMap.Remove(task);
profile.BuildTasks.Remove(task);
break;
}
GUILayout.EndHorizontal();
if (foldoutMap[task])
{
GUILayout.BeginVertical("Box");
GUILayout.BeginHorizontal();
GUILayout.Label("打包場景:", GUILayout.Width(70));
if (GUILayout.Button(EditorGUIUtility.IconContent("Toolbar Plus More"), GUILayout.Width(28)))
{
task.SceneAssets.Add(null);
}
GUILayout.EndHorizontal();
if (task.SceneAssets.Count > 0)
{
GUILayout.BeginHorizontal();
GUILayout.Space(75);
GUILayout.BeginVertical("Badge");
for (int j = 0; j < task.SceneAssets.Count; j++)
{
var sceneAsset = task.SceneAssets[j];
GUILayout.BeginHorizontal();
GUILayout.Label($"{j + 1}.", GUILayout.Width(20));
task.SceneAssets[j] = EditorGUILayout.ObjectField(sceneAsset, typeof(SceneAsset), false) as SceneAsset;
if (GUILayout.Button("↑", "MiniButtonLeft", GUILayout.Width(20)))
{
if (j > 0)
{
Undo.RecordObject(profile, "Move Up Scene Assets");
var temp = task.SceneAssets[j - 1];
task.SceneAssets[j - 1] = sceneAsset;
task.SceneAssets[j] = temp;
}
}
if (GUILayout.Button("↓", "MiniButtonMid", GUILayout.Width(20)))
{
if (j < task.SceneAssets.Count - 1)
{
Undo.RecordObject(profile, "Move Down Scene Assets");
var temp = task.SceneAssets[j + 1];
task.SceneAssets[j + 1] = sceneAsset;
task.SceneAssets[j] = temp;
}
}
if (GUILayout.Button(EditorGUIUtility.IconContent("Toolbar Plus"), "MiniButtonMid", GUILayout.Width(20)))
{
Undo.RecordObject(profile, "Add Scene Assets");
task.SceneAssets.Insert(j + 1, null);
break;
}
if (GUILayout.Button(EditorGUIUtility.IconContent("Toolbar Minus"), "MiniButtonMid", GUILayout.Width(20)))
{
Undo.RecordObject(profile, "Delete Scene Assets");
task.SceneAssets.RemoveAt(j);
break;
}
GUILayout.EndHorizontal();
}
GUILayout.EndVertical();
GUILayout.EndHorizontal();
}
GUILayout.BeginHorizontal();
GUILayout.Label("產(chǎn)品名稱:", GUILayout.Width(70));
var newPN = GUILayout.TextField(task.ProductName);
if (task.ProductName != newPN)
{
Undo.RecordObject(profile, "Product Name");
task.ProductName = newPN;
}
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label("打包平臺:", GUILayout.Width(70));
var newBT = (BuildTarget)EditorGUILayout.EnumPopup(task.BuildTarget);
if (task.BuildTarget != newBT)
{
Undo.RecordObject(profile, "Build Target");
task.BuildTarget = newBT;
}
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label("打包路徑:", GUILayout.Width(70));
GUILayout.TextField(task.BuildPath);
if (GUILayout.Button("Browse", GUILayout.Width(60)))
{
task.BuildPath = EditorUtility.SaveFolderPanel("Build Path", task.BuildPath, "");
}
GUILayout.EndHorizontal();
GUILayout.EndVertical();
}
}
}
GUILayout.EndScrollView();
serializedObject.ApplyModifiedProperties();
if (GUI.changed) EditorUtility.SetDirty(profile);
}
}

到此這篇關于Unity實現(xiàn)批量Build打包詳解的文章就介紹到這了,更多相關Unity批量Build打包內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C#實現(xiàn)在啟動目錄創(chuàng)建快捷方式的方法
這篇文章主要介紹了C#實現(xiàn)在啟動目錄創(chuàng)建快捷方式的方法,涉及C#快捷方式的創(chuàng)建技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-09-09
C# 使用Microsoft Edge WebView2的相關總結
這篇文章主要介紹了C# 使用Microsoft Edge WebView2的相關總結,幫助大家更好的理解和學習使用c#,感興趣的朋友可以了解下2021-02-02

