1.异步下载
using System.Collections;using System.Collections.Generic;using UnityEngine;using System;using System.IO;using System.Net.Http;using System.Threading;using System.Threading.Tasks;public class DownloadHelp:MonoBehaviour{privatevoidStart(){Test();}private CancellationTokenSource _cancellationTokenSource;public async TaskTest(){var downloader=newProgressableStreamDownloader();_cancellationTokenSource=newCancellationTokenSource();var progress=new Progress<(longdownloaded,long?total,doublepercent)>(p=>{Debug.Log($"已下载: {p.downloaded / 1024 / 1024}MB, "+$"总大小: {p.total / 1024 / 1024}MB, "+$"进度: {p.percent:F1}%");});await downloader.DownloadFileAsync("http://10.0.1.24/test.apk",//文件下载地址@"D:\Downloads\test.apk",//文件保存地址progress,_cancellationTokenSource.Token);_cancellationTokenSource?.Dispose();}publicvoidStopDownload(){_cancellationTokenSource?.Cancel();Debug.Log("已请求停止下载");}}public class ProgressableStreamDownloader{private readonly HttpClient _httpClient=newHttpClient();public async TaskDownloadFileAsync(string url,string savePath,IProgress<(longdownloaded,long?total,doublepercent)>progress=null,CancellationToken cancellationToken=default){try{Directory.CreateDirectory(Path.GetDirectoryName(savePath));using var response=await _httpClient.GetAsync(url,HttpCompletionOption.ResponseHeadersRead,cancellationToken);response.EnsureSuccessStatusCode();var totalBytes=response.Content.Headers.ContentLength;await using var contentStream=await response.Content.ReadAsStreamAsync();await using var fileStream=newFileStream(savePath,FileMode.Create,FileAccess.Write,FileShare.None,81920,true);var buffer=new byte[81920];longdownloadedBytes=0;intbytesRead;while((bytesRead=await contentStream.ReadAsync(buffer,0,buffer.Length,cancellationToken))>0){await fileStream.WriteAsync(buffer,0,bytesRead,cancellationToken);downloadedBytes+=bytesRead;// 报告进度progress?.Report((downloadedBytes,totalBytes,totalBytes.HasValue?(double)downloadedBytes/totalBytes.Value*100:0));}}catch(Exception e){Debug.LogError(e);}}}
2.线程下载
publicclassDownloadHelp:MonoBehaviour{privatevoidStart(){BeginDownloadThread();}voidBeginDownloadThread(){vardownloader=newThreadedDownloader();downloader.OnProgress+=(downloaded,total,percent)=>{vartxt=($"已下载:{downloaded/1024/1024}MB, "+$"总大小:{total/1024/1024}MB, "+$"进度:{percent:F1}%");/*var c = (int)percent; if (lastProcess != c) { Debug.Log(lastProcess); lastProcess = c; AndroidJNI.AttachCurrentThread(); //BackgroundServiceManager.Instance.UpdateProcess(txt, (int)percent); }*/};downloader.OnError+=(stage,ex)=>{Debug.LogError($"[{stage}]{ex.Message}");};downloader.OnCompleted+=()=>{Debug.Log("下载完成");//BackgroundServiceManager.Instance.StopBackgroundService();};downloader.StartDownload("http://10.0.1.24/test.apk",Application.persistentDataPath+"/down.apk");}publicvoidStopDownload(){downloader.StopDownload();Debug.Log("已请求停止下载");}}usingSystem;usingSystem.IO;usingSystem.Net.Http;usingSystem.Threading;usingUnityEngine;publicclassThreadedDownloader{privateThread_downloadThread;privatevolatilebool_isDownloading;privatevolatilebool_shouldStop;privatereadonlyobject_lockObject=newobject();publiceventAction<long,long?,double>OnProgress;publiceventAction<string,Exception>OnError;publiceventActionOnCompleted;publiceventActionOnCancelled;publicboolIsDownloading{get{lock(_lockObject){return_isDownloading;}}}publicvoidStartDownload(stringurl,stringsavePath){lock(_lockObject){if(_isDownloading){Debug.LogWarning("下载已在进行中");return;}_isDownloading=true;_shouldStop=false;}_downloadThread=newThread(()=>DownloadWorker(url,savePath)){IsBackground=true,Name="DownloadThread"};_downloadThread.Start();}publicvoidStopDownload(){lock(_lockObject){if(!_isDownloading){Debug.LogWarning("没有正在进行的下载");return;}_shouldStop=true;Debug.Log("已请求停止下载");}}privatevoidDownloadWorker(stringurl,stringsavePath){HttpClienthttpClient=null;StreamcontentStream=null;FileStreamfileStream=null;try{// 创建目录try{stringdirectory=Path.GetDirectoryName(savePath);if(!Directory.Exists(directory)){Directory.CreateDirectory(directory);}}catch(Exceptionex){InvokeOnError("创建目录",ex);return;}// 发起HTTP请求HttpResponseMessageresponse=null;try{httpClient=newHttpClient();httpClient.Timeout=TimeSpan.FromMinutes(30);vartask=httpClient.GetAsync(url,HttpCompletionOption.ResponseHeadersRead);response=task.Result;if(!response.IsSuccessStatusCode){thrownewHttpRequestException($"HTTP错误:{response.StatusCode}");}}catch(AggregateExceptionex){InvokeOnError("HTTP请求",ex.InnerException??ex);response?.Dispose();return;}catch(Exceptionex){InvokeOnError("网络请求",ex);response?.Dispose();return;}// 读取和写入文件try{vartotalBytes=response.Content.Headers.ContentLength;vartask=response.Content.ReadAsStreamAsync();contentStream=task.Result;try{fileStream=newFileStream(savePath,FileMode.Create,FileAccess.Write,FileShare.None,81920);}catch(Exceptionex){InvokeOnError("创建文件",ex);response?.Dispose();return;}varbuffer=newbyte[81920];longdownloadedBytes=0;intbytesRead;while((bytesRead=contentStream.Read(buffer,0,buffer.Length))>0){// 检查是否需要停止if(_shouldStop){InvokeOnCancelled();response?.Dispose();return;}// 写入文件try{fileStream.Write(buffer,0,bytesRead);downloadedBytes+=bytesRead;doublepercent=totalBytes.HasValue?(double)downloadedBytes/totalBytes.Value*100:0;InvokeOnProgress(downloadedBytes,totalBytes,percent);}catch(IOExceptionex){InvokeOnError("文件写入",ex);response?.Dispose();return;}catch(Exceptionex){InvokeOnError("写入数据",ex);response?.Dispose();return;}}// 下载完成InvokeOnCompleted();response?.Dispose();}catch(Exceptionex){InvokeOnError("文件操作",ex);response?.Dispose();return;}}finally{contentStream?.Close();fileStream?.Close();httpClient?.Dispose();lock(_lockObject){_isDownloading=false;}}}privatevoidInvokeOnProgress(longdownloaded,long?total,doublepercent){try{OnProgress?.Invoke(downloaded,total,percent);}catch(Exceptionex){Debug.LogError($"进度回调异常:{ex.Message}");}}privatevoidInvokeOnError(stringstage,Exceptionex){try{OnError?.Invoke(stage,ex);}catch(ExceptioncallbackEx){Debug.LogError($"错误回调异常:{callbackEx.Message}");}}privatevoidInvokeOnCompleted(){try{OnCompleted?.Invoke();}catch(Exceptionex){Debug.LogError($"完成回调异常:{ex.Message}");}}privatevoidInvokeOnCancelled(){try{OnCancelled?.Invoke();}catch(Exceptionex){Debug.LogError($"取消回调异常:{ex.Message}");}}publicvoidDispose(){StopDownload();if(_downloadThread!=null&&_downloadThread.IsAlive){_downloadThread.Join(TimeSpan.FromSeconds(5));}}}