feat(editor): 新增一键打包AB资源工具,支持自动生成list.json

新增BuildTool编辑器窗口,集成AssetBundle Browser实现一键打包,自动生成版本化的list.json配置文件,支持同步拷贝到StreamingAssets目录
This commit is contained in:
“虞渠成” 2026-07-15 16:37:05 +08:00
parent ff418c307a
commit d9e66a2327
3 changed files with 183 additions and 0 deletions

159
Assets/Editor/BuildTool.cs Normal file
View File

@ -0,0 +1,159 @@
using System;
using System.IO;
using System.Reflection;
using UnityEditor;
using UnityEngine;
public class BuildTool : EditorWindow
{
private string buildVersion = "1.0.0";
private const string PREF_BUILD_VERSION = "BuildTool_Version";
[MenuItem("Tools/Build/一键打包资源 (AB + List)")]
public static void ShowWindow()
{
var window = GetWindow<BuildTool>("一键打包资源");
window.minSize = new Vector2(400, 100);
}
private void OnEnable()
{
buildVersion = EditorPrefs.GetString(PREF_BUILD_VERSION, "1.0.0");
}
private void OnGUI()
{
GUILayout.Label("一键打包资源 (AB → List)", EditorStyles.boldLabel);
EditorGUILayout.Space();
buildVersion = EditorGUILayout.TextField("版本号", buildVersion);
EditorGUILayout.Space();
EditorGUILayout.HelpBox("使用 Asset Bundle Browser 的设置进行构建,完成后自动生成 list.json", MessageType.Info);
EditorGUILayout.Space();
if (GUILayout.Button("开始打包", GUILayout.Height(35)))
{
if (string.IsNullOrEmpty(buildVersion))
{
EditorUtility.DisplayDialog("错误", "请输入版本号", "确定");
return;
}
EditorPrefs.SetString(PREF_BUILD_VERSION, buildVersion);
StartBuild();
}
}
private void StartBuild()
{
try
{
// ========== 第1步调用 ABB 构建 AssetBundle ==========
Debug.Log("=== 第1步调用 Asset Bundle Browser 构建 ===");
EditorUtility.DisplayProgressBar("打包中", "构建 AssetBundle...", 0.0f);
// 获取 ABB 窗口类型
var abbType = Type.GetType("AssetBundleBrowser.AssetBundleBrowserMain, Unity.AssetBundleBrowser.Editor");
if (abbType == null)
{
EditorUtility.ClearProgressBar();
EditorUtility.DisplayDialog("错误", "未找到 Asset Bundle Browser请确认已安装该包", "确定");
return;
}
// 获取/创建 ABB 窗口
var abbWindow = EditorWindow.GetWindow(abbType);
// 通过反射获取 m_BuildTab
var buildTabField = abbType.GetField("m_BuildTab", BindingFlags.NonPublic | BindingFlags.Instance);
if (buildTabField == null)
{
EditorUtility.ClearProgressBar();
EditorUtility.DisplayDialog("错误", "无法访问 ABB 构建选项卡", "确定");
return;
}
var buildTab = buildTabField.GetValue(abbWindow);
// 获取 ABB 输出路径和 CopyToStreaming 状态(在 ExecuteBuild 之前读取)
string abbOutputPath = GetABBSettings(buildTab, "m_UserData", "m_OutputPath") as string;
string fullAbbPath = !string.IsNullOrEmpty(abbOutputPath) ? Path.GetFullPath(abbOutputPath) : null;
bool copyToStreaming = (bool)GetABBSettings(buildTab, "m_CopyToStreaming", "state");
// 通过反射调用 ExecuteBuild同步执行内部会处理构建 + 拷贝到 StreamingAssets
var executeMethod = buildTab.GetType().GetMethod("ExecuteBuild", BindingFlags.NonPublic | BindingFlags.Instance);
if (executeMethod == null)
{
EditorUtility.ClearProgressBar();
EditorUtility.DisplayDialog("错误", "无法调用 ABB 构建方法", "确定");
return;
}
executeMethod.Invoke(buildTab, null);
AssetDatabase.Refresh();
// ========== 第2步生成 list.json ==========
Debug.Log("=== 第2步生成 list.json ===");
EditorUtility.DisplayProgressBar("打包中", "生成 list.json...", 0.6f);
if (string.IsNullOrEmpty(fullAbbPath) || !Directory.Exists(fullAbbPath))
{
EditorUtility.ClearProgressBar();
EditorUtility.DisplayDialog("错误", "ABB 构建后未找到输出目录", "确定");
return;
}
// 在 ABB 输出目录下生成 list.json
string listJsonPath = Path.Combine(fullAbbPath, "list.json");
AssetBundleListGenerator.GenerateList(fullAbbPath, listJsonPath, buildVersion);
Debug.Log($"list.json 已生成: {listJsonPath}");
// 如果 ABB 勾选了 Copy to StreamingAssets同步复制 list.json 过去
if (copyToStreaming)
{
string streamingAssetsPath = Path.GetFullPath("Assets/StreamingAssets");
if (Directory.Exists(streamingAssetsPath))
{
string destPath = Path.Combine(streamingAssetsPath, "list.json");
File.Copy(listJsonPath, destPath, true);
Debug.Log($"list.json 已同步到 StreamingAssets: {destPath}");
}
}
AssetDatabase.Refresh();
EditorUtility.ClearProgressBar();
Debug.Log("=== 资源打包完成! ===");
EditorUtility.DisplayDialog("打包成功",
$"资源打包完成\n版本号: {buildVersion}\n配置文件: {listJsonPath}" +
(copyToStreaming ? "\n已同步到: Assets/StreamingAssets/list.json" : ""),
"确定");
}
catch (Exception e)
{
EditorUtility.ClearProgressBar();
Debug.LogError($"打包失败: {e.Message}\n{e.StackTrace}");
EditorUtility.DisplayDialog("打包失败", $"发生错误: {e.Message}", "确定");
}
}
/// <summary>
/// 通过反射链式读取 ABB BuildTab 中的嵌套字段值
/// </summary>
private static object GetABBSettings(object buildTab, params string[] fieldPath)
{
object current = buildTab;
foreach (string fieldName in fieldPath)
{
if (current == null) return null;
var field = current.GetType().GetField(fieldName,
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
if (field == null) return null;
current = field.GetValue(current);
}
return current;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1e36e4ebd0184a3459625ad180468cc8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -22,6 +22,19 @@ public class AssetBundleListGenerator : EditorWindow
GetWindow<AssetBundleListGenerator>("AB List Generator");
}
/// <summary>
/// 静态方法:一键生成 list.json供自动化打包脚本调用
/// </summary>
public static void GenerateList(string folderPath, string outputPath, string version)
{
var window = GetWindow<AssetBundleListGenerator>(utility: true);
window.folderPath = folderPath;
window.outputPath = outputPath;
window.version = version;
window.GenerateAssetBundleList();
window.Close();
}
private void OnEnable()
{
// 从 EditorPrefs 加载保存的值