using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Events;
///
/// AB包管理器
///
public class AssetBundle_Manager_ : SingletonAutoMono
{
#region 变量
private Dictionary
private Dictionary
private AssetBundle abMain = null;//主包
private AssetBundleManifest abMainManifest = null;//主包依赖
private string abPath = Application.streamingAssetsPath;//AB包文件夹路径
public string ABPath
{
set => abPath = value;
get => abPath;
}
//主包名称,这里可以根据实际情况修改主包名称
private string ABMainName
{
get
{
#if UNITY_IOS
return "IOS";
#elif UNITY_ANDROID
return "Android";
#else
return "AB Package";
#endif
}
}
#endregion
#region 同步加载AB包
///
/// 加载主包以及主包配置文件
///
private bool LoadMainAB()
{
//加载主包
if (abMain == null)
{
//尝试加载AB包
string path = Path.Combine(ABPath, ABMainName);
abMain = AssetBundle.LoadFromFile(path);
//如果加载失败 则输出错误信息
if (abMain == null)
{
Debug.LogError($"主包加载失败!路径:{path}");
return false;
}
}
//加载主包的依赖配置文件
if (abMainManifest == null)
{
//尝试加载主包的AssetBundleManifest
abMainManifest = abMain.LoadAsset
//如果加载失败 则输出错误信息
if (abMainManifest == null)
{
Debug.LogError("主包的AssetBundleManifest加载失败!");
return false;
}
}
//如果主包和主包配置文件都加载成功 则返回true
return true;
}
///
/// 加载目标包
///
/// 目标包名称
private AssetBundle LoadTargetAB(string targetABName)
{
//如果主包和主包配置文件没有加载成功 则返回null
if (!LoadMainAB())
{
Debug.LogError("主包加载失败,无法加载目标包");
return null;
}
//获取所有依赖的名称
string[] dependenciesStrs = abMainManifest.GetAllDependencies(targetABName);
//加载所有依赖
foreach (string dependencyStr in dependenciesStrs)
{
//如果依赖包没有加载过 则加载依赖包
if (!abDic.ContainsKey(dependencyStr))
{
//尝试加载依赖包
var dependencyAB = AssetBundle.LoadFromFile(Path.Combine(ABPath, dependencyStr));
//如果加载失败 则输出错误信息
if (dependencyAB == null)
{
Debug.LogError($"依赖包加载失败!路径:{Path.Combine(ABPath, dependencyStr)}");
continue;
}
//将加载的依赖包存入字典
abDic.TryAdd(dependencyStr, dependencyAB);
}
}
//加载目标AB包
//如果目标AB包没有加载过 则加载目标AB包
if (!abDic.TryGetValue(targetABName, out var targetAB))
{
targetAB = AssetBundle.LoadFromFile(Path.Combine(ABPath, targetABName));
//如果加载失败 则输出错误信息
if (targetAB == null)
{
Debug.LogError($"目标AB包加载失败!路径:{Path.Combine(ABPath, targetABName)}");
return null;
}
//将加载的目标AB包存入字典
abDic.TryAdd(targetABName, targetAB);
}
//返回加载的目标AB包
return targetAB;
}
///
/// 生成资源Key
///
/// AB包
/// 资源包
/// 后缀
///
private string GenerateObjKey(string abName, string resName, string suffix = "")
{
return $"{abName}_{resName}_{suffix}_";
}
///
/// 加载资源的接口
///
/// 目标资源Key
/// 目标AB包
/// 目标资源名称
/// 回调函数
///
private UnityEngine.Object LoadResInternal(string objKey, string targetABName, string targetResName,Func
{
//如果资源容器中没有该资源
if (!objDic.TryGetValue(objKey, out UnityEngine.Object obj) || obj == null)
{
//则加载目标AB包
AssetBundle ab = LoadTargetAB(targetABName);
//如果加载失败 则返回null
if (ab == null)
{
Debug.LogError($"目标AB包加载失败:{targetABName}");
return null;
}
//加载目标资源
obj = callBack(ab);
//如果加载失败 则输出错误信息
if (obj == null)
{
Debug.LogError($"资源加载失败:AB包:{targetABName},资源名:{targetResName}");
return null;
}
else
{
//将加载的资源存入字典
objDic[objKey] = obj;
}
}
return obj;
}
///
/// 同步加载资源(以名称的形式加载资源)
///
/// 目标包
/// 目标资源
///
public UnityEngine.Object LoadABRes(string targetABName, string targetResName)
{
// 资源容器中存储的资源名称
string objKey = GenerateObjKey(targetABName, targetResName, "Name");
// 获取资源
return LoadResInternal(objKey, targetABName, targetResName, (ab) => ab.LoadAsset(targetResName));
}
///
/// 同步加载资源(以Type的形式加载资源)
///
/// 目标AB包名称
/// 目标资源名称
/// 目标资源类型
///
public UnityEngine.Object LoadABRes(string targetABName, string targetResName, System.Type type)
{
// 资源容器中存储的资源名称
string objKey = GenerateObjKey(targetABName, targetResName, "Type");
// 获取资源
return LoadResInternal(objKey, targetABName, targetResName, (ab) => ab.LoadAsset(targetResName, type));
}
///
/// 同步加载资源(以泛型加载资源)
///
///
/// 目标AB包名称
/// 目标资源名称
///
public T LoadABRes
{
// 资源容器中存储的资源名称
string objKey = GenerateObjKey(targetABName, targetResName, "Generics");
// 获取资源
return LoadResInternal(objKey, targetABName, targetResName, (ab) => ab.LoadAsset
}
#endregion
#region 异步加载AB包
///
/// 用于将带回调的协程包装成 Task
///
private Task
{
var tcs = new TaskCompletionSource
StartCoroutine(coroutineStarter((result) => tcs.SetResult(result), path));
return tcs.Task;
}
///
/// 加载主包以及主包配置文件
///
private IEnumerator LoadMainABAsyncCor(UnityAction
{
//加载主包
if (abMain == null)
{
//尝试加载AB包
AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync(path);
//等待AssetBundleCreateRequest完成
yield return abcr;
//如果加载失败 则输出错误信息
if (abcr.assetBundle == null)
{
Debug.LogError($"AssetBundleCreateRequest加载失败!");
yield break;
}
//获取加载的主包
abMain = abcr.assetBundle;
}
//加载主包的依赖配置文件
if (abMainManifest == null)
{
//尝试加载主包的AssetBundleManifest
AssetBundleRequest abr = abMain.LoadAssetAsync
yield return abr;
if (abr.asset == null)
{
Debug.LogError("AssetBundleRequest加载失败!");
yield break;
}
abMainManifest = abr.asset as AssetBundleManifest;
}
//如果主包和主包配置文件都加载成功 则执行回调函数
tcsCallBack?.Invoke(abMain);
}
///
/// 异步加载目标AB包的协程
///
/// 回调函数
/// 目标AB包
///
private IEnumerator LoadFromFileAsyncCor(UnityAction
{
//加载目标AB包
AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync(targetABName);
//等待AssetBundle加载完成
yield return abcr;
//如果加载失败 则输出错误信息
if (abcr.assetBundle == null)
{
Debug.LogError($"目标AssetBundleCreateRequest加载失败!");
yield break;
}
//获取加载的AssetBundle
AssetBundle ab = abcr.assetBundle;
//如果有回调函数 则执行回调
callBack?.Invoke(ab);
}
///
/// 异步加载目标AB包
///
/// 目标AB包名称
private async Task
{
await WrapCoroutine
//获取所有依赖的名称
string[] dependenciesStrs = abMainManifest.GetAllDependencies(targetABName);
//加载所有依赖
foreach (string dependencyStr in dependenciesStrs)
{
if (!abDic.ContainsKey(dependencyStr))
{
//尝试加载依赖包
var denpendencyAB = await WrapCoroutine
//如果加载失败 则输出错误信息
if (denpendencyAB == null)
{
Debug.LogError($"依赖包加载失败!路径:{Path.Combine(ABPath, dependencyStr)}");
continue;
}
//将加载的依赖包存入字典
abDic.TryAdd(dependencyStr, denpendencyAB);
}
}
//加载目标AB包
if (!abDic.TryGetValue(targetABName, out AssetBundle ab) || ab == null)
{
string path = Path.Combine(ABPath, targetABName);
ab = await WrapCoroutine
//如果加载失败 则输出错误信息
if (ab == null)
{
Debug.LogError($"目标AB包加载失败!路径:{path}");
return null;
}
//将加载的目标AB包存入字典
abDic.TryAdd(targetABName, ab);
}
//返回加载的目标AB包
return ab;
}
///
/// 用于封装异步加载资源的通用方法
///
///
/// 目标AB包名称
/// 目标资源名称
/// 资源存储的Key
/// 回调函数
/// 加载资源的委托
///
private async Task
{
//如果资源容器中已经有该资源 则执行回调并返回资源
if (objDic.TryGetValue(objKey, out UnityEngine.Object obj))
{
callBack?.Invoke(obj);
return obj as T;
}
//异步加载目标AB包
AssetBundle ab = await LoadTargetABAsync(targetABName);
//判断callBack2是否为null
if (loadRequestGetter == null)
{
Debug.LogError("加载函数 callBack2 为空!");
return null;
}
AssetBundleRequest abr = loadRequestGetter.Invoke(ab, targetResName);
//等待AssetBundleRequest完成
while (!abr.isDone)
{
await Task.Yield();
}
//判断加载的资源是否为null
if (abr.asset == null)
{
Debug.LogError("AssetBundleRequest加载失败!(资源为空)");
return null;
}
obj = abr.asset;
//如果有回调函数 则执行回调wo1
callBack?.Invoke(obj);
//将加载的资源存入字典
objDic[objKey] = obj;
return abr.asset as T;
}
///
/// 异步加载资源(以名称的形式加载资源)
///
/// 目标AB包
/// 目标资源
///
public async Task
{
//生成资源Key
string objKey = GenerateObjKey(targetABName, targetResName, "Name");
UnityEngine.Object obj = await AwaitAssetBundleRequest
//返回资源
return obj;
}
///
/// 异步加载资源(以Type的形式加载资源)
///
/// 目标AB包
/// 目标资源
/// 目标资源类型
///
public async Task
{
//生成资源Key
string objKey = GenerateObjKey(targetABName, targetResName, "Type");
UnityEngine.Object obj = await AwaitAssetBundleRequest
//返回资源
return obj;
}
///
/// 异步加载资源(以泛型加载资源)
///
///
/// 目标AB包
/// 目标资源
/// 目标类型
///
public async Task
{
//生成资源Key
string objKey = GenerateObjKey(targetABName, targetResName, "Generics");
T obj = await AwaitAssetBundleRequest
//返回资源
return obj;
}
#endregion
#region 同步卸载AB包
///
/// 单个包卸载
///
/// 目标包名称
public void UnLoadAB(string targetABName)
{
if(abDic.ContainsKey(targetABName))
{
abDic[targetABName].Unload(false);
abDic.Remove(targetABName);
}
}
///
/// 所有包卸载
///
public void UnLoadAllAB()
{
//卸载所有AB包
foreach (var ab in abDic)
{
ab.Value.Unload(false);
}
abDic.Clear();
// 卸载主包和主包配置文件
if (abMain != null)
{
abMain.Unload(false);
abMain = null;
}
if (abMainManifest != null)
{
abMainManifest = null;
}
}
#endregion
#region 异步卸载AB包
///
/// 异步卸载AB包的协程
///
/// 目标AB包名称
/// 回调函数
///
private IEnumerator UnLoadABAsyncCor(string targetABName, UnityAction
{
//先在字典中查找目标AB包
if (abDic.ContainsKey(targetABName))
{
//等待一帧以确保资源加载完成
yield return null;
//卸载目标AB包
abDic[targetABName].Unload(false);
//从字典中移除目标AB包
bool isSuccess = abDic.Remove(targetABName);
//执行回调函数
callBack?.Invoke(isSuccess);
}
}
///
/// 异步卸载AB包
///
/// 目标包名称
/// 回调函数
///
public Task
{
//使用TaskCompletionSource来封装异步操作
var tcs = new TaskCompletionSource
//开始协程卸载AB包
StartCoroutine(UnLoadABAsyncCor(targetABName, (b) => { tcs.SetResult(b); }));
//执行回调函数
callBack?.Invoke();
//返回一个Task对象来判断当前协程是否完成
return tcs.Task;
}
///
/// 清空所有AB包的协程
///
/// 回调函数
///
private IEnumerator UnLoadAllABAsyncCor(UnityAction
{
//卸载内存中所有的AB包
AssetBundle.UnloadAllAssetBundles(false);
//清空字典
abDic.Clear();
//执行回调函数
callBack?.Invoke(true);
//等待一帧以确保资源加载完成
yield return null;
}
///
/// 删除所有AB包的异步方法
///
/// 回调函数
///
public Task
{
//使用TaskCompletionSource来封装异步操作
var tcs = new TaskCompletionSource
//开始协程卸载所有AB包
StartCoroutine(UnLoadAllABAsyncCor( (b) => { tcs.SetResult(b); }));
//执行回调函数
callBack?.Invoke();
return tcs.Task;
}
///
/// 清理objDic里的缓存资源
///
public void ClearUnusedObjects()
{
List
foreach (var kvp in objDic)
{
if (kvp.Value == null) toRemove.Add(kvp.Key);
}
foreach (var key in toRemove)
{
objDic.Remove(key);
}
}
#endregion
#region objDic相关操作
///
/// 清空objDic里的缓存资源
///
public void ClearObjDic()
{
if (objDic.Count > 0)
{
objDic.Clear();
}
}
#endregion
}