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);
                }
            }
        }
    }
}

一的部分到此结束

 

posted @ 2023-07-24 14:09  江小明Moon  阅读(24)  评论(0编辑  收藏  举报