Unity资源管理--AssetBundle学习

Unity资源目录

当用Unity创建一个工程的时候,目录如下:
在这里插入图片描述
Assets:存放Unity工程实际的资源目录。
Library:存放Unity处理完毕的资源,由unity自动转化生成。
Log:存放日志文件。
Packages:统一管理各种packages组件,使用PackageManager进行管理。
ProjectSettings:存放Unity的各种项目设定。

当进行项目迁移时,只需要将Assets、Packages以及ProjectSettings三个目录拷贝即可。

Unity提供了Resource加载和AssetBundle加载两种方式

引用这篇文章的内容 Unity资源管理(二)-Resources文件夹

强烈不建议使用Resources系统,原因如下:
使用Resources文件夹将会使细粒度的内存管理变得更难
对Resources文件夹的不恰当使用会导致应用程序构架和启动时间变长
随着Resources文件夹数量的增加,在这些文件夹中管理Asset将会变得越来越难
使用Resources系统会降低项目向不同平台提供定制内容的能立,并且导致项目无法进行增量内容更新

AssetBundle学习

AssetBundle 官方API文档

AssetBundles的压缩方式:LZMA、LZ4、不压缩

1. 加载AssetBundles

AssetBundle.LoadFromMemory(Async optional) // 不推荐,此API会消耗两倍于AB大小的内存
AssetBundle.LoadFromFile(Async optional) // 推荐使用
UnityWebRequest.GetAssetBundle // 在Unity 5.2及更早版本中使用 WWW.LoadFromCacheOrDownload

2. 从AssetBundles中加载Assets

LoadAsset(LoadAssetAsync) // 加载单个或者少量时使用
LoadAllAssets(LoadAllAssetsAsync) // 加载多数或者所有Assets时使用
LoadAssetWithSubAssets(LoadAssetWithSubAssetsAsync)

3. 构建AssetBundls管线

BuildPipeline.BuildAssetBundles

4. 卸载不使用的AssetBundls

AssetBundle.unload(true) // false会有引用丢失的风险

tips:开发一个良好的分离下载系统是至关重要的


自动打包至指定文件夹

  • 自动添加label
using UnityEngine;
using UnityEditor;
using System.IO;

