Unity使用UnityWebRequest下载多AssetBundle缓存丢失无法离线加载问题
问题根因
你遇到的缓存丢失问题主要由两个原因导致:
- Unity默认的AssetBundle全局缓存有空间上限,当新下载的包体总大小超出上限时,系统会自动删除最早下载的旧缓存,就会出现下载B后A被清理、多包先后加载都丢失的情况。
- 移动端系统的存储空间清理机制也可能会主动清理Unity的默认缓存目录,完全依赖默认缓存很容易出现离线加载失败的问题。
解决方案
1. 调整默认缓存规则,避免自动清理
在项目初始化阶段(比如启动页Awake逻辑中)先修改默认缓存的配置,根据业务需求设置足够大的容量,或者设置缓存永不过期:
// 设置缓存最大容量为10GB,单位为字节,可根据实际需求调整 Caching.defaultCache.maximumAvailableDiskSpace = 10L * 1024 * 1024 * 1024; // 额外设置缓存永不过期,不会被系统自动清理 Caching.defaultCache.expirationDelay = -1;
2. 增加自主持久化存储逻辑(最稳妥方案,完全规避缓存被清理问题)
不要完全依赖Unity的默认缓存,下载到AB包后主动把包体字节存到Application.persistentDataPath下的自定义目录,离线加载时优先读本地文件,只有本地没有对应版本的包时才走联网下载。
注意:自主存储AB包时,建议同时把对应包的版本号、CRC值存在本地配置文件里,加载前先校验本地包的版本是否和服务端一致,避免加载旧资源。
3. 优化代码逻辑
调整后的完整实现示例如下,同时兼容缓存加载、本地存储加载、联网下载三种场景:
// 先判断对应版本的AB包是否已经在缓存里,存在的话可以直接加载不需要联网 if (Caching.IsVersionCached(url, bundleData.version, bundleData.crc)) { using UnityWebRequest uwr = UnityWebRequestAssetBundle.GetAssetBundle(url, bundleData.version, bundleData.crc); yield return uwr.SendWebRequest(); LoadAssetAndCallback(uwr, bundleData, levelText, isDiff, callback); yield break; } // 缓存不存在,先尝试读本地持久化存储的包 string localSavePath = Path.Combine(Application.persistentDataPath, "AssetBundles", bundleData.name); if (File.Exists(localSavePath)) { AssetBundle localBundle = AssetBundle.LoadFromFile(localSavePath); if (localBundle != null) { Sprite sprite = isDiff ? localBundle.LoadAsset<Sprite>(levelText + "Diff") : localBundle.LoadAsset<Sprite>(levelText); callback(sprite); localBundle.Unload(false); yield break; } } // 本地也没有,走联网下载逻辑 using UnityWebRequest downloadUwr = UnityWebRequestAssetBundle.GetAssetBundle(url, bundleData.version, bundleData.crc); yield return downloadUwr.SendWebRequest(); if (downloadUwr.result != UnityWebRequest.Result.Success) { Debug.Log("下载失败:" + downloadUwr.error); callback(null); yield break; } // 下载成功后主动存到本地持久化目录 Directory.CreateDirectory(Path.GetDirectoryName(localSavePath)); File.WriteAllBytes(localSavePath, downloadUwr.downloadHandler.data); LoadAssetAndCallback(downloadUwr, bundleData, levelText, isDiff, callback); // 封装统一的资源加载回调方法 void LoadAssetAndCallback(UnityWebRequest uwr, BundleData bundleData, string levelText, bool isDiff, Action<Sprite> callback) { AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(uwr); if (bundle == null) { Debug.Log("COULDN'T LOAD ASSET BUNDLE"); callback(null); return; } Sprite sprite = isDiff ? bundle.LoadAsset<Sprite>(levelText + "Diff") : bundle.LoadAsset<Sprite>(levelText); callback(sprite); // 资源加载完成后卸载AB包,避免内存泄漏,false表示仅卸载包体不卸载已加载的资源 bundle.Unload(false); }
内容的提问来源于stack exchange,提问作者Volkan Ege Dindar
相关产品推荐
相关产品推荐

