using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using Sirenix.OdinInspector; using Sirenix.OdinInspector.Editor; using UnityEditor; using UnityEditor.Build.Reporting; using UnityEngine; using UnityEngine.SceneManagement; using Debug = UnityEngine.Debug; namespace HK.Editor { /// /// 构建工具 /// 后续考虑搞一个一键打包工具,该打包会执行自动 /// 生成热更程序集 ——> 生成hybridCLR Aot ——> copy aotDlls ——> yooasset 构建资源 ——> 构建平台包 ——> 完成 /// public class CustomBuildTool : OdinEditorWindow { // 定义一个构建目标平台 enum BuildType { PC, Android, WebGL, } static string citizenPath = "Plugins/Citizen"; static string buildFolderPath = ""; private static string buidRootPath = "Builds"; public BuildTargetPlatform platform = BuildTargetPlatform.StandaloneWindows; [LabelText("是否使用Citizen打印机")] public bool isCitizenPrinter; public enum BuildTargetPlatform { StandaloneWindows, StandaloneWindows64, Android, WebGL, IOS, StandaloneOSX, StandaloneLinux64, TvOS, PS4, } [MenuItem("Tool/Build")] static void ShowWindow() { GetWindow().Show(); } [Button("打包")] void Build() { BuildTarget target = BuildTarget.NoTarget; switch (platform) { case BuildTargetPlatform.StandaloneWindows: target = BuildTarget.StandaloneWindows; break; case BuildTargetPlatform.StandaloneWindows64: target = BuildTarget.StandaloneWindows64; break; case BuildTargetPlatform.Android: target = BuildTarget.Android; break; case BuildTargetPlatform.WebGL: target = BuildTarget.WebGL; break; case BuildTargetPlatform.IOS: target = BuildTarget.iOS; break; case BuildTargetPlatform.StandaloneOSX: target = BuildTarget.StandaloneOSX; break; case BuildTargetPlatform.StandaloneLinux64: target = BuildTarget.StandaloneLinux64; break; case BuildTargetPlatform.TvOS: target = BuildTarget.tvOS; break; case BuildTargetPlatform.PS4: target = BuildTarget.PS4; break; default: throw new ArgumentOutOfRangeException(); } Run(target, GetBuildPath()); } [Button("打开Build文件夹")] void OpenBuildDirectory() { OpenFolder(); } [Button("清空所有Build文件夹")] void ClearBuildDirectory() { if (EditorUtility.DisplayDialog("提示", "确认清空所有平台的Build文件夹?", "是", "否")) { Directory.Delete(buidRootPath, true); } } string GetBuildPath() { string name = $"{Application.productName}-{DateTime.Now:yy-MM-dd}-v{Application.version}"; string extension = platform == BuildTargetPlatform.Android ? "apk" : platform == BuildTargetPlatform.WebGL ? "html" : platform == BuildTargetPlatform.StandaloneWindows ? "exe" : platform == BuildTargetPlatform.StandaloneWindows64 ? "exe" : ""; string dir = $"{buidRootPath}/{platform.ToString()}/v{Application.version}"; string path = $"{dir}/{name}.{extension}"; buildFolderPath = dir; if (Directory.Exists(dir)) Directory.Delete(dir, true); Directory.CreateDirectory(dir); return path; } private void Run(BuildTarget buildTarget, string outputFilePath) { // 清空一下文件夹的内容,避免某些重叠问题 if (Directory.Exists(outputFilePath)) Directory.Delete(outputFilePath, true); switch (buildTarget) { case BuildTarget.Android: ChangeAssetLoadMode(BuildType.Android); // Android签名配置示例 // PlayerSettings.Android.keystoreName = "path/to/keystore"; // PlayerSettings.Android.keystorePass = "password"; break; case BuildTarget.WebGL: ChangeAssetLoadMode(BuildType.WebGL); break; case BuildTarget.StandaloneWindows: ChangeAssetLoadMode(BuildType.PC); break; case BuildTarget.StandaloneWindows64: ChangeAssetLoadMode(BuildType.PC); break; default: throw new ArgumentOutOfRangeException(nameof(buildTarget), buildTarget, null); } // 设置要构建的场景 string[] scenes = EditorBuildSettings.scenes .Where(s => s.enabled) .Select(s => s.path) .ToArray(); // 设置构建选项 BuildPlayerOptions buildOptions = new BuildPlayerOptions { scenes = scenes, locationPathName = outputFilePath, target = buildTarget, options = BuildOptions.None // 根据需要设置构建选项,如压缩、包含调试信息等 }; // 开始构建过程 var buildPlayer = BuildPipeline.BuildPlayer(buildOptions); var summary = buildPlayer.summary; if (summary.result == BuildResult.Succeeded) { if (isCitizenPrinter && (buildTarget == BuildTarget.StandaloneWindows || buildTarget == BuildTarget.StandaloneWindows64)) { CommonHelper.CopyCitizenToBuild(buildFolderPath); } OpenFolder(); Debug.Log($"{buildTarget} 平台构建完成! "); } else if (summary.result == BuildResult.Cancelled) { Debug.LogWarning($"{buildTarget} 平台构建取消了! "); } else if (summary.result == BuildResult.Failed) { Debug.LogError($"{buildTarget} 平台构建失败了! "); } else if (summary.result == BuildResult.Unknown) { Debug.LogError($"{buildTarget} 平台构建 未知状态??! "); } } private static void OpenFolder() { // 根据不同的操作系统调用不同的命令来打开文件夹 string path = Application.dataPath.Replace("Assets", buidRootPath); Debug.Log(path); Process.Start(path); return; switch (Application.platform) { case RuntimePlatform.WindowsEditor: Process.Start("explorer.exe", path); break; case RuntimePlatform.OSXEditor: Process.Start("open", path); break; case RuntimePlatform.LinuxEditor: Process.Start("xdg-open", path); break; } } // static void ChangeAssetLoadMode(BuildType buildType) { // var scene = SceneManager.GetSceneByName("Init"); // var gameObjects = scene.GetRootGameObjects(); // foreach (var gameObject in gameObjects) // { // var components = gameObject.GetComponentsInChildren(); // foreach (var component in components) // { // if (component.GetType() == typeof(Global)) // { // EPlayMode playMode = EPlayMode.EditorSimulateMode; // FieldInfo fieldInfo = component.GetType().GetField("playMode", BindingFlags.NonPublic | BindingFlags.Instance); // // switch (buildType) // { // case BuildType.PC: // playMode = EPlayMode.HostPlayMode; // break; // case BuildType.Android: // playMode = EPlayMode.HostPlayMode; // break; // case BuildType.WebGL: // playMode = EPlayMode.WebPlayMode; // break; // default: // throw new ArgumentOutOfRangeException(nameof(buildType), buildType, null); // } // // if (fieldInfo != null) // fieldInfo.SetValue(component, playMode); // else // Debug.LogError("检查一下,打包出问题了!没找到global"); // // EditorUtility.SetDirty(gameObject); // // Debug.Log($"资源加载模式自动更改为 {playMode}."); // } // } // } } } }