服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - Unity实现批量Build打包详解

Unity实现批量Build打包详解

2022-12-13 12:23CoderZ1010 C#

一般来讲如果项目是PC或Android、IOS端不会有批量Build打包这样的需求,但如果项目是WebGL端可能会遇到这样的需求。本文主要为大家介绍Unity中如何实现Build批量打包的,需要的朋友可以参考一下

一般来讲如果项目是PC或Android、IOS端不会有批量Build打包这样的需求,但如果项目是WebGL端可能会遇到这样的需求:不同场景打包成不同的包体,入口是前端在页面中布局的,点击链接打开相应的程序。依次手动打包比较繁琐而且需要等待很长时间,因此写了批量Build这样的功能,下班时点击Build经历漫长的夜晚,第二天上班时包体已经都打好了。

Unity实现批量Build打包详解

核心API是UnityEditor.BuildPipeline类中的BuildPlayer,调用该方法传入相应参数即可实现打包,我们要做的是做一个配置文件,在其中配置打包不同包体对应的数据,包含打包的场景、名称和平台等。首先构建可序列化类:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/// <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构建配置:

?
1
2
3
4
5
6
7
8
9
10
11
/// <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);
}

Unity实现批量Build打包详解

有了BuildProfile后,配置打包列表,批量打包要做的就是遍历该列表依次调用BuildPipeline中的BuildPlayer方法。创建Editor类,重写BuildProfile的Inspector面板,编写打包功能,以及添加、移除打包项等菜单。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
[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("产品名称:", 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实现批量Build打包详解

到此这篇关于Unity实现批量Build打包详解的文章就介绍到这了,更多相关Unity批量Build打包内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/qq_42139931/article/details/121675391

延伸 · 阅读

精彩推荐
  • C#再谈异常处理try catch finally

    再谈异常处理try catch finally

    这篇文章主要介绍了再谈异常处理try catch finally 的相关资料,需要的朋友可以参考下...

    至软9072021-11-08
  • C#C#中AS和IS关键字的用法

    C#中AS和IS关键字的用法

    这篇文章主要介绍了C#中AS和IS关键字的用法的相关资料,需要的朋友可以参考下...

    那年的冬天9892021-11-15
  • C#深入浅析C#中的var和dynamic

    深入浅析C#中的var和dynamic

    这篇文章给大家介绍了C#中的var和dynamic的相关知识,var和dynamic的本质区别是类型判断的时间不同,前者是编译时,后者是运行时。具体内容详情大家通过本...

    阿子7062022-02-23
  • C#利用FlubuCore用C#来写DevOps脚本的方法详解

    利用FlubuCore用C#来写DevOps脚本的方法详解

    这篇文章主要介绍了利用FlubuCore用C#来写DevOps脚本的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考...

    Savorboard5682022-09-22
  • C#C#中enum和string的相互转换

    C#中enum和string的相互转换

    这篇文章主要介绍了C#中enum和string的相互转换的相关资料,需要的朋友可以参考下...

    MeachiealFactory9592022-01-21
  • C#C#实现单例模式的几种方法总结

    C#实现单例模式的几种方法总结

    这篇文章主要介绍了C#实现单例模式的几种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面...

    zls3659322022-10-28
  • C#Untiy Shader实现纹理贴图滚动

    Untiy Shader实现纹理贴图滚动

    这篇文章主要为大家详细介绍了Untiy Shader实现纹理贴图滚动,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    fredshao11262022-07-09
  • C#Unity AssetBundle打包工具示例详解

    Unity AssetBundle打包工具示例详解

    这篇文章主要介绍了Unity AssetBundle打包工具,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下...

    小紫苏xw7602022-12-06