AsssetBundle打包(一)
先建立一个需要打包的配置文件(方便打包路径的修改)
using System.Collections; using System.Collections.Generic; using UnityEngine; [CreateAssetMenu(fileName = "ABConfig",menuName = "CreatABConfig", order = 0)] public class ABConfig : ScriptableObject { //单个文件所在文件夹路径,遍历所有Prefab,保证名字唯一性 public List<string> m_AllPrefabPath = new List<string>();//预制体目录 public List<FileDirABName> m_AllFileDirAB = new List<FileDirABName>();//资源文件目录 [System.Serializable] public struct FileDirABName { public string ABName; public string Path; } }
在项目中生成一个配置文件
手动输入配置
之后开始写打包工具需要写在Editor文件夹下,没有Editor文件夹要自己创建一个。写一个BundleEditor的类,它要对资源,和预制体,AB包文件,进行处理。还需要对文件进行存储,以及读取配置文件。
所以它至少需要5条属性
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using System.IO; public class BundleEditor { //打包路径 public static string m_assetBundlePath = Application.streamingAssetsPath; //配置文件路径 public static string ABCONFIGPATH = "Assets/Editor/Build/ABConfig.asset"; //所有路径目录key:name, value:path public static Dictionary<string, string> m_AllFileDir = new Dictionary<string, string>(); //所有AB文件 public static List<string> m_AllFileAB = new List<string>(); //预制体资源key:name, value:path public static Dictionary<string, List<string>> m_allABPrefabDir = new Dictionary<string, List<string>>(); }
预制体的Value用List来存储,用来存储依赖资源,依赖的资源都放在同一图集文件下 接下来建立我们的Build方法
[MenuItem("Tools/打包")] public static void Build() { //读取配置文件路径 ABConfig aBConfig = AssetDatabase.LoadAssetAtPath<ABConfig>(ABCONFIGPATH); //创建打包文件目录 if (!Directory.Exists(m_assetBundlePath)) Directory.CreateDirectory(m_assetBundlePath);
}
接下来对abConfig里的资源文件进行遍历对比防止配置重复
[MenuItem("Tools/打包")] public static void Build() { //读取配置文件路径 ABConfig aBConfig = AssetDatabase.LoadAssetAtPath<ABConfig>(ABCONFIGPATH); //创建打包文件目录 if (!Directory.Exists(m_assetBundlePath)) Directory.CreateDirectory(m_assetBundlePath); foreach (ABConfig.FileDirABName filDir in aBConfig.m_AllFileDirAB) { Debug.Log(filDir.ABName); Debug.Log(filDir.Path); if (m_AllFileDir.ContainsKey(filDir.ABName)) { Debug.LogError("配置重复"); } else { m_AllFileDir.Add(filDir.ABName, filDir.Path); m_AllFileAB.Add(filDir.Path); } } }
之后对预制体配置路径进行预制体读取以及依赖读取
tring[] allStr = AssetDatabase.FindAssets("t:Prefab", aBConfig.m_AllPrefabPath.ToArray());//读取配置路径下的所有Prefab for (int i = 0; i < allStr.Length; i++) { string path = AssetDatabase.GUIDToAssetPath(allStr[i]);//获得路径 EditorUtility.DisplayProgressBar("查找Prefab", "Prefab" + path, i * 1.0f / allStr.Length); if (!ContainAllFileAB(path)) { GameObject obj = AssetDatabase.LoadAssetAtPath<GameObject>(path); string[] allDepend = AssetDatabase.GetDependencies(path); List<string> allDependPath = new List<string>(); for (int j = 0; j < allDepend.Length; j++) { if (!ContainAllFileAB(allDepend[j]) && !allDepend[j].EndsWith(".cs")) { m_AllFileAB.Add(allDepend[j]); allDependPath.Add(allDepend[j]); } } if (m_allABPrefabDir.ContainsKey(obj.name)) { Debug.LogError("存在相同Prefab" + obj.name); } else { m_allABPrefabDir.Add(obj.name, allDependPath); } } }
/// <summary> /// 是否包含在已经有的AB包里 /// </summary> /// <param name="path"></param> /// <returns></returns> static bool ContainAllFileAB(string path) { for (int i = 0; i < m_AllFileAB.Count; i++) { if (path == m_AllFileAB[i] || path.Contains(m_AllFileAB[i])) return true; } return false; }
之后为得到的文件资源和预制体资源设置AsssetBundle名
foreach (string name in m_AllFileDir.Keys) { SetABName(name, m_AllFileDir[name]); } foreach (string name in m_allABPrefabDir.Keys) { SetABName(name, m_allABPrefabDir[name]); }
//设置AsssetBundle名
static void SetABName(string name, string path) { AssetImporter assetImporter = AssetImporter.GetAtPath(path); if (assetImporter == null) { Debug.LogError("文件不存在" + path); } else { assetImporter.assetBundleName = name; } } static void SetABName(string name, List<string> paths) { for (int i = 0; i < paths.Count; i++) { SetABName(name, paths[i]); } }
再执行打包方法
static void BuildAssetBundle() { string[] allBundles = AssetDatabase.GetAllAssetBundleNames(); //key全路径,value包名 Dictionary<string, string> resPathDic = new Dictionary<string, string>(); for (int i = 0; i < allBundles.Length; i++) { string[] allBundlePath = AssetDatabase.GetAssetPathsFromAssetBundle(allBundles[i]); for (int j = 0; j < allBundlePath.Length; j++) { if (allBundlePath[j].EndsWith(".cs")) continue; resPathDic.Add(allBundlePath[j], allBundles[i]); } } DeleteAB(); //生成ab配置表(后面写) //打包使用LZ4压缩格式,目标平台当前用户激活的平台,打场景得不压缩,场景压缩后会加载不出来 BuildPipeline.BuildAssetBundles(m_assetBundlePath, BuildAssetBundleOptions.ChunkBasedCompression , EditorUserBuildSettings.activeBuildTarget); }
/// <summary> /// 删掉冗余的AB包 /// </summary> static void DeleteAB() { string[] allBundlesName = AssetDatabase.GetAllAssetBundleNames(); DirectoryInfo direction = new DirectoryInfo(m_assetBundlePath); FileInfo[] files = direction.GetFiles("*", SearchOption.AllDirectories); for (int i = 0; i < files.Length; i++) { if (ConatinABName(files[i].Name, allBundlesName) || files[i].Name.EndsWith(".meta")) { continue; } else { Debug.Log("已发生变化AB包" + files[i].Name); if (File.Exists(files[i].FullName)) { File.Delete(files[i].FullName); } } } }
最后整理细节
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using System.IO; public class BundleEditor { public static string m_assetBundlePath = Application.streamingAssetsPath; public static string ABCONFIGPATH = "Assets/Editor/Build/ABConfig.asset"; //所有路径目录value:name,path public static Dictionary<string, string> m_AllFileDir = new Dictionary<string, string>(); public static List<string> m_AllFileAB = new List<string>(); //预制体资源目录value:name,path public static Dictionary<string, List<string>> m_allABPrefabDir = new Dictionary<string, List<string>>(); [MenuItem("Tools/打包")] public static void Build() { m_AllFileDir.Clear(); m_AllFileAB.Clear(); m_allABPrefabDir.Clear(); ClearABName(); //读取配置文件路径 ABConfig aBConfig = AssetDatabase.LoadAssetAtPath<ABConfig>(ABCONFIGPATH); if (!Directory.Exists(m_assetBundlePath)) Directory.CreateDirectory(m_assetBundlePath); foreach (ABConfig.FileDirABName filDir in aBConfig.m_AllFileDirAB) { Debug.Log(filDir.ABName); Debug.Log(filDir.Path); if (m_AllFileDir.ContainsKey(filDir.ABName)) { Debug.LogError("配置重复"); } else { m_AllFileDir.Add(filDir.ABName, filDir.Path); m_AllFileAB.Add(filDir.Path); } } string[] allStr = AssetDatabase.FindAssets("t:Prefab", aBConfig.m_AllPrefabPath.ToArray()); for (int i = 0; i < allStr.Length; i++) { string path = AssetDatabase.GUIDToAssetPath(allStr[i]); EditorUtility.DisplayProgressBar("查找Prefab", "Prefab" + path, i * 1.0f / allStr.Length); if (!ContainAllFileAB(path)) { GameObject obj = AssetDatabase.LoadAssetAtPath<GameObject>(path); string[] allDepend = AssetDatabase.GetDependencies(path); List<string> allDependPath = new List<string>(); for (int j = 0; j < allDepend.Length; j++) { if (!ContainAllFileAB(allDepend[j]) && !allDepend[j].EndsWith(".cs")) { m_AllFileAB.Add(allDepend[j]); allDependPath.Add(allDepend[j]); } } if (m_allABPrefabDir.ContainsKey(obj.name)) { Debug.LogError("存在相同Prefab" + obj.name); } else { m_allABPrefabDir.Add(obj.name, allDependPath); } } } foreach (string name in m_AllFileDir.Keys) { SetABName(name, m_AllFileDir[name]); } foreach (string name in m_allABPrefabDir.Keys) { SetABName(name, m_allABPrefabDir[name]); } BuildAssetBundle(); AssetDatabase.Refresh(); EditorUtility.ClearProgressBar(); } static void SetABName(string name, string path) { AssetImporter assetImporter = AssetImporter.GetAtPath(path); if (assetImporter == null) { Debug.LogError("文件不存在" + path); } else { assetImporter.assetBundleName = name; } } static void SetABName(string name, List<string> paths) { for (int i = 0; i < paths.Count; i++) { SetABName(name, paths[i]); } } static bool ConatinABName(string name, string[] strs) { for (int i = 0; i < strs.Length; i++) { if (name == strs[i]) return true; } return false; } /// <summary> /// 是否包含在已经有的AB包里 /// </summary> /// <param name="path"></param> /// <returns></returns> static bool ContainAllFileAB(string path) { for (int i = 0; i < m_AllFileAB.Count; i++) { if (path == m_AllFileAB[i] || path.Contains(m_AllFileAB[i])) return true; } return false; } static void BuildAssetBundle() { string[] allBundles = AssetDatabase.GetAllAssetBundleNames(); //key全路径,value包名 Dictionary<string, string> resPathDic = new Dictionary<string, string>(); for (int i = 0; i < allBundles.Length; i++) { string[] allBundlePath = AssetDatabase.GetAssetPathsFromAssetBundle(allBundles[i]); for (int j = 0; j < allBundlePath.Length; j++) { if (allBundlePath[j].EndsWith(".cs")) continue; resPathDic.Add(allBundlePath[j], allBundles[i]); } } DeleteAB(); //生成ab配置表(后面写) //打包 BuildPipeline.BuildAssetBundles(m_assetBundlePath, BuildAssetBundleOptions.ChunkBasedCompression , EditorUserBuildSettings.activeBuildTarget); } private static void ClearABName() { string[] oldABName = AssetDatabase.GetAllAssetBundleNames(); for (int i = 0; i < oldABName.Length; i++) { AssetDatabase.RemoveAssetBundleName(oldABName[i], true); EditorUtility.DisplayProgressBar("清除AB包名", oldABName[i].ToString(), i * 1.0f / oldABName.Length); } } /// <summary> /// 删掉冗余的AB包 /// </summary> static void DeleteAB() { string[] allBundlesName = AssetDatabase.GetAllAssetBundleNames(); DirectoryInfo direction = new DirectoryInfo(m_assetBundlePath); FileInfo[] files = direction.GetFiles("*", SearchOption.AllDirectories); for (int i = 0; i < files.Length; i++) { if (ConatinABName(files[i].Name, allBundlesName) || files[i].Name.EndsWith(".meta")) { continue; } else { Debug.Log("已发生变化AB包" + files[i].Name); if (File.Exists(files[i].FullName)) { File.Delete(files[i].FullName); } } } } }
一的部分到此结束