private void CreateReportFile(AssetBundleBuilder.BuildParametersContext buildParameters, BuildMapContext buildMapContext)
        {
            PatchManifest patchManifest = AssetBundleBuilderHelper.LoadPatchManifestFile(buildParameters.PipelineOutputDirectory, buildParameters.Parameters.BuildVersion);
            BuildReport   buildReport   = new BuildReport();

            // 概述信息
            {
                buildReport.Summary.UnityVersion                = UnityEngine.Application.unityVersion;
                buildReport.Summary.BuildTime                   = DateTime.Now.ToString();
                buildReport.Summary.BuildSeconds                = (int)buildParameters.GetBuildingSeconds();
                buildReport.Summary.BuildTarget                 = buildParameters.Parameters.BuildTarget;
                buildReport.Summary.BuildMode                   = buildParameters.Parameters.BuildMode;
                buildReport.Summary.BuildVersion                = buildParameters.Parameters.BuildVersion;
                buildReport.Summary.BuildinTags                 = buildParameters.Parameters.BuildinTags;
                buildReport.Summary.EnableAddressable           = buildParameters.Parameters.EnableAddressable;
                buildReport.Summary.AppendFileExtension         = buildParameters.Parameters.AppendFileExtension;
                buildReport.Summary.CopyBuildinTagFiles         = buildParameters.Parameters.CopyBuildinTagFiles;
                buildReport.Summary.AutoCollectShaders          = AssetBundleCollectorSettingData.Setting.AutoCollectShaders;
                buildReport.Summary.ShadersBundleName           = AssetBundleCollectorSettingData.Setting.ShadersBundleName;
                buildReport.Summary.EncryptionServicesClassName = buildParameters.Parameters.EncryptionServices == null ?
                                                                  "null" : buildParameters.Parameters.EncryptionServices.GetType().FullName;

                // 构建参数
                buildReport.Summary.CompressOption        = buildParameters.Parameters.CompressOption;
                buildReport.Summary.DisableWriteTypeTree  = buildParameters.Parameters.DisableWriteTypeTree;
                buildReport.Summary.IgnoreTypeTreeChanges = buildParameters.Parameters.IgnoreTypeTreeChanges;

                // 构建结果
                buildReport.Summary.AssetFileTotalCount       = buildMapContext.AssetFileCount;
                buildReport.Summary.AllBundleTotalCount       = GetAllBundleCount(patchManifest);
                buildReport.Summary.AllBundleTotalSize        = GetAllBundleSize(patchManifest);
                buildReport.Summary.BuildinBundleTotalCount   = GetBuildinBundleCount(patchManifest);
                buildReport.Summary.BuildinBundleTotalSize    = GetBuildinBundleSize(patchManifest);
                buildReport.Summary.EncryptedBundleTotalCount = GetEncryptedBundleCount(patchManifest);
                buildReport.Summary.EncryptedBundleTotalSize  = GetEncryptedBundleSize(patchManifest);
                buildReport.Summary.RawBundleTotalCount       = GetRawBundleCount(patchManifest);
                buildReport.Summary.RawBundleTotalSize        = GetRawBundleSize(patchManifest);
            }

            // 资源对象列表
            buildReport.AssetInfos = new List <ReportAssetInfo>(patchManifest.AssetList.Count);
            foreach (var patchAsset in patchManifest.AssetList)
            {
                var             mainBundle      = patchManifest.BundleList[patchAsset.BundleID];
                ReportAssetInfo reportAssetInfo = new ReportAssetInfo();
                reportAssetInfo.Address        = patchAsset.Address;
                reportAssetInfo.AssetPath      = patchAsset.AssetPath;
                reportAssetInfo.AssetTags      = patchAsset.AssetTags;
                reportAssetInfo.AssetGUID      = AssetDatabase.AssetPathToGUID(patchAsset.AssetPath);
                reportAssetInfo.MainBundleName = mainBundle.BundleName;
                reportAssetInfo.MainBundleSize = mainBundle.SizeBytes;
                reportAssetInfo.DependBundles  = GetDependBundles(patchManifest, patchAsset);
                reportAssetInfo.DependAssets   = GetDependAssets(buildMapContext, mainBundle.BundleName, patchAsset.AssetPath);
                buildReport.AssetInfos.Add(reportAssetInfo);
            }

            // 资源包列表
            buildReport.BundleInfos = new List <ReportBundleInfo>(patchManifest.BundleList.Count);
            foreach (var patchBundle in patchManifest.BundleList)
            {
                ReportBundleInfo reportBundleInfo = new ReportBundleInfo();
                reportBundleInfo.BundleName = patchBundle.BundleName;
                reportBundleInfo.Hash       = patchBundle.Hash;
                reportBundleInfo.CRC        = patchBundle.CRC;
                reportBundleInfo.SizeBytes  = patchBundle.SizeBytes;
                reportBundleInfo.Tags       = patchBundle.Tags;
                reportBundleInfo.Flags      = patchBundle.Flags;
                buildReport.BundleInfos.Add(reportBundleInfo);
            }

            // 删除旧文件
            string filePath = $"{buildParameters.PipelineOutputDirectory}/{YooAssetSettingsData.GetReportFileName(buildParameters.Parameters.BuildVersion)}";

            if (File.Exists(filePath))
            {
                File.Delete(filePath);
            }

            // 序列化文件
            BuildReport.Serialize(filePath, buildReport);
            BuildRunner.Log($"资源构建报告文件创建完成:{filePath}");
        }
