using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Threading; using Cysharp.Threading.Tasks; using Stary.Evo.Unzip; using UnityEngine; using UnityEngine.Networking; #if WEIXINMINIGAME using WeChatWASM; #endif namespace Stary.Evo { public class ZipTool { private static SemaphoreSlim unzipLock = new(1, 1); // 新增:带进度回调的下载解压方法 public static async UniTask DownloadAndUnzipAsync(string fildId, string extractPath, Action downloadProgress = null, Action unzipProgress = null) { try { string url = $"{AppConfig.IpConfig}/FileLoad/Download/{fildId}"; #if !WEIXINMINIGAME string tempPath = Path.Combine(Application.persistentDataPath, "temp.zip"); await WebRequestSystem.GetFile(url, tempPath, downloadProgress); #else bool isCompleted = false; string tempPath = WX.env.USER_DATA_PATH + "/temp.zip"; // 指定保存路径 var downloadTask = WX.DownloadFile(new DownloadFileOption() { url = url, filePath = WX.env.USER_DATA_PATH + "/temp.zip", // 指定保存路径 success = (res) => { isCompleted = true; }, fail = (err) => { Debug.LogError("下载失败:" + err.errMsg); isCompleted = true; } }); // 注册进度回调(关键代码) downloadTask.OnProgressUpdate((res) => { // res.progress: 下载进度 0-100 // res.totalBytesExpectedToWrite: 预期总字节数 // res.totalBytesWritten: 已下载字节数 downloadProgress?.Invoke((float) res.progress); Debug.Log($"下载进度:{res.progress:F1}% | " + $"已下载:{res.totalBytesWritten / 1024}KB / " + $"总计:{res.totalBytesExpectedToWrite / 1024}KB"); }); // 等待完成或被取消 await new WaitUntil(() => isCompleted); // 等待下载完成,同时可以更新 UI // while (!isCompleted) // { // // 在这里更新 Unity UI 进度条 // UpdateProgressUI(currentProgress); // yield return null; // } // WX.GetFileSystemManager().Unzip(new UnzipOption() // { // zipFilePath = tempPath, // targetPath = extractPath, // success = (suc) => // { // Debug.Log("解压成功"); // File.Delete(tempPath); // }, // fail = (err) => // { // Debug.LogError($"解压失败:{err.errMsg}"); // } // }); #endif // 解压下载的文件 await CrossPlatformUnzip.UnzipAsync(tempPath, extractPath, unzipProgress); } catch (Exception ex) { Debug.LogError($"解压失败: {ex.Message}"); } } // 修改:添加进度回调参数 public static async UniTask UnzipAsync(string zipPath, string extractPath, Action progressCallback = null) { try { // 验证路径安全性 string fullExtractPath = Path.GetFullPath(extractPath); using (ZipArchive archive = ZipFile.OpenRead(zipPath)) { float totalEntries = archive.Entries.Count; float processed = 0; foreach (ZipArchiveEntry entry in archive.Entries) { // 安全检查:防止目录遍历 string filePath = Path.GetFullPath(Path.Combine(extractPath, entry.FullName)); if (!filePath.StartsWith(fullExtractPath)) { Debug.LogWarning($"跳过不安全的文件路径: {entry.FullName}"); continue; } Directory.CreateDirectory(Path.GetDirectoryName(filePath)); if (!string.IsNullOrEmpty(entry.Name)) { using (Stream inputStream = entry.Open()) using (FileStream outputStream = File.Create(filePath)) { await inputStream.CopyToAsync(outputStream, 81920); } } processed++; float progress = processed / totalEntries; progressCallback?.Invoke(progress); } } Debug.Log($"解压完成: {extractPath}"); } catch (Exception ex) { Debug.LogError($"解压失败: {ex.Message}"); throw; // 重新抛出异常让调用方处理 } } /// /// 自定义网络请求器需要登录 /// /// /// private static UnityWebRequest WebRequester(string url) { var request = new UnityWebRequest(url, UnityWebRequest.kHttpVerbGET); var authorization = GetAuthorization(AppConfig.UserName, AppConfig.PassWord); request.SetRequestHeader("AUTHORIZATION", authorization); return request; } private static string GetAuthorization(string userName, string password) { string auth = userName + ":" + password; var bytes = System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(auth); return "Basic " + System.Convert.ToBase64String(bytes); } } }