06-03-YooAsset源码-Unity下载系统(DownloadSystem)

发布时间:2026/7/19 14:44:47
06-03-YooAsset源码-Unity下载系统(DownloadSystem) 源码-下载系统DownloadSystem篇章06-源码深度-文件系统与下载模块阅读时间约 30 分钟前置知识了解 IFileSystem一、引言本章将深入解析 YooAsset 下载系统DownloadSystem的源码实现。DownloadSystem 是 YooAsset 热更新功能的核心负责从远程服务器下载资源到本地。深入理解 DownloadSystem 是掌握 YooAsset 热更新机制的关键。DownloadSystem 采用了 DownloadManager、DownloadTask、BundleDownloader 的分层架构支持并发下载、断点续传、错误重试等高级特性。本章将从源码层面深入解析 DownloadSystem 的实现。二、下载系统架构2.1 分层架构YooAsset 的下载系统采用三层架构下载系统架构 ├── DownloadManager下载管理器 │ ├── 全局下载管理 │ ├── 并发控制 │ └── 任务调度 ├── DownloadTask下载任务 │ ├── 单个 Package 的下载任务 │ ├── 子任务管理 │ └── 进度汇总 └── BundleDownloaderBundle 下载器 ├── 单个 Bundle 的下载 ├── HTTP 请求 └── 文件写入DownloadManager 详解DownloadManager 是下载管理器负责全局的下载管理。DownloadTask 详解DownloadTask 是下载任务封装了一个 Package 的所有 Bundle 下载。BundleDownloader 详解BundleDownloader 是 Bundle 下载器负责单个 Bundle 的实际下载。2.2 核心组件public class DownloadManager { public int DownloadMaxConcurrency { get; set; } 10; public int FailedTryAgain { get; set; } 3; public float Timeout { get; set; } 60f; private ListDownloadTask _allTasks new ListDownloadTask(); private ListDownloadTask _runningTasks new ListDownloadTask(); public DownloadTask CreateDownloadTask(ResourcePackage package, ListBundleInfo bundleInfos); public void StartDownload(DownloadTask task); public void StopDownload(DownloadTask task); } public class DownloadTask : AsyncOperationBase { public ListBundleDownloader Downloaders { get; } public long TotalSize { get; } public long DownloadedSize { get; } public float Progress { get; } public DownloadStatus Status { get; } } public class BundleDownloader { public BundleInfo BundleInfo { get; } public long DownloadedBytes { get; } public float Progress { get; } public BundleDownloadStatus Status { get; } public IEnumerator Download(); }DownloadManager 配置详解DownloadMaxConcurrency最大下载并发数FailedTryAgain失败重试次数Timeout下载超时时间DownloadTask 状态详解Status下载状态Progress下载进度TotalSize总大小DownloadedSize已下载大小BundleDownloader 状态详解Status下载状态Progress下载进度DownloadedBytes已下载字节数三、HTTP 下载实现3.1 UnityWebRequest 封装public class BundleDownloader { private UnityWebRequest _request; private string _remoteURL; private string _localPath; public IEnumerator Download() { // 1. 创建下载请求 _request UnityWebRequest.Get(_remoteURL); _request.timeout 60; // 2. 设置下载处理器 var downloadHandler new DownloadHandlerFile(_localPath); downloadHandler.removeFileOnAbort true; _request.downloadHandler downloadHandler; // 3. 发送请求 yield return _request.SendWebRequest(); // 4. 处理结果 if (_request.result UnityWebRequest.Result.Success) { Status BundleDownloadStatus.Succeed; } else { Status BundleDownloadStatus.Failed; Error _request.error; } } }UnityWebRequest 详解UnityWebRequest 是 Unity 提供的网络请求 API。DownloadHandlerFile 详解DownloadHandlerFile 是文件下载处理器直接将下载的数据写入文件。removeFileOnAbort 详解removeFileOnAbort 设置下载中断时是否删除已下载的文件。3.2 下载进度跟踪public IEnumerator Download() { _request UnityWebRequest.Get(_remoteURL); _request.downloadHandler new DownloadHandlerFile(_localPath); var asyncOp _request.SendWebRequest(); while (!asyncOp.isDone) { // 更新进度 Progress asyncOp.progress; DownloadedBytes (long)(asyncOp.progress * TotalSize); yield return null; } }进度更新详解每帧更新下载进度asyncOp.progress 范围是 0-1。DownloadedBytes 计算详解已下载字节数 进度 × 总大小。3.3 HTTP 超时处理public IEnumerator Download() { _request UnityWebRequest.Get(_remoteURL); _request.timeout 60; // 60 秒超时 _request.downloadHandler new DownloadHandlerFile(_localPath); var startTime Time.realtimeSinceStartup; var asyncOp _request.SendWebRequest(); while (!asyncOp.isDone) { if (Time.realtimeSinceStartup - startTime Timeout) { _request.Abort(); Status BundleDownloadStatus.Timeout; yield break; } yield return null; } }超时检测详解每帧检查是否超时超时则取消请求。四、断点续传实现4.1 断点续传的概念断点续传可以从上次中断的位置继续下载优势减少重复下载节省流量提高下载成功率实现原理使用 HTTP Range 请求告诉服务器从哪个字节开始下载。4.2 HTTP Range 请求实现public IEnumerator Download() { // 1. 检查本地是否已有部分下载的文件 long resumePosition GetResumePosition(); if (resumePosition 0) { // 2. 设置 Range 请求头 _request.SetRequestHeader(Range, $bytes{resumePosition}-); } // 3. 设置下载处理器追加模式 var downloadHandler new DownloadHandlerFile(_localPath, resumePosition 0); _request.downloadHandler downloadHandler; // 4. 发送请求 yield return _request.SendWebRequest(); }Range 请求头详解Range 请求头的格式为bytesstart-end表示从 start 字节开始下载。追加模式详解DownloadHandlerFile 的第二个参数为 appendtrue 表示追加模式。4.3 文件位置记录private long GetResumePosition() { if (File.Exists(_localPath)) { return new FileInfo(_localPath).Length; } return 0; }文件大小获取详解通过 FileInfo 获取已下载的文件大小。断点位置详解断点位置就是已下载的文件大小。4.4 完整性验证public IEnumerator Download() { // ... 下载逻辑 ... // 下载完成后验证文件完整性 if (Status BundleDownloadStatus.Succeed) { if (!VerifyFileIntegrity()) { Status BundleDownloadStatus.Failed; Error File integrity check failed; // 删除损坏的文件 if (File.Exists(_localPath)) File.Delete(_localPath); } } } private bool VerifyFileIntegrity() { string fileHash CalculateFileHash(_localPath); return fileHash BundleInfo.FileHash; }Hash 校验详解计算下载文件的 Hash与 BundleInfo 中的 FileHash 对比。损坏文件处理详解校验失败时删除损坏的文件下次重新下载。五、错误重试5.1 重试策略public IEnumerator Download() { int retryCount 0; int maxRetries 3; while (retryCount maxRetries) { bool success false; yield return DoDownload(result success result); if (success) yield break; retryCount; // 等待一段时间后重试 float waitTime Mathf.Pow(2, retryCount); yield return new WaitForSeconds(waitTime); } Status BundleDownloadStatus.Failed; Error Max retries exceeded; }重试次数详解默认重试 3 次可通过配置调整。指数退避详解重试前等待时间 2^retryCount避免立即重试。5.2 错误分类private bool ShouldRetry(UnityWebRequest request) { switch (request.result) { case UnityWebRequest.Result.ConnectionError: // 网络错误重试 return true; case UnityWebRequest.Result.ProtocolError: // 协议错误根据状态码决定 if (request.responseCode 500) return true; // 服务器错误 return false; // 客户端错误不重试 case UnityWebRequest.Result.DataProcessingError: // 数据处理错误重试 return true; default: return false; } }网络错误详解网络连接失败应该重试。服务器错误详解5xx 状态码是服务器错误可以重试。客户端错误详解4xx 状态码是客户端错误不应该重试。5.3 重试实现public IEnumerator Download() { int retryCount 0; int maxRetries 3; while (retryCount maxRetries) { yield return DoSingleDownload(); if (Status BundleDownloadStatus.Succeed) yield break; if (!ShouldRetry(_request)) { yield break; } retryCount; yield return new WaitForSeconds(Mathf.Pow(2, retryCount)); } }重试条件详解只有可重试的错误才重试。重试间隔详解使用指数退避策略避免频繁重试。六、下载进度计算6.1 整体进度计算public class DownloadTask { public float Progress { get { if (TotalSize 0) return 0; return (float)DownloadedSize / TotalSize; } } public long DownloadedSize { get { long total 0; foreach (var downloader in Downloaders) { total downloader.DownloadedBytes; } return total; } } }整体进度详解整体进度 所有 Bundle 已下载字节数 / 总字节数。DownloadedSize 详解DownloadedSize 是所有 BundleDownloader 的已下载字节数之和。6.2 单个下载进度public class BundleDownloader { public float Progress _totalSize 0 ? (float)_downloadedBytes / _totalSize : 0; }单个下载进度详解单个下载进度 已下载字节数 / 该 Bundle 总大小。6.3 下载速度计算public class DownloadSpeedCalculator { private long _lastBytes; private float _lastTime; public float Speed { get; private set; } public void Update(long currentBytes) { var currentTime Time.realtimeSinceStartup; var timeDelta currentTime - _lastTime; if (timeDelta 1.0f) // 每秒更新一次 { Speed (currentBytes - _lastBytes) / timeDelta; _lastBytes currentBytes; _lastTime currentTime; } } }下载速度详解下载速度 (当前字节数 - 上次字节数) / 时间差。更新频率详解每秒更新一次速度避免抖动。七、并发控制7.1 并发控制的重要性并发控制是 DownloadManager 的重要特性避免过多的网络请求控制带宽使用防止服务器过载7.2 并发控制实现public class DownloadManager { private int _maxConcurrency 10; private QueueDownloadTask _waitingTasks new QueueDownloadTask(); private ListDownloadTask _runningTasks new ListDownloadTask(); public void StartDownload(DownloadTask task) { if (_runningTasks.Count _maxConcurrency) { _waitingTasks.Enqueue(task); return; } _runningTasks.Add(task); task.BeginDownload(); } public void OnTaskComplete(DownloadTask task) { _runningTasks.Remove(task); if (_waitingTasks.Count 0) { var nextTask _waitingTasks.Dequeue(); StartDownload(nextTask); } } }最大并发数详解默认最大并发数为 10可通过 DownloadMaxConcurrency 调整。任务队列详解超过并发数的任务进入等待队列。启动等待任务详解有任务完成时启动等待中的任务。7.3 单任务内部并发public class DownloadTask { private int _maxConcurrency 5; private QueueBundleDownloader _waitingDownloaders new QueueBundleDownloader(); public void Update() { // 启动等待中的下载 while (_currentConcurrency _maxConcurrency _waitingDownloaders.Count 0) { var downloader _waitingDownloaders.Dequeue(); StartDownloader(downloader); } } }任务内部并发详解单个 DownloadTask 也可以控制内部并发。Bundle 并发下载详解单个任务内的多个 Bundle 可以并发下载。八、下载操作 API8.1 下载操作public class DownloadManager { public DownloadTask BeginDownload(ResourcePackage package, ListBundleInfo bundleInfos, int failedTryAgain 0, int timeout 60); public void CancelDownload(DownloadTask task); public void PauseDownload(DownloadTask task); public void ResumeDownload(DownloadTask task); }BeginDownload 详解开始下载返回 DownloadTask。CancelDownload 详解取消下载停止所有下载。PauseDownload 详解暂停下载保存下载进度。ResumeDownload 详解恢复下载从断点继续。8.2 进度查询public class DownloadTask { public float Progress { get; } public long DownloadedSize { get; } public long TotalSize { get; } public DownloadStatus Status { get; } public string Error { get; } }Progress 详解Progress 是下载进度范围 0-1。Status 详解Status 是下载状态包括 Running、Paused、Succeed、Failed、Canceled。8.3 事件回调public class DownloadTask { public event ActionDownloadTask OnDownloadStart; public event ActionDownloadTask OnDownloadProgress; public event ActionDownloadTask OnDownloadComplete; public event ActionDownloadTask OnDownloadError; }事件类型详解OnDownloadStart下载开始OnDownloadProgress下载进度更新OnDownloadComplete下载完成OnDownloadError下载错误九、总结本章深入解析了 YooAsset 下载系统DownloadSystem的源码实现包括下载系统架构分层架构、核心组件HTTP 下载实现UnityWebRequest 封装、进度跟踪、超时处理断点续传实现HTTP Range 请求、文件位置记录、完整性验证错误重试重试策略、错误分类、重试实现下载进度计算整体进度、单个进度、下载速度并发控制并发控制的重要性、实现、单任务内部并发下载操作 API下载操作、进度查询、事件回调通过深入理解 DownloadSystem 的实现开发者可以更好地使用 YooAsset 的热更新功能并优化下载性能。下一篇加密解密机制