using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using UnityEditor; namespace XGame.Editor.Build { internal class ContextBuilder { private BuildContext _context; private BuildConfig _config; private bool _collectCmd; public ContextBuilder(BuildConfig config, bool collectCmd) { _config = config; _collectCmd = collectCmd; } public BuildContext GetProduct() { return _context; } public bool Build() { //创建文件夹 if (!Directory.Exists(_config.project.outputPath)) { try { Directory.CreateDirectory(_config.project.outputPath); } catch (Exception ex) { BuildLog.Exception(ex); BuildLog.Error($"打包输出目录错误,无法创建文件夹。{_config.project.outputPath}"); OnFailed(BuildErrorCode.OutputPathInvalid); return false; } } //转换Version var versionName = _config.project.bundleVersion; if (!Version.TryParse(versionName, out var version)) { var idx = versionName.LastIndexOf('.'); if (idx > 0) { //第一次解析失败,去掉最后一个"."后面的字符,再重试一次 versionName = versionName.Substring(0, idx); try { version = Version.Parse(versionName); } catch (Exception ex) { BuildLog.Exception(ex); BuildLog.Error($"Bundle Version failure. Version:{_config.project.bundleVersion}"); OnFailed(BuildErrorCode.BundleVersionFailure); return false; } } else { BuildLog.Error($"Bundle Version Can't Find Separator. Version:{_config.project.bundleVersion}"); OnFailed(BuildErrorCode.BundleVersionFailure); return false; } } //string callback = null; //if (_config.callback != null) //{ // //回调转成字符串 // callback = $""; // //清空原回调 // _config.callback = null; //} //app输出路径 var output = GetBuildAppPath(_config, version); _context = new BuildContext() { config = _config, appOutputPath = output, version = version, //complatedEvent = callback, }; if (_collectCmd) { _context.cmdTypeNames = CollectCmdTypeNames(); } return true; } private void OnFailed(BuildErrorCode errorCode) { BuildUtils.BuildCompleted(_config.callback, errorCode); if (_config.editor.autoExit) { BuildUtils.ExitApplication(errorCode); } } private string GetBuildAppPath(BuildConfig config, Version version) { var output = Path.Combine(config.project.outputPath, $"{config.project.productName}_v{version}"); string ext; switch (config.target) { case BuildTarget.Android: ext = config.android.exportAsGoogleAndroidProject ? string.Empty : ".apk"; break; case BuildTarget.iOS: ext = string.Empty; break; case BuildTarget.StandaloneWindows: case BuildTarget.StandaloneWindows64: if (Directory.Exists(output)) { UnityEditor.FileUtil.DeleteFileOrDirectory(output); } Directory.CreateDirectory(output); ext = $"{config.project.productName}.exe"; break; case BuildTarget.StandaloneOSX: if (Directory.Exists(output)) { UnityEditor.FileUtil.DeleteFileOrDirectory(output); } Directory.CreateDirectory(output); ext = $"{config.project.productName}"; break; default: ext = string.Empty; break; } if (!string.IsNullOrEmpty(ext)) { output = Path.Combine(output, ext); } return output; } private List CollectCmdTypeNames() { var cmdType = typeof(IBuildCommand); var assembly = cmdType.Assembly; var types = assembly.GetTypes(); var cmdTypesMap = new Dictionary(); foreach (var type in types) { if (type.IsClass && cmdType.IsAssignableFrom(type)) { if (type.IsAbstract) continue; var attribute = type.GetCustomAttribute(); if (attribute != null) { var priority = attribute.Priority; if (cmdTypesMap.ContainsKey(priority)) { BuildLog.Error($"BuildCommand Priority Repeated. Last:{cmdTypesMap[priority]} Next:{type}"); } else { cmdTypesMap.Add(attribute.Priority, type); } } } } var prioritys = cmdTypesMap.Keys.ToList(); prioritys.Sort((a, b) => a.CompareTo(b)); var typeNames = new List(); foreach (var priority in prioritys) { typeNames.Add(cmdTypesMap[priority].AssemblyQualifiedName); } return typeNames; } } }