04-05-YooAsset源码-Unity清单生成与构建报告
源码-清单与报告
篇章:04-源码深度-编辑器模块
阅读时间:约 25 分钟
前置知识:了解构建管线分析
一、引言
本章将深入解析 YooAsset 清单(Manifest)与报告(Report)的源码实现。PackageManifest 是 YooAsset Editor 端和 Runtime 端之间的数据桥梁,记录了所有 Bundle 的信息;BuildReport 记录了构建的详细信息,是开发者分析构建结果的重要依据。
本章将从源码层面深入解析 PackageManifest 和 BuildReport 的设计与实现。
二、PackageManifest 概述
2.1 PackageManifest 的作用
PackageManifest 是 YooAsset 的资源清单,在整个资源管理流程中起到核心作用:
数据桥梁:
PackageManifest 是 Editor 端和 Runtime 端之间的数据桥梁。Editor 端生成 PackageManifest,Runtime 端读取 PackageManifest。
资源定位:
PackageManifest 记录了所有资源地址到 Bundle 的映射关系,运行时通过 PackageManifest 定位资源。
依赖管理:
PackageManifest 记录了 Bundle 之间的依赖关系,运行时可以根据依赖关系加载 Bundle。
版本管理:
PackageManifest 包含版本信息,支持热更新时的版本比较。
加密信息:
PackageManifest 包含加密信息,运行时根据加密信息解密资源。
2.2 PackageManifest 的核心字段
[Serializable] public class PackageManifest { // 包名 public string PackageName; // 包版本 public string PackageVersion; // 包描述 public string PackageDesc; // 资源版本(用于热更新) public string ResourceVersion; // 构建时间 public long BuildTime; // 构建引擎版本 public string BuildEngineVersion; // 资源清单 public AssetList AssetList = new AssetList(); // Bundle 列表 public BundleList BundleList = new BundleList(); } [Serializable] public class AssetList { public List<PackageAsset> Assets = new List<PackageAsset>(); } [Serializable] public class PackageAsset { public string Address; // 资源地址 public string AssetPath; // 资源路径 public string AssetGUID; // 资源 GUID public int BundleID; // 所属 Bundle ID public int DependIDs; // 依赖的 Bundle ID 列表 public string AssetTags; // 资源标签 } [Serializable] public class BundleList { public List<PackageBundle> Bundles = new List<PackageBundle>(); } [Serializable] public class PackageBundle { public int BundleID; // Bundle ID public string BundleName; // Bundle 名称 public string FileName; // Bundle 文件名 public string FileHash; // Bundle 文件 Hash public long FileSize; // Bundle 文件大小 public string FileCRC; // Bundle 文件 CRC public bool Encrypted; // 是否加密 public EBundleType BundleType; // Bundle 类型 public List<int> DependIDs; // 依赖的 Bundle ID 列表 }PackageName 详解:
PackageName 是 Package 的唯一标识符。运行时通过 PackageName 加载 Package。
PackageVersion 详解:
PackageVersion 是 Package 的版本号,用于热更新时的版本比较。
ResourceVersion 详解:
ResourceVersion 是资源版本号,可以与 PackageVersion 不同。用于更细粒度的版本管理。
AssetList 详解:
AssetList 包含了所有资源的信息,包括资源地址、路径、Bundle 等。
BundleList 详解:
BundleList 包含了所有 Bundle 的信息,包括 Bundle 名称、文件信息、依赖关系等。
2.3 PackageManifest 的序列化
PackageManifest 使用 JSON 格式序列化:
public class PackageManifest { public string ToJson() { return JsonUtility.ToJson(this, true); } public static PackageManifest FromJson(string json) { return JsonUtility.FromJson<PackageManifest>(json); } public void SaveToFile(string filePath) { string json = ToJson(); File.WriteAllText(filePath, json); } public static PackageManifest LoadFromFile(string filePath) { string json = File.ReadAllText(filePath); return FromJson(json); } }JSON 序列化详解:
使用 Unity 的 JsonUtility 进行 JSON 序列化。JsonUtility 支持 [Serializable] 特性的类。
JSON 文件存储详解:
PackageManifest 通常保存为PackageManifest_{PackageVersion}.bytes或PackageManifest_{PackageVersion}.json文件。
序列化的兼容性:
JsonUtility 的序列化是向前兼容的。新版本可以读取旧版本的 JSON,但旧版本可能无法读取新版本。
三、PackageManifest 生成流程
3.1 生成流程概述
PackageManifest 的生成流程:
PackageManifest 生成流程 1. 收集所有 Bundle 信息 2. 收集所有资源信息 3. 建立资源到 Bundle 的映射 4. 建立 Bundle 依赖关系 5. 计算资源地址 6. 计算 Bundle Hash 和大小 7. 序列化为 JSON 8. 写入输出文件收集 Bundle 信息详解:
从 BuildMap 中收集所有 Bundle 的信息,包括 Bundle 名称、文件、依赖等。
收集资源信息详解:
从 BuildMap 中收集所有资源的信息,包括资源地址、路径、Bundle 等。
建立映射详解:
建立资源地址到 Bundle 的映射,便于运行时通过资源地址定位 Bundle。
建立依赖关系详解:
建立 Bundle 之间的依赖关系,便于运行时加载依赖的 Bundle。
计算 Hash 和大小详解:
计算 Bundle 文件的 Hash 和大小,用于版本管理和完整性验证。
3.2 BuildTaskCreateManifest
BuildTaskCreateManifest 是创建 PackageManifest 的构建任务:
public class BuildTaskCreateManifest : IBuildTask { public void Run(BuildContext context) { PackageManifest manifest = new PackageManifest(); // 1. 填充基本信息 manifest.PackageName = context.Parameters.PackageName; manifest.PackageVersion = context.Parameters.PackageVersion; manifest.ResourceVersion = context.Parameters.ResourceVersion; manifest.BuildTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); manifest.BuildEngineVersion = Application.unityVersion; // 2. 创建 Bundle 列表 foreach (var buildBundle in context.BuildMap.Bundles) { var packageBundle = new PackageBundle(); packageBundle.BundleID = manifest.BundleList.Bundles.Count; packageBundle.BundleName = buildBundle.BundleName; packageBundle.FileName = buildBundle.FileName; packageBundle.FileHash = buildBundle.Hash; packageBundle.FileSize = buildBundle.FileSize; packageBundle.FileCRC = buildBundle.CRC; packageBundle.Encrypted = context.Parameters.EnableEncryption; packageBundle.BundleType = buildBundle.BundleType; packageBundle.DependIDs = ConvertDependNamesToIds(buildBundle.Dependencies, manifest); manifest.BundleList.Bundles.Add(packageBundle); } // 3. 创建资源列表 foreach (var assetEntry in context.BuildMap.AssetToBundle) { var packageAsset = new PackageAsset(); packageAsset.Address = assetEntry.Key; packageAsset.AssetPath = assetEntry.Value.AssetPath; packageAsset.AssetGUID = assetEntry.Value.AssetGUID; packageAsset.BundleID = GetBundleId(assetEntry.Value.BundleName, manifest); packageAsset.DependIDs = GetDependIds(assetEntry.Value.Dependencies, manifest); packageAsset.AssetTags = string.Join(",", assetEntry.Value.AssetTags); manifest.AssetList.Assets.Add(packageAsset); } // 4. 保存到文件 manifest.SaveToFile(context.ManifestFilePath); } }填充基本信息详解:
填充 PackageManifest 的基本信息,包括包名、版本、构建时间等。
创建 Bundle 列表详解:
将 BuildMap 中的 Bundle 转换为 PackageBundle,并建立 Bundle ID。
创建资源列表详解:
将 BuildMap 中的资源转换为 PackageAsset,并设置 Bundle ID。
保存到文件详解:
将 PackageManifest 序列化为 JSON 并保存到输出文件。
3.3 资源地址计算
资源地址是 PackageManifest 中的重要字段:
public class AssetAddressCalculator { public string CalculateAddress(string assetPath, AssetBundleCollector collector) { if (collector.AddressRule == EAddressRule.StringAddress) { return CalculateStringAddress(assetPath, collector); } else if (collector.AddressRule == EAddressRule.GUIDAddress) { return AssetDatabase.AssetPathToGUID(assetPath); } else if (collector.AddressRule == EAddressRule.LabelAddress) { return string.Join(",", collector.AssetTags); } return string.Empty; } private string CalculateStringAddress(string assetPath, AssetBundleCollector collector) { if (!string.IsNullOrEmpty(collector.Address)) { return collector.Address + "/" + Path.GetFileNameWithoutExtension(assetPath); } string relativePath = assetPath.Substring(collector.CollectPath.Length); return relativePath.Replace("\\", "/").TrimStart('/').Replace(Path.GetExtension(assetPath), ""); } }String Address 计算详解:
使用 Collector 的 Address 作为前缀,加上文件名生成地址。
GUID Address 计算详解:
使用 Unity 的 AssetPathToGUID API 获取资源的 GUID。
Label Address 计算详解:
使用 Collector 的 AssetTags 作为地址。
四、BuildReport 概述
4.1 BuildReport 的作用
BuildReport 记录了构建的详细信息:
- 构建结果(成功/失败)
- 构建参数
- 构建时间
- 资源统计
- Bundle 统计
- 错误和警告
4.2 BuildReport 的核心字段
[Serializable] public class BuildReport { public string PackageName; public string PackageVersion; public bool BuildSuccess; public string BuildError; public long BuildStartTime; public long BuildEndTime; public long BuildDuration; public string BuildEngineVersion; public BuildTarget BuildTarget; public int TotalAssetCount; public int TotalBundleCount; public long TotalFileSize; public List<BuildBundleReport> BundleReports = new List<BuildBundleReport>(); public List<string> Warnings = new List<string>(); } [Serializable] public class BuildBundleReport { public string BundleName; public string FileName; public int AssetCount; public long FileSize; public string FileHash; public List<string> Assets = new List<string>(); public List<string> Dependencies = new List<string>(); }BuildSuccess 详解:
BuildSuccess 标识构建是否成功。
BuildError 详解:
BuildError 记录构建失败的错误信息。
BuildDuration 详解:
BuildDuration 记录构建耗时。
BundleReports 详解:
BundleReports 包含了所有 Bundle 的报告。
Warnings 详解:
Warnings 记录了构建过程中的警告信息。
4.3 BuildReport 的生成
public class BuildReportGenerator { public BuildReport Generate(BuildContext context) { BuildReport report = new BuildReport(); // 1. 填充基本信息 report.PackageName = context.Parameters.PackageName; report.PackageVersion = context.Parameters.PackageVersion; report.BuildStartTime = context.BuildStartTime; report.BuildEndTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); report.BuildDuration = report.BuildEndTime - report.BuildStartTime; report.BuildEngineVersion = Application.unityVersion; report.BuildTarget = context.BuildTarget; // 2. 统计资源 foreach (var bundle in context.BuildMap.Bundles) { var bundleReport = new BuildBundleReport(); bundleReport.BundleName = bundle.BundleName; bundleReport.FileName = bundle.FileName; bundleReport.AssetCount = bundle.Assets.Count; bundleReport.FileSize = bundle.FileSize; bundleReport.FileHash = bundle.Hash; bundleReport.Assets = bundle.Assets; bundleReport.Dependencies = bundle.Dependencies; report.BundleReports.Add(bundleReport); } // 3. 计算总数 report.TotalBundleCount = report.BundleReports.Count; report.TotalAssetCount = report.BundleReports.Sum(b => b.AssetCount); report.TotalFileSize = report.BundleReports.Sum(b => b.FileSize); // 4. 设置构建结果 report.BuildSuccess = context.BuildSuccess; report.BuildError = context.BuildError; report.Warnings = context.Warnings; return report; } }填充基本信息详解:
填充 BuildReport 的基本信息,包括包名、版本、构建时间、构建平台等。
统计 Bundle 信息详解:
为每个 Bundle 生成 BuildBundleReport,包含 Bundle 的详细信息。
计算总数详解:
计算所有 Bundle 的资源总数、文件总大小等。
设置构建结果详解:
设置构建的成功状态、错误信息、警告信息。
4.4 BuildReport 的展示
BuildReport 提供了多种展示方式:
Editor 内显示:
[CustomEditor(typeof(BuildReport))] public class BuildReportEditor : Editor { public override void OnInspectorGUI() { // 显示 BuildReport 的内容 } }导出为 JSON:
public void SaveToJson(string filePath) { string json = JsonUtility.ToJson(this, true); File.WriteAllText(filePath, json); }导出为 HTML:
可以自定义将 BuildReport 导出为 HTML 格式,便于在浏览器中查看。
五、版本管理
5.1 版本号格式
YooAsset 使用语义化版本号(Semantic Versioning):
格式:
Major.Minor.Patch(如1.0.0)
Major 版本:
主版本号,表示重大更新,可能不兼容旧版本。
Minor 版本:
次版本号,表示新增功能,向后兼容。
Patch 版本:
补丁版本号,表示 bug 修复。
5.2 版本管理实现
public class VersionManager { public bool IsNewerVersion(string newVersion, string oldVersion) { var newVer = new Version(newVersion); var oldVer = new Version(oldVersion); return newVer > oldVer; } public string GenerateNextVersion(string currentVersion, EVersionIncrementType incrementType) { var ver = new Version(currentVersion); switch (incrementType) { case EVersionIncrementType.Major: return $"{ver.Major + 1}.0.0"; case EVersionIncrementType.Minor: return $"{ver.Major}.{ver.Minor + 1}.0"; case EVersionIncrementType.Patch: return $"{ver.Major}.{ver.Minor}.{ver.Build + 1}"; default: return currentVersion; } } }版本比较详解:
使用 .NET 的 Version 类进行版本比较。
版本递增详解:
支持 Major、Minor、Patch 三种递增方式。
5.3 版本号的使用
版本号在 YooAsset 中有以下用途:
- 标识 Package 的版本
- 标识构建产物的版本
- 标识热更新的差异
- 标识缓存的版本
六、总结
本章深入解析了 YooAsset 清单(Manifest)与报告(Report)的源码实现,包括:
- PackageManifest 概述:PackageManifest 的作用、字段、序列化
- PackageManifest 生成流程:生成流程、BuildTaskCreateManifest、地址计算
- BuildReport 概述:BuildReport 的作用、字段、生成
- BuildReport 展示:Editor 内显示、JSON 导出、HTML 导出
- 版本管理:版本号格式、版本比较、版本递增
PackageManifest 和 BuildReport 是 YooAsset 编辑器端的重要组成部分,深入理解它们的实现有助于更好地使用和扩展 YooAsset。
上一篇:构建管线分析
下一篇:调试与诊断工具
