基于Unity2017版本的AB技术
1.项目中成百上千的大量资源需要(批量)打包处理,不可能手工维护方式给每个资源添加ab"包名称"
2.Unity对包依赖关系不是很完善
如果要加载一个多重依赖项的AB包,需要手工写代码,把底层所有依赖包关系需要预先进行加载后才可以。
3.AB包商业应用 步骤有 AB包加载 AB包依赖关系(不遗漏、不重复) 资源提取释放。繁重海量 手动写工作效率低下
4.可能会反复加载同一AB包中资源 导致加载过慢
AB框架包括自动标记脚本、创建与销毁打包资源、单一AB包加载
与测试脚本、专门读取manifest维护AB包依赖关系,实现递归依赖加载机制的脚本
自动创建AB包分类依据 按照场景分类
命名规则 场景名称/功能文件夹
在Editor类添加自动添加标记类
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: AutoSetLables.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-13
*Description: AB打包工具
* 定义需要打包资源的文件夹根目录
* 遍历每个"场景"文件夹
* 遍历本场景目录下所有目录或者文件
* 如果是目录,则继续递归访问,直到定位到文件
* 找到文件,则使用AssetImporter类 标记包名、后缀名
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
namespace ABFrameWork
{
public class AutoSetLables
{
/// <summary>
/// 设置AB包名
/// </summary>
[MenuItem("ABTools/SetABLable")]
public static void SetABLable()
{
string strNeedSetLableRoot = string.Empty;
//根目录下所有场景目录
DirectoryInfo[] dirSencesDIRArray;
//清空无用AB标记
AssetDatabase.RemoveUnusedAssetBundleNames();
strNeedSetLableRoot = PathTools.GetABResourcesPath();
//获取路径下所有文件夹
DirectoryInfo directoryInfo = new DirectoryInfo(strNeedSetLableRoot);
dirSencesDIRArray = directoryInfo.GetDirectories();
foreach (var item in dirSencesDIRArray)
{
string tmpSencesDIR = strNeedSetLableRoot + "/" + item.Name;
int tmpIndex = tmpSencesDIR.LastIndexOf("/");
string tmpScenesName = tmpSencesDIR.Substring(tmpIndex + 1);
JudgeDIRorFileByRecursive(item, tmpScenesName);
}
AssetDatabase.Refresh();
Debug.Log("AB设置标记完成");
}
/// <summary>
/// 递归判断是否为目录与文件,修改AB标记
/// </summary>
/// <param name="currentDIR">当前文件信息 (和目录信息可以相互转换)</param>
/// <param name="scenesName"></param>
static void JudgeDIRorFileByRecursive(FileSystemInfo fileSystemInfo, string scenesName)
{
if (!fileSystemInfo.Exists)
{
Debug.LogError("目录或文件名称" + fileSystemInfo + "不存在,请检查");
return;
}
DirectoryInfo directoryInfo = fileSystemInfo as DirectoryInfo;
FileSystemInfo[] fileSystemInfos = directoryInfo.GetFileSystemInfos();
foreach (var item in fileSystemInfos)
{
FileInfo fileInfo = item as FileInfo;
if (fileInfo != null)
{
//修改AB标签
SetFileABLable(fileInfo, scenesName);
}
else
{
JudgeDIRorFileByRecursive(item, scenesName);
}
}
}
static void SetFileABLable(FileInfo fileInfo, string scenesName)
{
//AB包名
string ABName = string.Empty;
string assetFilePath = string.Empty;
//检查后缀
if (fileInfo.Extension==".meta")
return;
ABName = GetABName(fileInfo, scenesName);
//截取到Asset之后的目录
int tmpIndex = fileInfo.FullName.IndexOf("Assets");
assetFilePath = fileInfo.FullName.Substring(tmpIndex);
//给资源文件设置AB名称及后缀
AssetImporter tmpImpObj = AssetImporter.GetAtPath(assetFilePath);
tmpImpObj.assetBundleName = ABName;
if (fileInfo.Extension==".unity")
{
//定义AB包扩展名
tmpImpObj.assetBundleVariant = "u3d";
}
else
{
tmpImpObj.assetBundleVariant = "ab";
}
}
/// <summary>
/// 返回合法AB包名称
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="scenesName"></param>
/// <returns></returns>
static string GetABName(FileInfo fileInfo,string scenesName)
{
string ABName = string.Empty;
//Win路径
string tmpWinPath = fileInfo.FullName;
//Unity路径
string tmpUnityPath = tmpWinPath.Replace("\\", "/");
//定位"场景名称"后面字符位置
int tmpScenceNamePos = tmpUnityPath.IndexOf(scenesName)+scenesName.Length;
//AB包中"类型名称"所在区域
string strABFileNameArea=tmpUnityPath.Substring(tmpScenceNamePos+1);
if (strABFileNameArea.Contains("/"))
{
string[] tempStrArray = strABFileNameArea.Split('/');
ABName = scenesName + "/" +tempStrArray[0];
}
else
{
//sences特殊名字
ABName = scenesName + "/" + scenesName;
}
return ABName;
}
}
}
把路径定义为常量类
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: PathTools.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-13
*Description: 路径工具类
* 包含路径常量
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ABFrameWork
{
public class PathTools
{
public const string AB_ResourcesPath = "AB_Res";
public static string GetABResourcesPath()
{
return Application.dataPath + "/" + AB_ResourcesPath;
}
}
}
然后添加本地加载和WebReq加载单个资源
Editor脚本
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: AutoSetLables.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-13
*Description: AB打包工具
* 定义需要打包资源的文件夹根目录
* 遍历每个"场景"文件夹
* 遍历本场景目录下所有目录或者文件
* 如果是目录,则继续递归访问,直到定位到文件
* 找到文件,则使用AssetImporter类 标记包名、后缀名
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
namespace ABFrameWork
{
public class DeleteAB
{
[MenuItem("ABTools/DeleteAllAB")]
public static void DeleteAllAB()
{
string strABNeedPathDir = string.Empty;
strABNeedPathDir = PathTools.GetABOutPath();
if (!string.IsNullOrEmpty(strABNeedPathDir))
{
//这里参数true表示可以删除非空目录
Directory.Delete(strABNeedPathDir,true);
File.Delete(strABNeedPathDir+".meta");
AssetDatabase.Refresh();
}
}
}
public class BuildAB
{
[MenuItem("ABTools/BuildAllAB")]
public static void BuildAllAB()
{
string strABOutPathDir = string.Empty;
strABOutPathDir = PathTools.GetABOutPath();
if (!Directory.Exists(strABOutPathDir))
{
Directory.CreateDirectory(strABOutPathDir);
}
BuildPipeline.BuildAssetBundles(strABOutPathDir, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);
AssetDatabase.Refresh();
}
}
public class AutoSetLables
{
/// <summary>
/// 设置AB包名
/// </summary>
[MenuItem("ABTools/SetABLable")]
public static void SetABLable()
{
string strNeedSetLableRoot = string.Empty;
//根目录下所有场景目录
DirectoryInfo[] dirSencesDIRArray;
//清空无用AB标记
AssetDatabase.RemoveUnusedAssetBundleNames();
strNeedSetLableRoot = PathTools.GetABResourcesPath();
//获取路径下所有文件夹
DirectoryInfo directoryInfo = new DirectoryInfo(strNeedSetLableRoot);
dirSencesDIRArray = directoryInfo.GetDirectories();
foreach (var item in dirSencesDIRArray)
{
string tmpSencesDIR = strNeedSetLableRoot + "/" + item.Name;
int tmpIndex = tmpSencesDIR.LastIndexOf("/");
string tmpScenesName = tmpSencesDIR.Substring(tmpIndex + 1);
JudgeDIRorFileByRecursive(item, tmpScenesName);
}
AssetDatabase.Refresh();
Debug.Log("AB设置标记完成");
}
/// <summary>
/// 递归判断是否为目录与文件,修改AB标记
/// </summary>
/// <param name="currentDIR">当前文件信息 (和目录信息可以相互转换)</param>
/// <param name="scenesName"></param>
static void JudgeDIRorFileByRecursive(FileSystemInfo fileSystemInfo, string scenesName)
{
if (!fileSystemInfo.Exists)
{
Debug.LogError("目录或文件名称" + fileSystemInfo + "不存在,请检查");
return;
}
DirectoryInfo directoryInfo = fileSystemInfo as DirectoryInfo;
FileSystemInfo[] fileSystemInfos = directoryInfo.GetFileSystemInfos();
foreach (var item in fileSystemInfos)
{
FileInfo fileInfo = item as FileInfo;
if (fileInfo != null)
{
//修改AB标签
SetFileABLable(fileInfo, scenesName);
}
else
{
JudgeDIRorFileByRecursive(item, scenesName);
}
}
}
static void SetFileABLable(FileInfo fileInfo, string scenesName)
{
//AB包名
string ABName = string.Empty;
string assetFilePath = string.Empty;
//检查后缀
if (fileInfo.Extension == ".meta")
return;
ABName = GetABName(fileInfo, scenesName);
//截取到Asset之后的目录
int tmpIndex = fileInfo.FullName.IndexOf("Assets");
assetFilePath = fileInfo.FullName.Substring(tmpIndex);
//给资源文件设置AB名称及后缀
AssetImporter tmpImpObj = AssetImporter.GetAtPath(assetFilePath);
tmpImpObj.assetBundleName = ABName;
if (fileInfo.Extension == ".unity")
{
//定义AB包扩展名
tmpImpObj.assetBundleVariant = "u3d";
}
else
{
tmpImpObj.assetBundleVariant = "ab";
}
}
/// <summary>
/// 返回合法AB包名称
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="scenesName"></param>
/// <returns></returns>
static string GetABName(FileInfo fileInfo, string scenesName)
{
string ABName = string.Empty;
//Win路径
string tmpWinPath = fileInfo.FullName;
//Unity路径
string tmpUnityPath = tmpWinPath.Replace("\\", "/");
//定位"场景名称"后面字符位置
int tmpScenceNamePos = tmpUnityPath.IndexOf(scenesName) + scenesName.Length;
//AB包中"类型名称"所在区域
string strABFileNameArea = tmpUnityPath.Substring(tmpScenceNamePos + 1);
if (strABFileNameArea.Contains("/"))
{
string[] tempStrArray = strABFileNameArea.Split('/');
ABName = scenesName + "/" + tempStrArray[0];
}
else
{
//sences特殊名字
ABName = scenesName + "/" + scenesName;
}
return ABName;
}
}
}
工具路径类
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: PathTools.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-13
*Description: 路径工具类
* 包含路径常量
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ABFrameWork
{
public class PathTools
{
public const string AB_ResourcesPath = "AB_Res";
/// <summary>
/// 获取AB标记路径
/// </summary>
/// <returns></returns>
public static string GetABResourcesPath()
{
return Application.dataPath + "/" + AB_ResourcesPath;
}
/// <summary>
/// 获取AB输出路径
/// 1.平台(PC/移动)路径
/// </summary>
public static string GetABOutPath()
{
return GetPlatfromPath()+"/"+ GetPlatfromName();
}
/// <summary>
/// 获取平台路径
/// </summary>
/// <returns></returns>
public static string GetPlatfromPath()
{
string strReturnPlatformPath = string.Empty;
switch (Application.platform)
{
case RuntimePlatform.WindowsPlayer:
case RuntimePlatform.WindowsEditor:
strReturnPlatformPath = Application.streamingAssetsPath;
break;
case RuntimePlatform.IPhonePlayer:
case RuntimePlatform.Android:
strReturnPlatformPath = Application.persistentDataPath;
break;
}
return strReturnPlatformPath;
}
/// <summary>
/// 获取平台名称
/// </summary>
/// <returns></returns>
public static string GetPlatfromName()
{
string strReturnPlatformName = string.Empty;
switch (Application.platform)
{
case RuntimePlatform.WindowsPlayer:
case RuntimePlatform.WindowsEditor:
strReturnPlatformName = "Windows";
break;
case RuntimePlatform.IPhonePlayer:
strReturnPlatformName = "IPhone";
break;
case RuntimePlatform.Android:
strReturnPlatformName = "Android";
break;
}
return strReturnPlatformName;
}
public static string GetWWWPath()
{
string strWWWPath = string.Empty;
switch (Application.platform)
{
case RuntimePlatform.WindowsPlayer:
case RuntimePlatform.WindowsEditor:
strWWWPath = "file://"+GetABOutPath();
break;
case RuntimePlatform.IPhonePlayer:
break;
case RuntimePlatform.Android:
strWWWPath = "jar:file://" + GetABOutPath();
break;
}
return strWWWPath;
}
}
}
加载资源类
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: AssetLoader.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-15
*Description:
* 管理与加载指定AB资源
* 加载具有"缓存功能"的资源 带选用参数
* 卸载、释放AB资源
* 查看当前AB的资源
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ABFrameWork
{
public class AssetLoader : System.IDisposable
{
AssetBundle currentAB;
/// <summary>
/// 缓存容器
/// </summary>
Hashtable ht=new Hashtable();
public AssetLoader(AssetBundle abObj)
{
if (abObj != null)
{
currentAB = abObj;
}
else
{
Debug.LogError($"{GetType()}/AssetLoader/abObj= null,please check!");
}
}
/// <summary>
/// 加载当前包中指定数据
/// </summary>
/// <param name="assetName"></param>
/// <param name="isCache"></param>
/// <returns></returns>
public Object LoadAsset(string assetName, bool isCache = false)
{
return LoadRes<Object>(assetName, isCache);
}
T LoadRes<T>(string assetName, bool isCache) where T : Object
{
//是否缓存集合已经存在
if (ht.Contains(assetName))
{
return ht[assetName] as T;
}
//正式加载
T tmpRes = currentAB.LoadAsset<T>(assetName);
if (tmpRes != null && isCache)
{
ht.Add(assetName, tmpRes);
}
else if (tmpRes == null)
{
Debug.LogError($"{GetType()}/LoadRes<T>/tmpRes == null,please check!");
}
return tmpRes;
}
/// <summary>
/// 卸载指定的资源
/// </summary>
public bool UnLoadAsset(Object asset)
{
if (asset != null)
{
Resources.UnloadAsset(asset);
return true;
}
Debug.LogError($"{GetType()}/UnLoadAsset/asset == null,please check!");
return false;
}
/// <summary>
/// 释放当前AB内存镜像资源
/// </summary>
public void Dispose()
{
currentAB.Unload(false);
}
/// <summary>
/// 释放当前AB内存镜像资源,且释放内存资源
/// </summary>
public void DisposeAll()
{
currentAB.Unload(true);
}
/// <summary>
/// 查询当前AB包包含的所有资源名称
/// </summary>
/// <returns></returns>
public string[] RetriveAllAssetName()
{
return currentAB.GetAllAssetNames();
}
}
}
网上加载资源类
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: SingleAssetLoader.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-15
*Description:
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
namespace ABFrameWork
{
public class SingleAssetLoader : System.IDisposable
{
/// <summary>
/// 引用类资源加载
/// </summary>
AssetLoader assetLoader;
DelLoadComplete loadCompleteHandle;
string ABName;
string ABDownLoadPath;
public SingleAssetLoader(string abName, DelLoadComplete loadComplete)
{
ABName = abName;
loadCompleteHandle = loadComplete;
ABDownLoadPath = PathTools.GetWWWPath() + "/" + abName;
}
public IEnumerator LoadAB()
{
using (UnityWebRequest req = UnityWebRequestAssetBundle.GetAssetBundle(ABDownLoadPath))
{
yield return req.SendWebRequest();
if (req.downloadProgress >= 1)
{
AssetBundle ab = DownloadHandlerAssetBundle.GetContent(req);
if (ab != null)
{
assetLoader = new AssetLoader(ab);
loadCompleteHandle?.Invoke(ABName);
}
else
{
Debug.LogError($"{GetType() }/ LoadAB() loadError ,please check! the{ABDownLoadPath} should be null");
}
}
}
}
/// <summary>
/// 加载AB包指定资源
/// </summary>
/// <param name="assetName"></param>
/// <param name="isCache"></param>
/// <returns></returns>
public Object LoadAsset(string assetName, bool isCache)
{
if (assetLoader != null)
{
return assetLoader.LoadAsset(assetName, isCache);
}
Debug.LogError($"{GetType() }/LoadAsset() assetLoader==null,please check!");
return null;
}
/// <summary>
/// 卸载AB包指定资源
/// </summary>
/// <param name="asset"></param>
public void UnLoadAsset(Object asset)
{
if (assetLoader != null)
{
assetLoader.UnLoadAsset(asset);
}
else
{
Debug.LogError($"{GetType() }/UnLoadAsset(Object asset) assetLoader==null,please check!");
}
}
/// <summary>
/// 释放资源
/// </summary>
public void Dispose()
{
if (assetLoader != null)
{
assetLoader.Dispose();
}
else
{
Debug.LogError($"{GetType() }/Dispose() assetLoader==null,please check!");
}
}
public void DisposeAll()
{
if (assetLoader != null)
{
assetLoader.DisposeAll();
}
else
{
Debug.LogError($"{GetType() }/DisposeAll() assetLoader==null,please check!");
}
}
/// <summary>
/// 查询AB包中所有资源
/// </summary>
/// <returns></returns>
public string[] RetrivalAllAssetName()
{
if (assetLoader != null)
{
return assetLoader.RetriveAllAssetName();
}
Debug.LogError($"{GetType() }/etrivalAllAssetName() assetLoader==null,please check!");
return null;
}
}
}
常量类
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: ABDefine.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-15
*Description: 工具类
* 本项目所有的常量
* 所有的委托定义
* 枚举定义
* 常量定义
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ABFrameWork
{
public delegate void DelLoadComplete(string abName);
/// <summary>
/// 框架常量
/// </summary>
public class ABDefine
{
}
}
测试类
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: TestAB.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-15
*Description: 测试类
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using ABFrameWork;
public class TestAB : MonoBehaviour
{
string abName = "sences_1/prefabs.ab";
string assetName = "Cube.prefab";
SingleAssetLoader loader;
// Start is called before the first frame update
void Start()
{
loader = new SingleAssetLoader(abName, (abName) =>
{
var a = loader.LoadAsset(assetName, false);
Instantiate(a);
});
StartCoroutine(loader.LoadAB());
}
// Update is called once per frame
void Update()
{
}
}
因为没有依赖资源 所以丢失了材质
所以要先加载材质贴图再加载预制体
需要有一个处理依赖关系的类
获取Manifest里面的依赖
维护包与包之间的关系
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: ABManifestLoader.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-16
*Description: 读取AB的依赖关系(Windows.mainfest)
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
namespace ABFrameWork
{
public class ABManifestLoader : Singleton<ABManifestLoader>,System.IDisposable
{
/// <summary>
/// 系统ab清单文件
/// </summary>
AssetBundleManifest manifest;
/// <summary>
/// ab清单文件路径
/// </summary>
string strManifestPath;
/// <summary>
/// 读取AB清单文件的AB
/// </summary>
AssetBundle ABReadManifest;
public bool isLoadFinish { get; private set; } = false;
public ABManifestLoader()
{
strManifestPath = PathTools.GetWWWPath() + "/" + PathTools.GetPlatfromName();
}
/// <summary>
/// 加载Mainfest清单文件
/// </summary>
/// <returns></returns>
public IEnumerator LoadMainfestFile()
{
using (UnityWebRequest req = UnityWebRequestAssetBundle.GetAssetBundle(strManifestPath))
{
yield return req.SendWebRequest();
if (req.downloadProgress >= 1)
{
AssetBundle ab = DownloadHandlerAssetBundle.GetContent(req);
if (ab != null)
{
ABReadManifest = ab;
manifest = ab.LoadAsset(ABDefine.ASSETBUNLDE_MANIFEST) as AssetBundleManifest;
isLoadFinish = true;
}
else
{
Debug.LogError($"{GetType()}/LoadMainfestFile() downLoad Error, please check{strManifestPath}");
}
}
}
}
/// <summary>
/// 获取ABManifest
/// </summary>
/// <returns></returns>
public AssetBundleManifest GetABManifest()
{
if (isLoadFinish)
{
if (manifest != null)
{
return manifest;
}
else
{
Debug.LogError($"{GetType()}/GetABManifest() manifest==null, please check");
}
}
else
{
Debug.LogError($"{GetType()}/GetABManifest() isLoadFinish==false, please check");
}
return null;
}
/// <summary>
/// 获取ABManifest系统类的依赖项
/// </summary>
/// <param name="abName"></param>
/// <returns></returns>
public string[] RetrivalDependce(string abName)
{
if (!string.IsNullOrEmpty(abName))
{
return manifest?.GetAllDependencies(abName);
}
return null;
}
/// <summary>
/// 释放本类资源
/// </summary>
public void Dispose()
{
ABReadManifest?.Unload(true);
}
}
}
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: ABRelation.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-16
*Description: AB关系类
* 储存制定AB包的所有依赖关系包
* 储存制定AB包所有的引用关系包
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ABFrameWork
{
public class ABRelation
{
string ABName;
List<string> allDependenceAB=new List<string>();
List<string> allReferenceAB=new List<string>();
public ABRelation(string ABName)
{
this.ABName = ABName;
}
/// <summary>
/// 增加依赖关系
/// </summary>
/// <param name="Name"></param>
public void AddDependence(string abName)
{
if (!allDependenceAB.Contains(abName))
{
allDependenceAB.Add(abName);
}
}
/// <summary>
/// 移除依赖关系
/// </summary>
/// <param name="abName"></param>
/// true 此AB包没有依赖项
/// false 此AB包还有其他的依赖项
/// <returns></returns>
public bool RemoveDependence(string abName)
{
if (allDependenceAB.Contains(abName))
{
allDependenceAB.Remove(abName);
}
if (allDependenceAB.Count>0)
return false;
else
return true;
}
public List<string>GetAllDependence()
{
return allDependenceAB;
}
/// <summary>
/// 增加引用关系
/// </summary>
/// <param name="Name"></param>
public void AddReference(string abName)
{
if (!allReferenceAB.Contains(abName))
{
allReferenceAB.Add(abName);
}
}
/// <summary>
/// 移除引用关系
/// </summary>
/// <param name="abName"></param>
/// true 此AB包没有依赖项
/// false 此AB包还有其他的依赖项
/// <returns></returns>
public bool RemoveReference(string abName)
{
if (allReferenceAB.Contains(abName))
{
allReferenceAB.Remove(abName);
}
if (allReferenceAB.Count > 0)
return false;
else
return true;
}
public List<string> GetAllReference()
{
return allReferenceAB;
}
}
}
一个场景多个包之间的关系
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: MultABMgr.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-16
*Description: 针对一个场景中关于多个AB综合管理
* 获取AB包之间的依赖关系和引用关系
* 管理AB包之间的自动连接(递归加载机制)
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ABFrameWork
{
public class MultABMgr
{
/// <summary>
/// 引用类 "单个AB包加载实现"
/// </summary>
SingleAssetLoader currentSingleABLoader;
/// <summary>
/// Ab包缓存集合(防止重复加载)
/// </summary>
Dictionary<string, SingleAssetLoader> singleABLoaderCache = new Dictionary<string, SingleAssetLoader>();
/// <summary>
/// 当前场景(调用使用)
/// </summary>
string currentScenceName;
/// <summary>
/// Ab包名
/// </summary>
string currentABName;
/// <summary>
/// AB包与对应依赖关系集合
/// </summary>
Dictionary<string, ABRelation> abRelation = new Dictionary<string, ABRelation>();
/// <summary>
/// 所有AB包加载完成回调
/// </summary>
DelLoadComplete LoadALLABPackageCompleteHandel;
public MultABMgr(string senceName, string abName, DelLoadComplete loadAllABPackCompleteHandle)
{
currentScenceName = senceName;
currentABName = abName;
LoadALLABPackageCompleteHandel = loadAllABPackCompleteHandle;
}
/// <summary>
/// 完成指定AB包调用
/// </summary>
/// <param name="name"></param>
void CompleteLoadAB(string abName)
{
if (abName.Equals(currentABName))
{
LoadALLABPackageCompleteHandel?.Invoke(abName);
}
}
public IEnumerator LoadAB(string abName)
{
ABRelation abRel;
//AB包关系建立
if (!abRelation.ContainsKey(abName))
{
abRel = new ABRelation(abName);
abRelation.Add(abName, abRel);
}
abRel = abRelation[abName];
//得到指定AB包所有依赖关系(查询Manifest清单文件)
string[] strDependeceArray = ABManifestLoader.Instance.RetrivalDependce(abName);
foreach (var item in strDependeceArray)
{
//添加依赖项
abRel.AddDependence(item);
//加载引用项(递归调用)
yield return LoadReference(item, abName);
}
//加载AB包
if (singleABLoaderCache.ContainsKey(abName))
{
yield return singleABLoaderCache[abName].LoadAB();
}
else
{
currentSingleABLoader = new SingleAssetLoader(abName, CompleteLoadAB);
singleABLoaderCache.Add(abName,currentSingleABLoader);
yield return currentSingleABLoader.LoadAB();
}
yield return null;
}
/// <summary>
/// 加载引用AB包
/// </summary>
/// <param name="abName">ab包名称</param>
/// <param name="refName">被引用AB包名称</param>
/// <returns></returns>
IEnumerator LoadReference(string abName, string refName)
{
ABRelation tmpABRelation;
if (abRelation.ContainsKey(abName))
{
tmpABRelation = abRelation[abName];
//添加AB包引用关系(被依赖)
tmpABRelation.AddReference(refName);
}
else
{
tmpABRelation = new ABRelation(abName);
tmpABRelation.AddReference(refName);
abRelation.Add(abName, tmpABRelation);
//开始加载依赖包(递归)
yield return LoadAB(abName);
}
yield return null;
}
/// <summary>
/// 加载AB包中资源
/// </summary>
/// <param name="abName"></param>
/// <param name="assetName"></param>
/// <param name="isCache"></param>
/// <returns></returns>
public Object LoadAsset(string abName, string assetName, bool isCache)
{
foreach (var item in singleABLoaderCache.Keys)
{
if (abName == item)
{
return singleABLoaderCache[item].LoadAsset(assetName, isCache);
}
}
Debug.LogError(GetType() + $"/LoadAsset()/do not find AB please check! abName{abName} assetName{assetName}");
return null;
}
public void DisposeAllAsset()
{
try
{
//逐一释放所有加载过的AB包中资源
foreach (var item in singleABLoaderCache.Values)
{
item.DisposeAll();
}
}
finally
{
singleABLoaderCache.Clear();
singleABLoaderCache = null;
//释放其他对象占用资源
abRelation.Clear();
abRelation = null;
currentABName = null;
currentScenceName = null;
LoadALLABPackageCompleteHandel = null;
//卸载没有用到的资源
Resources.UnloadUnusedAssets();
//强制垃圾收集
System.GC.Collect();
}
}
}
}
最后封装一层调用类
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: ABMgr.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-19
*Description: 多包管理按场景加载
* 读取清单文件 缓存脚本
* 以场景为单位 管理整个项目中所有AB包
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ABFrameWork
{
public class ABMgr : SingletonM<ABMgr>
{
//场景集合
Dictionary<string, MultABMgr> allScenes = new Dictionary<string, MultABMgr>();
//AB清单文件
AssetBundleManifest manifest;
protected override void Awake()
{
base.Awake();
StartCoroutine(ABManifestLoader.Instance.LoadMainfestFile());
}
public IEnumerator LoadAB(string sencesName, string abName, DelLoadComplete loadAllCompleteHandle)
{
//参数检查
if (string.IsNullOrEmpty(sencesName) || string.IsNullOrEmpty(abName))
{
Debug.LogError(GetType() + "/LoadAB()/sencesName or abName==null,please check!");
}
//等待Manifest清单文件加载完成
while (!ABManifestLoader.Instance.isLoadFinish)
{
yield return null;
}
manifest = ABManifestLoader.Instance.GetABManifest();
if (manifest == null)
{
Debug.LogError(GetType() + "/LoadAB()/manifest==null,please check!");
yield return null;
}
MultABMgr multABMgr;
//把当前场景加入到集合中
if (!allScenes.ContainsKey(sencesName))
{
multABMgr = new MultABMgr(sencesName, abName, loadAllCompleteHandle);
allScenes.Add(sencesName, multABMgr);
}
//调用下一层(多包管理员)
multABMgr = allScenes[sencesName];
if (multABMgr == null)
{
Debug.LogError(GetType() + "/LoadAB()/multABMgr==null,please check!");
}
//调用多包管理类的加载指定AB包
yield return multABMgr.LoadAB(abName);
}
/// <summary>
/// 加载AB包资源
/// </summary>
/// <param name="scenesName">场景名</param>
/// <param name="abName">包名</param>
/// <param name="assetName">资源名</param>
/// <param name="isCache">是否缓存</param>
/// <returns></returns>
public Object LoadAsset(string scenesName, string abName, string assetName, bool isCache)
{
if (allScenes.ContainsKey(scenesName))
{
MultABMgr multABMgr = allScenes[scenesName];
return multABMgr.LoadAsset(abName, assetName, isCache);
}
Debug.LogError(GetType() + $"/LoadAsset()do not find scenes,can't loadAsset, scenesName={scenesName}");
return null;
}
/// <summary>
/// 加载AB包资源
/// </summary>
/// <param name="scenesName">场景名</param>
/// <param name="abName">包名</param>
/// <param name="assetName">资源名</param>
/// <param name="isCache">是否缓存</param>
/// <returns></returns>
public void DisposeAllAssets(string scenesName)
{
if (allScenes.ContainsKey(scenesName))
{
MultABMgr multABMgr = allScenes[scenesName];
multABMgr.DisposeAllAsset();
}
else
{
Debug.LogError(GetType() + $"/DisposeAllAssets()do not find scenes,can't DisposeAllAssets, scenesName={scenesName}");
}
}
}
}
测试类 根据场景名 包名 预制体名字 加载
好像是有点麻烦
/**
*Copyright(C) 2019 by DefaultCompany
*All rights reserved.
*FileName: TestAB.cs
*Author: why
*Version: 1.0
*UnityVersion:2018.3.9f1
*Date: 2019-05-15
*Description: 测试类
*History:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using ABFrameWork;
public class TestAB : MonoBehaviour
{
//string abName = "sences_1/prefabs.ab";
//string assetName = "Cube.prefab";
//SingleAssetLoader loader;
string scenesName = "scence_1";
string abName = "sences_1/prefabs.ab";
string assetName = "Cube.prefab";
void Start()
{
//loader = new SingleAssetLoader(abName, (abName) =>
//{
// var a = loader.LoadAsset(assetName, false);
// Instantiate(a);
//});
//StartCoroutine(loader.LoadAB());
StartCoroutine(ABMgr.Instance.LoadAB(scenesName, abName, (abName) =>
{
Object tmpObj = ABMgr.Instance.LoadAsset(scenesName, abName, assetName, false);
if (tmpObj != null)
{
Instantiate(tmpObj);
}
}));
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.A))
{
ABMgr.Instance.DisposeAllAssets(scenesName);
}
}
}
释放后
里面用到一个单例类之后放出源码
https://github.com/1004019267/ABFrameWorkWithSence