namespace ABFW
{
    public class AutoSetLabels
    {
        [MenuItem("AssetBundleTools/Set AB Label")]
        public static void SetABLable()
        {
            // 清空标记
            AssetDatabase.RemoveUnusedAssetBundleNames();

            // AB根目录 调用文件ABPath.cs统一获取路径
            string strNeedSetlabelRoot = ABPath.GetABResourcesPath();
            // 通过根路径获取目录
            DirectoryInfo dirTempInfo = new DirectoryInfo(strNeedSetlabelRoot);
            DirectoryInfo[] dirSceneDirArray = dirTempInfo.GetDirectories();

            // 遍历所有路径
            foreach (DirectoryInfo currentDIR in dirSceneDirArray)
            {
                Debug.Log("输出目录所有" + currentDIR);
                string tmpScenesDIR = strNeedSetlabelRoot + "/" + currentDIR.Name;
                int tmpIndex = tmpScenesDIR.LastIndexOf("/");
                string tmpScenesName = tmpScenesDIR.Substring(tmpIndex + 1);

                JudgeDIRorFileByRecursive(currentDIR, tmpScenesName);

            }
            // 刷新列表
            AssetDatabase.Refresh();
            Debug.Log("-----------------AB初始化完成--------------------");
        }
        /// 
        /// 递归判断是否为目录/文件,修改AssetBundle
        /// 
        /// 目录信息
        /// 场景名称
        private static void JudgeDIRorFileByRecursive(FileSystemInfo fileSysInfo, string scenesName)
        {
            if (!fileSysInfo.Exists)
            {
                Debug.Log("文件或者目录名称:" + fileSysInfo + "不存在,请检查");
                return;
            }

            DirectoryInfo dirInfoObj = fileSysInfo as DirectoryInfo;
            FileSystemInfo[] fileSysArray = dirInfoObj.GetFileSystemInfos();
            // 遍历文件 设置标签
            foreach (FileSystemInfo fileInfo in fileSysArray)
            {
                FileInfo fileInfoObj = fileInfo as FileInfo;
                if (fileInfoObj != null)
                {
                    // 文件类型 设置lable
                    SetFilesABLabel(fileInfoObj, scenesName);
                }
                else
                {
                    // 目录文件 递归
                    JudgeDIRorFileByRecursive(fileInfo, scenesName);
                }
            }
        }
        /// 
        /// 设置AB标签
        /// 
        /// 文件信息
        /// 场景名称
        private static void SetFilesABLabel(FileInfo fileInfoObj, string scenesName)
        {
            if (fileInfoObj.Extension == ".meta") return;

            // AB名
            string strABName = GetABName(fileInfoObj, scenesName);

            // 获取文件的相对路径,从Assets/开始
            int tmpIndex = fileInfoObj.FullName.IndexOf("Assets");
            string strAssetFilepath = fileInfoObj.FullName.Substring(tmpIndex);

            AssetImporter tmpImporterObj = AssetImporter.GetAtPath(strAssetFilepath);
            // 设置AB名
            tmpImporterObj.assetBundleName = strABName;

            // 根据拓展名设置AB后缀
            if (fileInfoObj.Extension == ".unity")
            {
                tmpImporterObj.assetBundleVariant = "u3d";
            } else
            {
                tmpImporterObj.assetBundleVariant = "ab";
            }
        }
        /// 
        /// 获取AB包的名称
        /// 
        /// 
        /// 
        /// 
        private static string GetABName(FileInfo fileInfoObj, string scenesName)
        {
            string tmpWinPath = fileInfoObj.FullName;
            string tmpUnityPath = tmpWinPath.Replace("\\", "/");
            // 场景名称后面的字符数
            int tmpSceneNameposition = tmpUnityPath.IndexOf(scenesName) + scenesName.Length;
            // 拓展名区域
            string strABFileNameArea = tmpUnityPath.Substring(tmpSceneNameposition + 1);

            string strABName;
            if (strABFileNameArea.Contains("/"))
            {
                string[] tmpStrArray = strABFileNameArea.Split('/');
                strABName = scenesName + "/" + tmpStrArray[0];
            }
            else
            {
                strABName = scenesName + "/" + scenesName;
            }
            return strABName;
        }
    }
}
  • 根据label进行打包
using System.IO;
using UnityEditor;
using UnityEngine;

namespace ABFW
{
    public class BuildAssetsBundle
    {
        [MenuItem("AssetBundleTools/Build All AB")]
        public static void BuildAllAB()
        {
        	// 创建目录
            string strABOutPathDIR = ABPath.GetABOutPath();
            if (!Directory.Exists(strABOutPathDIR))
            {
                Directory.CreateDirectory(strABOutPathDIR);
            }
            // 调用内置API打包
            BuildPipeline.BuildAssetBundles(strABOutPathDIR, BuildAssetBundleOptions.None, BuildTarget.StandaloneOSX);
        }
    }

}
  • 删除所有的AB包
using System.IO;
using UnityEditor;
using UnityEngine;

namespace ABFW
{
    public class DeleteAssetsBundle : MonoBehaviour
    {
        [MenuItem("AssetBundleTools/Delete All AB")]
        public static void DeleteAllBundle()
        {
            string strNeedDeleteDIR = ABPath.GetABOutPath();
            if (!string.IsNullOrEmpty(strNeedDeleteDIR))
            {
                Directory.Delete(strNeedDeleteDIR, true);
                File.Delete(strNeedDeleteDIR + ".meta ");
                AssetDatabase.Refresh();
            } else
            {
                Debug.LogError("无可删除的AB文件");
            }
        }
    }
}