Exemple #2
0
        void IBuildTask.Run(BuildContext context)
        {
            var buildParameters = context.GetContextObject <AssetBundleBuilder.BuildParametersContext>();

            buildParameters.BeginWatch();

            // 检测构建平台是否合法
            if (buildParameters.Parameters.BuildTarget == BuildTarget.NoTarget)
            {
                throw new Exception("请选择目标平台");
            }

            // 检测构建版本是否合法
            if (buildParameters.Parameters.BuildVersion <= 0)
            {
                throw new Exception("请先设置版本号");
            }

            // 检测输出目录是否为空
            if (string.IsNullOrEmpty(buildParameters.PipelineOutputDirectory))
            {
                throw new Exception("输出目录不能为空");
            }

            // 增量更新时候的必要检测
            var buildMode = buildParameters.Parameters.BuildMode;

            if (buildMode == EBuildMode.IncrementalBuild)
            {
                // 检测历史版本是否存在
                if (AssetBundleBuilderHelper.HasAnyPackageVersion(buildParameters.Parameters.BuildTarget, buildParameters.Parameters.OutputRoot) == false)
                {
                    throw new Exception("没有发现任何历史版本,请尝试强制重建");
                }

                // 检测构建版本是否合法
                int maxPackageVersion = AssetBundleBuilderHelper.GetMaxPackageVersion(buildParameters.Parameters.BuildTarget, buildParameters.Parameters.OutputRoot);
                if (buildParameters.Parameters.BuildVersion <= maxPackageVersion)
                {
                    throw new Exception("构建版本不能小于历史版本");
                }

                // 检测补丁包是否已经存在
                string packageDirectory = buildParameters.GetPackageDirectory();
                if (Directory.Exists(packageDirectory))
                {
                    throw new Exception($"补丁包已经存在:{packageDirectory}");
                }

                // 检测内置资源分类标签是否一致
                var oldPatchManifest = AssetBundleBuilderHelper.GetOldPatchManifest(buildParameters.PipelineOutputDirectory);
                if (buildParameters.Parameters.BuildinTags != oldPatchManifest.BuildinTags)
                {
                    throw new Exception($"增量更新时内置资源标签必须一致:{buildParameters.Parameters.BuildinTags} != {oldPatchManifest.BuildinTags}");
                }
            }

            // 如果是强制重建
            if (buildMode == EBuildMode.ForceRebuild)
            {
                // 删除平台总目录
                string platformDirectory = $"{buildParameters.Parameters.OutputRoot}/{buildParameters.Parameters.BuildTarget}";
                if (EditorTools.DeleteDirectory(platformDirectory))
                {
                    BuildRunner.Log($"删除平台总目录:{platformDirectory}");
                }
            }

            // 如果输出目录不存在
            if (EditorTools.CreateDirectory(buildParameters.PipelineOutputDirectory))
            {
                BuildRunner.Log($"创建输出目录:{buildParameters.PipelineOutputDirectory}");
            }
        }
        /// <summary>
        /// 验证构建结果
        /// </summary>
        private void VerifyingBuildingResult(BuildContext context, AssetBundleManifest unityManifest)
        {
            var buildParameters = context.GetContextObject <AssetBundleBuilder.BuildParametersContext>();
            var buildMapContext = context.GetContextObject <BuildMapContext>();

            string[] buildedBundles = unityManifest.GetAllAssetBundles();

            // 1. 过滤掉原生Bundle
            List <BuildBundleInfo> expectBundles = new List <BuildBundleInfo>(buildedBundles.Length);

            foreach (var bundleInfo in buildMapContext.BundleInfos)
            {
                if (bundleInfo.IsRawFile == false)
                {
                    expectBundles.Add(bundleInfo);
                }
            }

            // 2. 验证数量
            if (buildedBundles.Length != expectBundles.Count)
            {
                Debug.LogWarning($"构建过程中可能存在无效的资源,导致和预期构建的Bundle数量不一致!");
            }

            // 3. 正向验证Bundle
            foreach (var bundleName in buildedBundles)
            {
                if (buildMapContext.IsContainsBundle(bundleName) == false)
                {
                    throw new Exception($"Should never get here !");
                }
            }

            // 4. 反向验证Bundle
            bool isPass = true;

            foreach (var expectBundle in expectBundles)
            {
                bool isMatch = false;
                foreach (var buildedBundle in buildedBundles)
                {
                    if (buildedBundle == expectBundle.BundleName)
                    {
                        isMatch = true;
                        break;
                    }
                }
                if (isMatch == false)
                {
                    isPass = false;
                    Debug.LogWarning($"没有找到预期构建的Bundle文件 : {expectBundle.BundleName}");
                }
            }
            if (isPass == false)
            {
                throw new Exception("构建结果验证没有通过,请参考警告日志!");
            }

            // 5. 验证Asset
            var buildMode = buildParameters.Parameters.BuildMode;

            if (buildMode == EBuildMode.ForceRebuild || buildMode == EBuildMode.IncrementalBuild)
            {
                int progressValue = 0;
                foreach (var buildedBundle in buildedBundles)
                {
                    string   filePath                = $"{buildParameters.PipelineOutputDirectory}/{buildedBundle}";
                    string[] allBuildinAssetPaths    = GetAssetBundleAllAssets(filePath);
                    string[] expectBuildinAssetPaths = buildMapContext.GetBuildinAssetPaths(buildedBundle);
                    if (expectBuildinAssetPaths.Length != allBuildinAssetPaths.Length)
                    {
                        Debug.LogWarning($"构建的Bundle文件内的资源对象数量和预期不匹配 : {buildedBundle}");
                        isPass = false;
                        continue;
                    }

                    foreach (var buildinAssetPath in allBuildinAssetPaths)
                    {
                        var guid = AssetDatabase.AssetPathToGUID(buildinAssetPath);
                        if (string.IsNullOrEmpty(guid))
                        {
                            Debug.LogWarning($"无效的资源路径,请检查路径是否带有特殊符号或中文:{buildinAssetPath}");
                            isPass = false;
                            continue;
                        }

                        bool isMatch = false;
                        foreach (var exceptBuildAssetPath in expectBuildinAssetPaths)
                        {
                            var guidExcept = AssetDatabase.AssetPathToGUID(exceptBuildAssetPath);
                            if (guid == guidExcept)
                            {
                                isMatch = true;
                                break;
                            }
                        }
                        if (isMatch == false)
                        {
                            Debug.LogWarning($"在构建的Bundle文件里发现了没有匹配的资源对象:{buildinAssetPath}");
                            isPass = false;
                            continue;
                        }
                    }

                    EditorTools.DisplayProgressBar("验证构建结果", ++progressValue, buildedBundles.Length);
                }
                EditorTools.ClearProgressBar();
                if (isPass == false)
                {
                    throw new Exception("构建结果验证没有通过,请参考警告日志!");
                }
            }

            // 卸载所有加载的Bundle
            BuildRunner.Log("构建结果验证成功!");
        }