killapp/Assets/Scripts/Network/NetworkCtrl.cs
“虞渠成” ed4a57b29d 0611
2026-06-11 11:17:27 +08:00

1091 lines
36 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
using Kill.Network;
using Kill.Managers;
using Kill.Core;
using Kill.UI.Components;
using UnityEngine.UI;
namespace Kill.Network
{
/// <summary>
/// 请求头配置
/// </summary>
[System.Serializable]
public class HeaderConfig
{
public string key;
public string value;
}
public class NetworkCtrl : MonoBehaviour
{
public static NetworkCtrl Instance;
public string localPath;
public string streamingPath;
#region -
public string[] serverBaseUrls;
[Header("服务器配置")]
[Tooltip("服务器基础URL例如: https://api.example.com")]
public string serverBaseUrl = "https://api.example.com";
[Header("请求配置")]
[Tooltip("默认请求超时时间(秒)")]
public int defaultTimeout = 30;
[Tooltip("默认最大重试次数")]
public int defaultMaxRetries = 3;
[Tooltip("是否使用指数退避重试")]
public bool useExponentialBackoff = true;
[Header("全局请求头")]
[Tooltip("添加全局请求头如Authorization等")]
public List<HeaderConfig> globalHeaders = new List<HeaderConfig>
{
// 示例: 在这里添加你的全局请求头
// new HeaderConfig { key = "Authorization", value = "Bearer your_token" },
// new HeaderConfig { key = "X-App-Version", value = "1.0.0" },
new HeaderConfig { key = "Content-Type", value = "application/json" },
};
[Header("队列配置")]
[Tooltip("最大并发请求数")]
public int maxConcurrentRequests = 5;
#endregion
public string BaseServerUrl { get; set; } = "";
void Awake()
{
Instance = this;
localPath = Application.persistentDataPath;
streamingPath = Application.streamingAssetsPath;
// 设置目标帧率为 60 FPS
Application.targetFrameRate = 120;
// 禁用垂直同步,允许更高帧率
QualitySettings.vSyncCount = 0;
#if UNITY_ANDROID
AndroidStatusBar.statusBarState = AndroidStatusBar.States.TranslucentOverContent;
#endif
}
async void Start()
{
#if UNITY_IOS
platform = "IOS";
#else
platform = "ANDROID";
#endif
Debug.Log("Init");
await Init();
}
public async Task Init()
{
Debug.Log("初始化网络控制");
// 初始化网络管理器
await InitializeNetworkManagers();
await NetworkStateManager.Instance.Init();
await GetNewBundle();
// 检查并清理过期资源
await CheckAndCleanOutdatedResources();
if (LoadRes.Instance.resPosition == LoadRes.ResPosition.)
{
await GetNowBundleList();
if (nowResVersion < new Version(resourceVersion))
{
LoadingUI.Show();
await GetBundleList();
LoadingUI.Hide();
await UpdateResources();
}
}
await LoadRes.Instance.Init();
await DataManager.Instance.Init();
await UI.UIManager.Instance.Init();
}
/// <summary>
/// 初始化网络管理器组件
/// </summary>
private async Task InitializeNetworkManagers()
{
// 确保 NetworkStateManager 存在
if (NetworkStateManager.Instance == null)
{
var nsManagerObj = new GameObject("NetworkStateManager");
nsManagerObj.AddComponent<NetworkStateManager>();
}
// 确保 HttpRequestManager 存在并配置
if (HttpRequestManager.Instance == null)
{
var httpManagerObj = new GameObject("HttpRequestManager");
httpManagerObj.AddComponent<HttpRequestManager>();
}
// 配置 HttpRequestManager
var httpManager = HttpRequestManager.Instance;
if (httpManager != null)
{
// 设置基础URL
if (!string.IsNullOrEmpty(serverBaseUrl))
{
httpManager.SetBaseUrl(serverBaseUrl);
BaseServerUrl = serverBaseUrl;
}
// 设置默认配置
var config = new HttpRequestConfig
{
Timeout = defaultTimeout,
MaxRetries = defaultMaxRetries,
UseExponentialBackoff = useExponentialBackoff
};
httpManager.SetDefaultConfig(config);
// 添加全局请求头
foreach (var header in globalHeaders)
{
if (!string.IsNullOrEmpty(header.key))
{
httpManager.AddGlobalHeader(header.key, header.value);
}
}
}
// 确保 RequestQueueManager 存在并配置
if (RequestQueueManager.Instance == null)
{
var queueManagerObj = new GameObject("RequestQueueManager");
var queueManager = queueManagerObj.AddComponent<RequestQueueManager>();
queueManager.SetMaxConcurrentRequests(maxConcurrentRequests);
}
Debug.Log($"[NetworkCtrl] 网络管理器初始化完成 - 服务器: {serverBaseUrl}");
}
#region 便API
/// <summary>
/// 发送GET请求
/// </summary>
public async Task<HttpResponse<T>> Get<T>(string url, Dictionary<string, string> queryParams = null, HttpRequestConfig config = null)
{
return await HttpRequestManager.Instance.Get<T>(url, queryParams, config);
}
/// <summary>
/// 发送GET请求(返回字符串)
/// </summary>
public async Task<HttpResponse<string>> Get(string url, Dictionary<string, string> queryParams = null, HttpRequestConfig config = null)
{
return await HttpRequestManager.Instance.Get(url, queryParams, config);
}
/// <summary>
/// 发送POST请求
/// </summary>
public async Task<HttpResponse<T>> Post<T>(string url, object data = null, HttpRequestConfig config = null)
{
return await HttpRequestManager.Instance.Post<T>(url, data, config);
}
/// <summary>
/// 发送POST请求(表单数据)
/// </summary>
public async Task<HttpResponse<T>> PostForm<T>(string url, WWWForm formData, HttpRequestConfig config = null)
{
return await HttpRequestManager.Instance.PostForm<T>(url, formData, config);
}
public async Task<HttpResponse<T>> PostFormData<T>(string url, List<IMultipartFormSection> formData, HttpRequestConfig config = null)
{
return await HttpRequestManager.Instance.PostFormData<T>(url, formData, config);
}
/// <summary>
/// 发送PUT请求
/// </summary>
public async Task<HttpResponse<T>> Put<T>(string url, object data = null, HttpRequestConfig config = null)
{
return await HttpRequestManager.Instance.Put<T>(url, data, config);
}
/// <summary>
/// 发送PUTform请求
/// </summary>
public async Task<HttpResponse<T>> PutForm<T>(string url, WWWForm formData, HttpRequestConfig config = null)
{
return await HttpRequestManager.Instance.PutForm<T>(url, formData, config);
}
/// <summary>
/// 发送DELETE请求
/// </summary>
public async Task<HttpResponse<T>> Delete<T>(string url, object data = null, HttpRequestConfig config = null)
{
if (data != null)
{
return await HttpRequestManager.Instance.Delete<T>(url, data, config);
}
return await HttpRequestManager.Instance.Delete<T>(url, config);
}
/// <summary>
/// 下载文件
/// </summary>
public async Task<HttpResponse<string>> DownloadFile(string url, string savePath, Action<DownloadProgress> onProgress = null, HttpRequestConfig config = null)
{
return await HttpRequestManager.Instance.DownloadFile(url, savePath, onProgress, config);
}
/// <summary>
/// 添加请求到队列
/// </summary>
public string EnqueueRequest<T>(Func<Task<HttpResponse<T>>> requestFunc, RequestPriority priority = RequestPriority.Normal, Action<HttpResponse<T>> onComplete = null)
{
return RequestQueueManager.Instance.Enqueue(requestFunc, priority, onComplete);
}
/// <summary>
/// 取消请求
/// </summary>
public bool CancelRequest(string requestId)
{
return RequestQueueManager.Instance.CancelRequest(requestId);
}
/// <summary>
/// 取消所有请求
/// </summary>
public void CancelAllRequests()
{
RequestQueueManager.Instance.CancelAllRequests();
}
/// <summary>
/// 检查网络状态
/// </summary>
public bool IsNetworkConnected
{
get
{
return NetworkStateManager.Instance != null && NetworkStateManager.Instance.IsConnected;
}
}
/// <summary>
/// 获取当前网络类型
/// </summary>
public NetworkConnectivityState CurrentNetworkState
{
get
{
return NetworkStateManager.Instance != null ? NetworkStateManager.Instance.CurrentState : NetworkConnectivityState.Unknown;
}
}
#endregion
#region
/// <summary>
/// 设置服务器基础URL
/// </summary>
public void SetServerUrl(string baseUrl)
{
BaseServerUrl = baseUrl;
if (HttpRequestManager.Instance != null)
{
HttpRequestManager.Instance.SetBaseUrl(baseUrl);
}
}
/// <summary>
/// 添加全局请求头
/// </summary>
public void AddGlobalHeader(string key, string value)
{
HttpRequestManager.Instance?.AddGlobalHeader(key, value);
}
/// <summary>
/// 移除全局请求头
/// </summary>
public void RemoveGlobalHeader(string key)
{
HttpRequestManager.Instance?.RemoveGlobalHeader(key);
}
/// <summary>
/// 设置默认请求超时时间
/// </summary>
public void SetDefaultTimeout(int seconds)
{
var config = new HttpRequestConfig { Timeout = seconds };
HttpRequestManager.Instance?.SetDefaultConfig(config);
}
/// <summary>
/// 设置默认最大重试次数
/// </summary>
public void SetDefaultMaxRetries(int retries)
{
var config = new HttpRequestConfig { MaxRetries = retries };
HttpRequestManager.Instance?.SetDefaultConfig(config);
}
#endregion
#region ()
string nowResourceUrl;
public string resourceVersion;
string platform;
Version nowResVersion = new Version("0.0.0");
public AssetBundleInfoList nowBundleList;
public AssetBundleInfoList newBundleList;
public async Task GetNowBundleList()
{
string localListPath = localPath + "/list.json";
string streamingListPath = streamingPath + "/list.json";
if (File.Exists(localListPath))
{
nowBundleList = JsonUtility.FromJson<AssetBundleInfoList>(File.ReadAllText(localListPath));
Debug.Log("===获取本地资源列表成功");
}
else
{
string listJson = await ReadTextFileFromStreamingAssets(streamingListPath);
if (!string.IsNullOrEmpty(listJson))
{
nowBundleList = JsonUtility.FromJson<AssetBundleInfoList>(listJson);
Debug.Log("===获取更包资源列表成功");
}
else
{
Debug.Log("===没有获取资源列表");
nowBundleList = null;
}
}
if (nowBundleList != null)
{
nowResVersion = new Version(nowBundleList.version);
}
}
/// <summary>
/// 检查并清理过期的本地资源
/// </summary>
public async Task CheckAndCleanOutdatedResources()
{
try
{
string streamingListPath = Path.Combine(streamingPath, "list.json");
string streamingListJson = await ReadTextFileFromStreamingAssets(streamingListPath);
if (string.IsNullOrEmpty(streamingListJson))
{
return;
}
AssetBundleInfoList streamingBundleList = JsonUtility.FromJson<AssetBundleInfoList>(streamingListJson);
string localListPath = Path.Combine(localPath, "list.json");
if (!File.Exists(localListPath))
{
return;
}
string localListJson = File.ReadAllText(localListPath);
AssetBundleInfoList localBundleList = JsonUtility.FromJson<AssetBundleInfoList>(localListJson);
if (new Version(streamingBundleList.version) >= new Version(localBundleList.version))
{
Debug.Log($"跟包资源版本: {localBundleList.version} -> {streamingBundleList.version},正在清理本地过期资源...");
CleanLocalAssetBundleFiles();
}
else
{
Debug.Log($"本地资源版本({localBundleList.version})更新,无需清理");
}
}
catch (Exception ex)
{
Debug.LogError($"检查资源版本时出错: {ex.Message}");
}
}
/// <summary>
/// 清理本地的所有AssetBundle文件
/// </summary>
private void CleanLocalAssetBundleFiles()
{
try
{
string[] localAbFiles = Directory.GetFiles(localPath, "*.ab", SearchOption.AllDirectories);
foreach (string abFile in localAbFiles)
{
try
{
File.Delete(abFile);
Debug.Log($"已删除过期资源文件: {abFile}");
}
catch (Exception ex)
{
Debug.LogError($"删除文件失败 {abFile}: {ex.Message}");
}
}
File.Delete(localPath + "/list.json");
Debug.Log("本地过期资源清理完成");
}
catch (Exception ex)
{
Debug.LogError($"清理本地资源时出错: {ex.Message}");
}
}
public async Task GetBundleList()
{
string url = nowResourceUrl + "/list.json";
using (UnityWebRequest webRequest = UnityWebRequest.Get(url))
{
var operation = webRequest.SendWebRequest();
while (!operation.isDone)
{
await Task.Yield();
}
if (webRequest.result == UnityWebRequest.Result.Success)
{
AssetBundleInfoList list = JsonUtility.FromJson<AssetBundleInfoList>(webRequest.downloadHandler.text);
newBundleList = list;
}
else
{
Debug.LogError(url + "获取资源列表失败" + webRequest.error);
}
}
}
/// <summary>
/// 从StreamingAssets目录读取文本文件兼容各平台
/// </summary>
private async Task<string> ReadTextFileFromStreamingAssets(string filePath)
{
string result = null;
#if UNITY_ANDROID && !UNITY_EDITOR
UnityWebRequest www = UnityWebRequest.Get(filePath);
var operation = www.SendWebRequest();
while (!operation.isDone)
{
await Task.Yield();
}
if (www.result == UnityWebRequest.Result.Success)
{
result = www.downloadHandler.text;
}
else
{
Debug.LogError($"读取StreamingAssets文件失败: {www.error}");
}
www.Dispose();
#else
if (File.Exists(filePath))
{
result = File.ReadAllText(filePath);
}
#endif
return result;
}
public async Task UpdateResources()
{
List<AssetBundleInfo> updateList = GetUpdateList();
if (updateList.Count > 0)
{
UpdateLoadingUI.Instance.Show();
bool success = await DownloadUpdateFiles(updateList, (downloaded, total) =>
{
float progress = (float)downloaded / total;
UpdateLoadingUI.Instance.SetPrecent(progress);
Debug.Log($"更新进度: {progress:P}");
});
UpdateLoadingUI.Instance.Hide();
if (success)
{
Debug.Log("资源更新完成");
}
else
{
ToastUI.ShowText("resource error");
Debug.LogError("资源更新失败");
}
}
else
{
Debug.Log("资源已是最新版本");
}
}
/// <summary>
/// 对比当前资源列表和新资源列表,找出需要更新的文件
/// </summary>
public List<AssetBundleInfo> GetUpdateList()
{
List<AssetBundleInfo> updateList = new List<AssetBundleInfo>();
if (nowBundleList == null || nowBundleList.assetbundles == null)
{
return newBundleList.assetbundles ?? new List<AssetBundleInfo>();
}
Dictionary<string, AssetBundleInfo> nowBundleDict = new Dictionary<string, AssetBundleInfo>();
foreach (var bundle in nowBundleList.assetbundles)
{
nowBundleDict[bundle.name] = bundle;
}
foreach (var newBundle in newBundleList.assetbundles)
{
if (!nowBundleDict.ContainsKey(newBundle.name) ||
nowBundleDict[newBundle.name].md5 != newBundle.md5)
{
updateList.Add(newBundle);
}
}
return updateList;
}
/// <summary>
/// 计算需要更新的总大小
/// </summary>
public long CalculateUpdateSize(List<AssetBundleInfo> updateList)
{
long totalSize = 0;
foreach (var bundle in updateList)
{
totalSize += bundle.size;
}
return totalSize;
}
/// <summary>
/// 下载更新文件并实时返回进度
/// </summary>
public async Task<bool> DownloadUpdateFiles(List<AssetBundleInfo> updateList, Action<long, long> progressCallback)
{
long totalSize = CalculateUpdateSize(updateList);
long downloadedSize = 0;
if (nowBundleList == null || nowBundleList.assetbundles == null)
{
nowBundleList = new AssetBundleInfoList(new List<AssetBundleInfo>());
}
Dictionary<string, AssetBundleInfo> nowBundleDict = new Dictionary<string, AssetBundleInfo>();
foreach (var bundle in nowBundleList.assetbundles)
{
nowBundleDict[bundle.name] = bundle;
}
foreach (var bundle in updateList)
{
string url = nowResourceUrl + $"/{bundle.name}";
string savePath = Path.Combine(localPath, bundle.name);
string directory = Path.GetDirectoryName(savePath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
bool downloadSuccess = await DownloadSingleFile(url, savePath, bundle.md5);
if (!downloadSuccess)
{
Debug.LogError($"下载文件失败: {bundle.name}");
return false;
}
nowBundleDict[bundle.name] = bundle;
downloadedSize += bundle.size;
progressCallback?.Invoke(downloadedSize, totalSize);
await Task.Yield();
}
nowBundleList.assetbundles = new List<AssetBundleInfo>(nowBundleDict.Values);
nowBundleList.version = resourceVersion;
SaveNewBundleList();
return true;
}
/// <summary>
/// 下载单个文件并校验MD5
/// </summary>
private async Task<bool> DownloadSingleFile(string url, string savePath, string expectedMd5)
{
int maxRetries = 5;
for (int i = 0; i <= maxRetries; i++)
{
using (UnityWebRequest webRequest = UnityWebRequest.Get(url))
{
var operation = webRequest.SendWebRequest();
while (!operation.isDone)
{
await Task.Yield();
}
if (webRequest.result == UnityWebRequest.Result.Success)
{
File.WriteAllBytes(savePath, webRequest.downloadHandler.data);
string actualMd5 = CalculateMD5(savePath);
if (actualMd5.ToLower() == expectedMd5.ToLower())
{
return true;
}
else
{
Debug.LogError($"MD5校验失败 {url}: 期望 {expectedMd5}, 实际 {actualMd5}");
if (File.Exists(savePath))
{
File.Delete(savePath);
}
}
}
else
{
Debug.LogError($"下载失败 {url}: {webRequest.error} (尝试 {i + 1}/{maxRetries + 1})");
}
if (i < maxRetries)
{
await Task.Delay(1000 * (i + 1));
}
}
}
return false;
}
/// <summary>
/// 计算文件的MD5值
/// </summary>
public string CalculateMD5(string filePath)
{
using (var md5 = System.Security.Cryptography.MD5.Create())
{
using (var stream = File.OpenRead(filePath))
{
byte[] hash = md5.ComputeHash(stream);
return BitConverter.ToString(hash).Replace("-", "").ToLower();
}
}
}
/// <summary>
/// 保存新的资源列表到本地
/// </summary>
public void SaveNewBundleList()
{
if (newBundleList != null)
{
string json = JsonUtility.ToJson(newBundleList, true);
string savePath = Path.Combine(localPath, "list.json");
File.WriteAllText(savePath, json);
Debug.Log("新的资源列表已保存到本地");
}
}
#endregion
#region
/// <summary>
/// 图片缓存目录名
/// </summary>
private const string IMAGE_CACHE_DIR = "ImageCache";
/// <summary>
/// 获取图片缓存目录路径
/// </summary>
private string GetImageCacheDirectory()
{
string cacheDir = Path.Combine(localPath, IMAGE_CACHE_DIR);
if (!Directory.Exists(cacheDir))
{
Directory.CreateDirectory(cacheDir);
}
return cacheDir;
}
/// <summary>
/// 根据URL生成缓存文件名使用MD5哈希
/// </summary>
private string GetCacheFileName(string url)
{
using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
{
byte[] hashBytes = md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(url));
string hashString = BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
// 尝试从URL获取扩展名如果没有则使用.jpg
string extension = ".jpg";
try
{
string urlPath = new Uri(url).AbsolutePath;
string urlExt = Path.GetExtension(urlPath);
if (!string.IsNullOrEmpty(urlExt))
{
extension = urlExt;
}
}
catch { }
return hashString + extension;
}
}
/// <summary>
/// 获取图片缓存的完整路径
/// </summary>
private string GetImageCachePath(string url)
{
string cacheDir = GetImageCacheDirectory();
string fileName = GetCacheFileName(url);
return Path.Combine(cacheDir, fileName);
}
/// <summary>
/// 检查图片是否已缓存
/// </summary>
public bool IsImageCached(string url)
{
string cachePath = GetImageCachePath(url);
return File.Exists(cachePath);
}
/// <summary>
/// 加载网络图片(带缓存)
/// </summary>
/// <param name="url">图片URL</param>
/// <param name="onProgress">下载进度回调 (0-1)</param>
/// <returns>Texture2D对象失败返回null</returns>
public async Task<Texture2D> LoadImageAsync(string url, Action<float> onProgress = null)
{
if (string.IsNullOrEmpty(url))
{
Debug.LogWarning("[NetworkCtrl] 图片URL为空");
return null;
}
// 首先检查本地缓存
string cachePath = GetImageCachePath(url);
if (File.Exists(cachePath))
{
Debug.Log($"[NetworkCtrl] 从缓存加载图片: {url}");
return await LoadImageFromCacheAsync(cachePath);
}
// 从网络下载
Debug.Log($"[NetworkCtrl] 从网络下载图片: {url}");
return await DownloadAndCacheImageAsync(url, cachePath, onProgress);
}
/// <summary>
/// 从本地缓存加载图片
/// </summary>
private async Task<Texture2D> LoadImageFromCacheAsync(string cachePath)
{
try
{
byte[] imageData = await File.ReadAllBytesAsync(cachePath);
Texture2D texture = new Texture2D(2, 2, TextureFormat.RGBA32, false);
if (texture.LoadImage(imageData))
{
return texture;
}
else
{
Debug.LogError($"[NetworkCtrl] 缓存图片加载失败: {cachePath}");
// 删除损坏的缓存文件
File.Delete(cachePath);
return null;
}
}
catch (Exception ex)
{
Debug.LogError($"[NetworkCtrl] 读取缓存图片失败: {ex.Message}");
return null;
}
}
/// <summary>
/// 下载并缓存图片
/// </summary>
private async Task<Texture2D> DownloadAndCacheImageAsync(string url, string cachePath, Action<float> onProgress)
{
try
{
using (UnityWebRequest request = UnityWebRequest.Get(url))
{
request.downloadHandler = new DownloadHandlerBuffer();
var operation = request.SendWebRequest();
// 报告进度
while (!operation.isDone)
{
onProgress?.Invoke(request.downloadProgress);
await Task.Yield();
}
onProgress?.Invoke(1f);
if (request.result == UnityWebRequest.Result.Success)
{
byte[] imageData = request.downloadHandler.data;
// 保存到缓存
try
{
await File.WriteAllBytesAsync(cachePath, imageData);
Debug.Log($"[NetworkCtrl] 图片已缓存: {cachePath}");
}
catch (Exception ex)
{
Debug.LogWarning($"[NetworkCtrl] 图片缓存保存失败: {ex.Message}");
}
// 创建Texture2D
Texture2D texture = new Texture2D(2, 2, TextureFormat.RGBA32, false);
if (texture.LoadImage(imageData))
{
return texture;
}
else
{
Debug.LogError($"[NetworkCtrl] 图片数据解析失败: {url}");
Destroy(texture);
return null;
}
}
else
{
Debug.LogError($"[NetworkCtrl] 图片下载失败: {url}, 错误: {request.error}");
return null;
}
}
}
catch (Exception ex)
{
Debug.LogError($"[NetworkCtrl] 下载图片异常: {ex.Message}");
return null;
}
}
/// <summary>
/// 加载图片并应用到Image组件带缓存
/// </summary>
/// <param name="url">图片URL</param>
/// <param name="image">UI Image组件</param>
/// <param name="onProgress">下载进度回调</param>
public async Task LoadImageToUIImageAsync(string url, Image image, Action<float> onProgress = null)
{
if (image == null)
{
Debug.LogWarning("[NetworkCtrl] Image组件为空");
return;
}
Texture2D texture = await LoadImageAsync(url, onProgress);
if (texture != null)
{
Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.one * 0.5f);
image.sprite = sprite;
}
image.gameObject.SetActive(true);
}
/// <summary>
/// 加载图片并应用到RawImage组件带缓存
/// </summary>
public async Task LoadImageToUIRawImageAsync(string url, RawImage rawImage, Action<float> onProgress = null)
{
if (rawImage == null)
{
Debug.LogWarning("[NetworkCtrl] RawImage组件为空");
return;
}
Texture2D texture = await LoadImageAsync(url, onProgress);
if (texture != null)
{
rawImage.texture = texture;
}
}
/// <summary>
/// 加载图片并应用到SpriteRenderer带缓存
/// </summary>
public async Task LoadImageToSpriteRendererAsync(string url, SpriteRenderer spriteRenderer, Action<float> onProgress = null)
{
if (spriteRenderer == null)
{
Debug.LogWarning("[NetworkCtrl] SpriteRenderer组件为空");
return;
}
Texture2D texture = await LoadImageAsync(url, onProgress);
if (texture != null)
{
Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.one * 0.5f);
spriteRenderer.sprite = sprite;
}
}
/// <summary>
/// 清除指定URL的图片缓存
/// </summary>
public void ClearImageCache(string url)
{
string cachePath = GetImageCachePath(url);
if (File.Exists(cachePath))
{
File.Delete(cachePath);
Debug.Log($"[NetworkCtrl] 已清除图片缓存: {url}");
}
}
/// <summary>
/// 清除所有图片缓存
/// </summary>
public void ClearAllImageCache()
{
string cacheDir = GetImageCacheDirectory();
if (Directory.Exists(cacheDir))
{
string[] files = Directory.GetFiles(cacheDir);
foreach (string file in files)
{
try
{
File.Delete(file);
}
catch (Exception ex)
{
Debug.LogWarning($"[NetworkCtrl] 删除缓存文件失败: {ex.Message}");
}
}
Debug.Log($"[NetworkCtrl] 已清除所有图片缓存,共 {files.Length} 个文件");
}
}
/// <summary>
/// 获取图片缓存总大小(字节)
/// </summary>
public long GetImageCacheSize()
{
string cacheDir = GetImageCacheDirectory();
if (!Directory.Exists(cacheDir))
return 0;
long totalSize = 0;
string[] files = Directory.GetFiles(cacheDir);
foreach (string file in files)
{
try
{
FileInfo fileInfo = new FileInfo(file);
totalSize += fileInfo.Length;
}
catch { }
}
return totalSize;
}
/// <summary>
/// 获取图片缓存文件数量
/// </summary>
public int GetImageCacheCount()
{
string cacheDir = GetImageCacheDirectory();
if (!Directory.Exists(cacheDir))
return 0;
return Directory.GetFiles(cacheDir).Length;
}
public async Task GetNewBundle()
{
LoadingUI.Show();
var response = await Instance.Get<BundleDataResponse>($"/api/v1/app/version/bundle?version={Application.version}&platform={platform}");
ResponseCodeHandler.HandleResponse(response,
onSuccess: (data) =>
{
resourceVersion=data.data.bundle_version;
nowResourceUrl=data.data.bundle_url;
}
);
LoadingUI.Hide();
}
#endregion
#region
#endregion
}
#region
/// <summary>
/// 设备控制指令请求
/// </summary>
[System.Serializable]
public class DeviceControlRequest
{
public string device_sn;
public string command;
}
/// <summary>
/// 设备控制指令响应
/// </summary>
[System.Serializable]
public class DeviceControlResponse
{
public string code;
public string message;
}
#endregion
}