生成MD5校验文件

using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using ABFW;

namespace HotUpdateModel
{
    public class CreateVerifyFiles
    {
        [MenuItem("AssetBundleTools/Create Verify Files")]
        public static void CreateFileMethod()
        {
            string abOutPath = ABPath.GetABOutPath();
            string verifyOutPath = abOutPath + "/ProjectVerifyFile.txt";
            List<string> fileList = new List<string>();
            if (File.Exists(verifyOutPath))
            {
                File.Delete(verifyOutPath);
            }
            ListFiles(new DirectoryInfo(abOutPath), ref fileList);
            WriteVerifyFile(verifyOutPath, fileList);
        }

        private static void ListFiles(FileSystemInfo fileSystemInfo, ref List<string> fileList)
        {
            DirectoryInfo dirInfo = fileSystemInfo as DirectoryInfo;
            FileSystemInfo[] fileSysInfo = dirInfo.GetFileSystemInfos();
            foreach (FileSystemInfo item in fileSysInfo)
            {
                FileInfo fileInfo = item as FileInfo;
                if (fileInfo != null)
                {
                    // 文件类型
                    string strFileFullName = fileInfo.FullName.Replace("\\", "/");
                    string fileExt = Path.GetExtension(strFileFullName);
                    if (fileExt.EndsWith(".meta") || fileExt.EndsWith(".bak"))
                    {
                        continue;
                    }
                    fileList.Add(strFileFullName);
                }
                else
                {
                    // 目录类型,继续递归
                    ListFiles(item, ref fileList);
                }
            }
        }

        /// 
        /// 把文件名称+对应的MD5写入文件
        /// 
        /// 验证文件的路径
        /// 所有合法文件的相对路径集合
        private static void WriteVerifyFile(string verifyFileOutPath, List<string> fileLists)
        {
            Debug.Log("verifyFileOutPath" + verifyFileOutPath);
            using (FileStream fs = new FileStream(verifyFileOutPath, FileMode.CreateNew))
            {

                using (StreamWriter sw = new StreamWriter(fs))
                {
                    for (int i = 0; i < fileLists.Count; i++)
                    {
                        string strFile = fileLists[i];
                        string strFileMD5 = Helps.GetMD5Value(strFile);
                        string strTrueFileName = strFile.Replace(ABPath.GetABOutPath() + "/", string.Empty);
                        sw.WriteLine(strTrueFileName + "|" + strFileMD5);
                    }
                }
            }
            AssetDatabase.Refresh();
        }
    }
}

拷贝Lua脚本至指定文件夹

using UnityEngine;
using UnityEditor;
using System.IO;
using ABFW;

public class CopyLuaFileToStreamAssets
{
    private static string _LuaIRPath = Application.dataPath + "/" + ABPath.LUA_RESOURCE_PATH;

    private static string _CopyTargetIR = ABPath.GetABOutPath() + "/" + ABPath.LUA_DEPLOY_PATH;

    [MenuItem("AssetBundleTools/Copy LuaFile To StreamAssets")]
    public static void CopyLuaTo()
    {
        DirectoryInfo dirInfo = new DirectoryInfo(_LuaIRPath);
        FileInfo[] files = dirInfo.GetFiles();

        if (!Directory.Exists(_CopyTargetIR))
        {
            Directory.CreateDirectory(_CopyTargetIR);
        }

        // 逐个拷贝
        foreach (FileInfo infoObj in files)
        {
            File.Copy(infoObj.FullName, _CopyTargetIR + "/" + infoObj.Name, true);
        }
        Debug.Log("---------拷贝完成,Lua文件已拷贝至发布区--------");
        AssetDatabase.Refresh();
    }
}

贴一个工具 游戏/VR应用性能诊断与优化 UWA框架

你可能感兴趣的:(unity,unity)