Contents

AB包加载类封装

Contents
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Events;

public class AssetBundleManager : Single<AssetBundleManager>
{
    /// <summary>
    /// AB包路径
    /// </summary>
    private string PathURL
    {
        get
        {
            return $"{Application.streamingAssetsPath}/ab/{MainName}"; 
        }
    }

    /// <summary>
    /// 主包名字
    /// </summary>
    private string MainName
    {
        get
        {
#if UNITY_IOS
                return "IOS";
#elif UNITY_EDITOR_OSX
                return "StandaloneOSXUniversal";
#else
            return "StandaloneWindows";
#endif
        }
    }

    /// <summary>
    /// 依赖信息
    /// </summary>
    private AssetBundleManifest mainABM;

    /// <summary>
    /// AB包字典
    /// </summary>
    private readonly Dictionary<string, AssetBundle> abDict = new();

    /// <summary>
    /// 加载中的AB包
    /// </summary>
    private readonly HashSet<string> loadingName = new();


    /// <summary>
    /// 加载AB包资源
    /// </summary>
    /// <typeparam name="T">资源类型</typeparam>
    /// <param name="abName">AB包名</param>
    /// <param name="resName">资源名</param>
    /// <param name="callBack">回调函数</param>
    public void Load<T>(string abName, string resName, UnityAction<T> callBack, bool isAsync = true) where T : Object
    {
        PublicMono.Instance.StartCoroutine(LoadRes(abName, resName, callBack, isAsync));
    }

    /// <summary>
    /// 加载AB包资源携程
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="abName"></param>
    /// <param name="resName"></param>
    /// <param name="callBack"></param>
    /// <returns></returns>
    private IEnumerator LoadRes<T>(string abName, string resName, UnityAction<T> callBack, bool isAsync) where T : Object
    {
        yield return LoadAB(isAsync, MainName);//加载主包
        if (mainABM == null)//加载依赖信息
        {
            if (isAsync)
            {
                var mainABMRq = abDict[MainName].LoadAssetAsync<AssetBundleManifest>("AssetBundleManifest");
                yield return mainABMRq;
                mainABM = mainABMRq.asset as AssetBundleManifest;
            }
            else
            {
                mainABM = abDict[MainName].LoadAsset<AssetBundleManifest>("AssetBundleManifest");
            }
        }
        string[] strs = mainABM.GetAllDependencies(abName);//加载依赖
        if (strs.Length > 0) yield return LoadAB(isAsync, strs);
        yield return LoadAB(isAsync, abName);//加载AB包
        if (isAsync)//加载资源
        {
            var rq = abDict[abName].LoadAssetAsync<T>(resName);
            yield return rq;
            callBack?.Invoke(rq?.asset as T);
        }
        else
        {
            callBack?.Invoke(abDict[abName].LoadAsset<T>(resName));
        }
    }

    /// <summary>
    /// 加载AB包携程
    /// </summary>
    /// <param name="abNames"></param>
    /// <returns></returns>
    private IEnumerator LoadAB(bool isAsync, params string[] abNames)
    {
        foreach (var abName in abNames)
        {
            while (loadingName.Contains(abName)) yield return null;//如果这个ab包正在加载 就等他加载完成
            if (abDict.ContainsKey(abName)) continue;//如果字典中有直接进入下一次循环
            loadingName.Add(abName);
            if (isAsync)
            {
                var rq = AssetBundle.LoadFromFileAsync($"{PathURL}/{abName}");
                yield return rq;
                abDict.Add(abName, rq.assetBundle);
            }
            else
            {
                abDict.Add(abName, AssetBundle.LoadFromFile($"{PathURL}/{abName}"));
            }
            loadingName.Remove(abName);
        }
    }

    /// <summary>
    /// 卸载AB包
    /// </summary>
    /// <param name="abName">包名</param>
    /// <param name="callback">回调函数</param>
    /// <param name="unloadObjects">是否卸载场景上的资源</param>
    public void UnLoad(string abName, UnityAction callback = null, bool unloadObjects = false)
    {
        PublicMono.Instance.StartCoroutine(UnLoadAB(abName, callback, unloadObjects));
    }

    /// <summary>
    /// 卸载AB包携程
    /// </summary>
    /// <param name="abName"></param>
    /// <param name="callback"></param>
    /// <param name="unloadObjects"></param>
    /// <returns></returns>
    private IEnumerator UnLoadAB(string abName, UnityAction callback, bool unloadObjects)
    {
        //如果这个ab包正在加载 就等他加载完成后卸载
        while (loadingName.Contains(abName)) yield return null;
        if (abDict.ContainsKey(abName))
        {
            var op = abDict[abName].UnloadAsync(unloadObjects);
            yield return op;
            abDict.Remove(abName);
        }
        callback?.Invoke();
    }

    /// <summary>
    /// 卸载所有AB包
    /// </summary>
    /// <param name="callback">回调函数</param>
    /// <param name="unloadObjects">是否卸载场景上的资源</param>
    public void UnLoadAll(UnityAction callback = null, bool unloadObjects = false)
    {
        PublicMono.Instance.StartCoroutine(UnLoadAllAB(callback, unloadObjects));
    }

    /// <summary>
    /// 卸载全部AB包携程
    /// </summary>
    /// <param name="callback"></param>
    /// <param name="unloadObjects"></param>
    /// <returns></returns>
    private IEnumerator UnLoadAllAB(UnityAction callback, bool unloadObjects)
    {
        //等待所有的AB包加载完成后卸载
        while (loadingName.Count > 0) yield return null;
        AssetBundle.UnloadAllAssetBundles(unloadObjects);
        abDict.Clear();
        callback?.Invoke();
    }
}