using System; using System.Collections.Generic; using System.IO; using System.Linq; using AlicizaX.Resource.Runtime; using UnityEditor; using UnityEditor.Build.Reporting; using UnityEngine; using YooAsset; using YooAsset.Editor; public class AdvancedBuildWindow : EditorWindow { [MenuItem("开发工具/打包工具")] public static void ShowWindow() { GetWindow("Build Window", true); } private int _selectedTab; private readonly string[] _tabLabels = { "AB包构建", "整包构建" }; // AB包构建配置 private BuildTarget _abBuildTarget = BuildTarget.StandaloneWindows64; private string _outputPath = "Builds/AB"; private string _packageVersion; private bool _copyAfterBuild; private string _copyDestination; private ECompressOption _compressOption = ECompressOption.LZ4; private EFileNameStyle _fileNameStyle = EFileNameStyle.BundleName_HashName; private EBuildinFileCopyOption _copyOption = EBuildinFileCopyOption.ClearAndCopyByTags; private string _copyParams = "Launch"; private bool _enableSharePack = true; private string _selectedEncryption; private string _selectedPackage; // 整包构建配置 private BuildTarget _appBuildTarget = BuildTarget.StandaloneWindows64; private string _appOutputPath = "Builds/App"; private List _scenes = new List(); private bool _developmentBuild; private Vector2 _scrollPosition; private List _encryptionClasses; private List _buildPackageNames; private void OnEnable() { LoadEncryptionClasses(); LoadBuildPackageNames(); GeneratePackageVersion(); } private void GeneratePackageVersion() { int totalMinutes = DateTime.Now.Hour * 60 + DateTime.Now.Minute; _packageVersion = DateTime.Now.ToString("yyyy-MM-dd") + "-" + totalMinutes; } private void LoadEncryptionClasses() { _encryptionClasses = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(a => a.GetTypes()) .Where(t => typeof(IEncryptionServices).IsAssignableFrom(t) && !t.IsAbstract) .Select(t => t.FullName) .ToList(); } private void LoadBuildPackageNames() { _buildPackageNames = new List(); foreach (var package in AssetBundleCollectorSettingData.Setting.Packages) { _buildPackageNames.Add(package.PackageName); } } private void OnGUI() { _selectedTab = GUILayout.Toolbar(_selectedTab, _tabLabels); _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition); { switch (_selectedTab) { case 0: DrawABBuildTab(); break; case 1: DrawAppBuildTab(); break; } } EditorGUILayout.EndScrollView(); } private void DrawABBuildTab() { EditorGUILayout.Space(); EditorGUILayout.LabelField("AB包构建配置", EditorStyles.boldLabel); // 基本配置 DrawBuildTarget(ref _abBuildTarget); DrawPathSelection("输出路径:", ref _outputPath); DrawPackageVersion(); // 高级配置 EditorGUILayout.Space(); EditorGUILayout.LabelField("高级选项", EditorStyles.boldLabel); _compressOption = (ECompressOption)EditorGUILayout.EnumPopup("压缩方式:", _compressOption); _fileNameStyle = (EFileNameStyle)EditorGUILayout.EnumPopup("文件命名风格:", _fileNameStyle); _copyOption = (EBuildinFileCopyOption)EditorGUILayout.EnumPopup("内置文件拷贝选项:", _copyOption); _copyParams = EditorGUILayout.TextField("拷贝参数:", _copyParams); _enableSharePack = EditorGUILayout.Toggle("启用共享打包:", _enableSharePack); DrawEncryptionSelection(); DrawPackageSelection(); // 拷贝配置 EditorGUILayout.Space(); _copyAfterBuild = EditorGUILayout.BeginToggleGroup("构建后拷贝", _copyAfterBuild); DrawPathSelection("拷贝目标:", ref _copyDestination); EditorGUILayout.EndToggleGroup(); // 操作按钮 EditorGUILayout.Space(); if (GUILayout.Button("构建AB包", GUILayout.Height(30))) { BuildABPackage(); } if (GUILayout.Button("构建热更程序集", GUILayout.Height(30))) { BuildDLLCommand.BuildAndCopyDlls(); } } private void DrawAppBuildTab() { EditorGUILayout.Space(); EditorGUILayout.LabelField("整包构建配置", EditorStyles.boldLabel); DrawBuildTarget(ref _appBuildTarget); DrawPathSelection("输出路径:", ref _appOutputPath); _developmentBuild = EditorGUILayout.Toggle("开发模式:", _developmentBuild); EditorGUILayout.Space(); EditorGUILayout.LabelField("包含场景:", EditorStyles.boldLabel); DrawSceneList(); EditorGUILayout.Space(); if (GUILayout.Button("构建应用程序", GUILayout.Height(30))) { BuildApplication(); } } private void DrawBuildTarget(ref BuildTarget target) { target = (BuildTarget)EditorGUILayout.EnumPopup("目标平台:", target); } private void DrawPathSelection(string label, ref string path) { EditorGUILayout.BeginHorizontal(); { path = EditorGUILayout.TextField(label, path); if (GUILayout.Button("浏览...", GUILayout.Width(60))) { string newPath = EditorUtility.SaveFolderPanel("选择输出目录", path, ""); if (!string.IsNullOrEmpty(newPath)) { path = newPath; } } } EditorGUILayout.EndHorizontal(); } private void DrawPackageVersion() { EditorGUILayout.BeginHorizontal(); { _packageVersion = EditorGUILayout.TextField("版本号:", _packageVersion); if (GUILayout.Button("生成新版本", GUILayout.Width(100))) { GeneratePackageVersion(); } } EditorGUILayout.EndHorizontal(); } private void DrawEncryptionSelection() { if (_encryptionClasses == null || _encryptionClasses.Count == 0) { EditorGUILayout.HelpBox("未找到加密类实现", MessageType.Info); return; } int selectedIndex = Mathf.Max(0, _encryptionClasses.IndexOf(_selectedEncryption)); selectedIndex = EditorGUILayout.Popup("加密方式:", selectedIndex, _encryptionClasses.ToArray()); _selectedEncryption = _encryptionClasses[selectedIndex]; } private void DrawPackageSelection() { if (_buildPackageNames == null || _buildPackageNames.Count == 0) { EditorGUILayout.HelpBox("未找到包", MessageType.Info); return; } int selectedIndex = Mathf.Max(0, _buildPackageNames.IndexOf(_selectedPackage)); selectedIndex = EditorGUILayout.Popup("Package:", selectedIndex, _buildPackageNames.ToArray()); _selectedPackage = _buildPackageNames[selectedIndex]; } private void DrawSceneList() { for (int i = 0; i < _scenes.Count; i++) { _scenes[i] = (SceneAsset)EditorGUILayout.ObjectField($"场景 {i + 1}:", _scenes[i], typeof(SceneAsset), false); } EditorGUILayout.BeginHorizontal(); { if (GUILayout.Button("添加场景")) { _scenes.Add(null); } if (GUILayout.Button("移除最后一个") && _scenes.Count > 0) { _scenes.RemoveAt(_scenes.Count - 1); } } EditorGUILayout.EndHorizontal(); } private void BuildABPackage() { try { var parameters = new ScriptableBuildParameters { BuildOutputRoot = _outputPath, BuildTarget = _abBuildTarget, PackageName = _selectedPackage, BuildBundleType = (int)EBuildBundleType.AssetBundle, BuildPipeline = EBuildPipeline.ScriptableBuildPipeline.ToString(), BuildinFileRoot = AssetBundleBuilderHelper.GetStreamingAssetsRoot(), PackageVersion = _packageVersion, CompressOption = _compressOption, FileNameStyle = _fileNameStyle, VerifyBuildingResult = true, ClearBuildCacheFiles = false, BuildinFileCopyOption = _copyOption, BuildinFileCopyParams = _copyParams, EnableSharePackRule = _enableSharePack, EncryptionServices = CreateEncryptionInstance() }; ScriptableBuildPipeline pipeline = new ScriptableBuildPipeline(); var report = pipeline.Run(parameters, true); if (report.Success) { BuildUpdateData(_packageVersion, _copyDestination); if (_copyAfterBuild && !string.IsNullOrEmpty(_copyDestination)) { CopyFiles(report.OutputPackageDirectory, _copyDestination); } EditorUtility.DisplayDialog("构建成功", $"AB包构建完成!\n输出目录: {report.OutputPackageDirectory}", "确定"); } else { EditorUtility.DisplayDialog("构建失败", $"错误信息: {report.ErrorInfo}", "确定"); } } catch (Exception e) { Debug.LogException(e); } } private void BuildUpdateData(string version, string outPath) { ResourcePatchData updateData = new ResourcePatchData() { Version = Application.version, BundleUrl = $"http://127.0.0.1:8081/res/{version}/", Notice = "Test Notice", }; File.WriteAllText(Path.Combine(outPath, "UpdateData.json"), Newtonsoft.Json.JsonConvert.SerializeObject(updateData)); } private void BuildApplication() { try { var options = new BuildPlayerOptions { scenes = _scenes.Where(s => s != null).Select(s => AssetDatabase.GetAssetPath(s)).ToArray(), locationPathName = Path.Combine(_appOutputPath, GetExecutableName()), target = _appBuildTarget, options = _developmentBuild ? BuildOptions.Development : BuildOptions.None }; var report = BuildPipeline.BuildPlayer(options); HandleBuildReport(report); } catch (Exception e) { EditorUtility.DisplayDialog("错误", $"构建过程中发生异常: {e.Message}", "确定"); } } private IEncryptionServices CreateEncryptionInstance() { if (string.IsNullOrEmpty(_selectedEncryption)) return null; var type = Type.GetType(_selectedEncryption); if (type != null) { return (IEncryptionServices)Activator.CreateInstance(type); } return null; } private void CopyFiles(string source, string destination) { try { if (!Directory.Exists(destination)) { Directory.CreateDirectory(destination); } foreach (string file in Directory.GetFiles(source)) { File.Copy(file, Path.Combine(destination, Path.GetFileName(file)), true); } Debug.Log($"文件拷贝完成: {source} -> {destination}"); } catch (Exception e) { Debug.LogError($"文件拷贝失败: {e.Message}"); } } private void HandleBuildReport(UnityEditor.Build.Reporting.BuildReport report) { if (report.summary.result == UnityEditor.Build.Reporting.BuildResult.Succeeded) { EditorUtility.DisplayDialog("构建成功", $"应用程序构建完成!\n输出大小: {report.summary.totalSize / 1024 / 1024}MB", "确定"); } else { EditorUtility.DisplayDialog("构建失败", $"错误信息: {report.summary}", "确定"); } } private string GetExecutableName() { return _appBuildTarget switch { BuildTarget.StandaloneWindows64 => "Game.exe", BuildTarget.StandaloneOSX => "Game.app", BuildTarget.Android => "Game.apk", _ => "Game" }; } }