Unity AssetBundle分包

一、Unity AssetBundle分包流程图

在这里插入图片描述

二、源码

AssetBundleGroupGetter对象,负责分组管理

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

public class AssetBundleGroupGetter
{
    /// <summary>
    /// 所有资源的AssetInfo
    /// </summary>
    private static Dictionary<string, AssetInfo> assetInfoDict = new Dictionary<string, AssetInfo>();

    /// <summary>
    /// 分过组的AssetInfo  key=>头部文件  value=>所有仅被头部文件引用的子依赖列表
    /// </summary>
    private static Dictionary<AssetInfo, List<AssetInfo>> assetGroupInfoDict =
        new Dictionary<AssetInfo, List<AssetInfo>>();

    private static string progressTitle;
    private static float progress;

    

    public static List<List<string>> GetAllUncompressedGroup()
    {
        List<List<string>> list = new List<List<string>>();
        int index = 0;
        foreach(var ais in assetGroupInfoDict)
        {
            if(ais.Key.assetType != AssetType.Video) continue;
            index = list.Count;
            list.Add(new List<string>());
            list[index].Add(ais.Key.path);
            foreach(var ai in ais.Value)
            {
                list[index].Add(ai.path);
            }
        }
        return list;
    }
    public static List<List<string>> GetAllGroup()
    {
        List<List<string>> list = new List<List<string>>();
        int index = 0;
        foreach(var ais in assetGroupInfoDict)
        {
            if(ais.Key.assetType == AssetType.Video) continue;
            index = list.Count;
            list.Add(new List<string>());

            if(ais.Key.assetType != AssetType.SpriteAtlas)
                list[index].Add(ais.Key.path);
            foreach(var ai in ais.Value)
            {
                list[index].Add(ai.path);
            }
        }
        return list;
    }

    /// <summary>
    /// 打Bundle初始化
    /// </summary>
    public static void InitBuild(string assetPath)
    {
        assetInfoDict.Clear();
        assetGroupInfoDict.Clear();
        progressTitle = "分析依赖";
        InitAllAssetInfo(assetPath);
        progressTitle = "资源分组";
        AllAssetInfoToGroup();
        EditorUtility.ClearProgressBar();
    }


    private static void ShowProgress(string title, string info, float progress)
    {
        EditorUtility.DisplayProgressBar(title, info, progress);
    }


    /// <summary>
    /// 实例化所有的AssetInfo
    /// </summary>
    private static void InitAllAssetInfo(string assetPath)
    {
        string[] allFileArr = Directory.GetFiles(assetPath, "*", SearchOption.AllDirectories);
        int allFileCount = allFileArr == null ? 0 : allFileArr.Length;

        for (int i = 0; i < allFileCount; i++)
        {
            string filePath = allFileArr[i];
            progress = (float) i / allFileCount;
            ShowProgress(progressTitle, filePath, progress);
            if (filePath.EndsWith(".meta"))
            {
                continue;
            }

            filePath = filePath.Replace("\\", "/");
            CreateAssetInfo(filePath, null);
        }
    }

    /// <summary>
    /// 生成AssetInfo
    /// </summary>
    /// <param name="path">AssetInfo的路径</param>
    /// <param name="parent">父依赖</param>
    private static void CreateAssetInfo(string path, AssetInfo parent = null)
    {
        AssetInfo info = null;
        if (assetInfoDict.ContainsKey(path))
        {
            info = assetInfoDict[path];
        }
        else
        {
            info = new AssetInfo(path);
            assetInfoDict.Add(path, info);
        }

        if (parent != null)
        {
            parent.AddChild(info);
            //文件的父级Scene文件不记录依赖关系
            if (parent.assetType != AssetType.Scene)
            {
                info.AddParent(parent);
            }
        }

        List<string> depends = info.GetDepends();

        if (depends != null && depends.Count > 0)
        {
            foreach (var item in depends)
            {
                CreateAssetInfo(item, info);
            }
        }
    }

    /// <summary>
    /// 对所有AssetInfo进行分组
    /// </summary>
    private static void AllAssetInfoToGroup()
    {
        int assetCount = assetInfoDict == null ? 0 : assetInfoDict.Count;
        int id = 0;
        if (assetCount > 0)
        {
            foreach (var item in assetInfoDict)
            {
                AssetInfo info = item.Value;
                AssetInfoToGroup(info);
                progress = (float) id / assetCount;
                
                
                ShowProgress(progressTitle, info.path, progress);
                id++;
            }
        }
    }

    /// <summary>
    /// AssetInfo进行分组
    /// </summary>
    /// <param name="info"></param>
    private static void AssetInfoToGroup(AssetInfo info)
    {
        if (info.isGrouped)
        {
            return;
        }

        bool isTop = info.IsTop();
        if (isTop) //是顶级文件
        {
            AddAssetGroupInfoDict(info, null);
            return;
        }

        AssetInfo atlasInfo = info.GetBelongSpriteAtlas();
        if (atlasInfo != null) //此文件已经被打进了图集
        {
            AddAssetGroupInfoDict(atlasInfo, info);
            return;
        }

        List<AssetInfo> topParentList = info.FindTopParent();
        if (topParentList.Count == 1) //只有一个顶级父文件,那么这个文件和顶级父文件分成一个组
        {
            AddAssetGroupInfoDict(topParentList[0], info);
        }
        else
        {
            //所有当前文件的顶级父物体共同拥有的子依赖
            List<AssetInfo> crossChildInfo = FindMultipleParentCrossChilds(topParentList);
            for (int i = crossChildInfo.Count - 1; i >= 0; i--)
            {
                AssetInfo crossInfo = crossChildInfo[i];
                if (crossInfo.isGrouped)
                {
                    crossChildInfo.Remove(crossInfo);
                    continue;
                }

                List<AssetInfo> crossChildInfoTopParentList = crossInfo.FindTopParent();
                int count = crossChildInfoTopParentList == null ? 0 : crossChildInfoTopParentList.Count;
                if (count != topParentList.Count) //这个共同子文件中间也被其他顶级文件引用
                {
                    crossChildInfo.Remove(crossInfo);
                }
            }

            //把这些被多个顶级父文件共同依赖的文件分成一组
            if (crossChildInfo.Count > 0)
            {
                //随表找一个文件来占分组字典的坑位
                AssetInfo headInfo = crossChildInfo[0];
                crossChildInfo.RemoveAt(0);
                AddAssetListGroupInfoDict(headInfo, crossChildInfo);
            }
        }
    }

    /// <summary>
    /// 将文件加入分组字典
    /// </summary>
    /// <param name="headInfo">头部文件,即为Key</param>
    /// <param name="childInfo">依赖文件</param>
    private static void AddAssetGroupInfoDict(AssetInfo headInfo, AssetInfo childInfo)
    {
        if (headInfo == null)
        {
            return;
        }

        if (!assetGroupInfoDict.ContainsKey(headInfo))
        {
            assetGroupInfoDict.Add(headInfo, new List<AssetInfo>());
            headInfo.isGrouped = true;
        }

        if (childInfo != null && !childInfo.isGrouped)
        {
            assetGroupInfoDict[headInfo].Add(childInfo);
            childInfo.isGrouped = true;
        }
    }

    private static void AddAssetListGroupInfoDict(AssetInfo headInfo, List<AssetInfo> childInfoList)
    {
        if (childInfoList == null || childInfoList.Count == 0)
        {
            AddAssetGroupInfoDict(headInfo, null);
            return;
        }

        for (int i = 0; i < childInfoList.Count; i++)
        {
            AssetInfo childInfo = childInfoList[i];
            AddAssetGroupInfoDict(headInfo, childInfo);
        }
    }
    
    /// <summary>
    /// 获取多个父文件共同依赖的子文件
    /// </summary>
    /// <param name="parentList"></param>
    /// <returns></returns>
    private static List<AssetInfo> FindMultipleParentCrossChilds(List<AssetInfo> parents)
    {
        if (parents == null || parents.Count < 2)
        {
            return null;
        }

        List<AssetInfo> list = parents[0].childList;
        if (list == null || list.Count == 0)
        {
            return null;
        }

        for (int i = 1; i < parents.Count; i++)
        {
            List<AssetInfo> childs = parents[i].childList;
            if (childs == null || childs.Count == 0)
            {
                return null;
            }

            list = list.Intersect(childs).ToList();
            if (list == null || list.Count == 0)
            {
                return null;
            }
        }

        return list;
    }

    /// <summary>
    /// 获得多个子文件共同拥有的父文件
    /// </summary>
    /// <param name="childs"></param>
    /// <returns></returns>
    private static List<AssetInfo> FindMultipleChildCrossParents(List<AssetInfo> childs)
    {
        if (childs == null || childs.Count < 2)
        {
            return null;
        }

        List<AssetInfo> list = childs[0].parentList;
        if (list == null || list.Count == 0)
        {
            return null;
        }

        for (int i = 1; i < childs.Count; i++)
        {
            List<AssetInfo> parents = childs[i].parentList;
            if (parents == null || parents.Count == 0)
            {
                return null;
            }

            list = list.Intersect(parents).ToList();
            if (list == null || list.Count == 0)
            {
                return null;
            }
        }

        return list;
    }

}


AssetInfo对象 这是一个文件对象,每一个资源文件对应一个AssetInfo

using System.Collections.Generic;
using System.IO;
using UnityEditor;
using Object = UnityEngine.Object;

public enum AssetType{
    //图集
    SpriteAtlas,
    //图片(精灵、贴图)
    Image,
    //预制体
    Prefab,
    //音频
    Audio,
    //视频
    Video,
    //场景
    Scene,
    //其他
    Other,
}

public class AssetInfo
{
    /// <summary>
    /// 是否已经分组
    /// </summary>
    public bool isGrouped = false;
    
    //资源类型
    public AssetType assetType;
    /// <summary>
    /// 文件路径
    /// </summary>
    public string path;
    /// <summary>
    /// 所有的父依赖文件
    /// </summary>
    public List<AssetInfo> parentList;
    /// <summary>
    /// 所有的子依赖文件
    /// </summary>
    public List<AssetInfo> childList;
    
    public AssetInfo(string _path)
    {
        path = _path;
        SetAssetType();
    }

    /// <summary>
    /// 设置文件类型
    /// </summary>
    private void SetAssetType()
    {
        string suffix = Path.GetExtension(path);
        switch (suffix)
        {
            case ".prefab":
                assetType = AssetType.Prefab;
                break;
            case ".spriteatlas":
                assetType = AssetType.SpriteAtlas;
                break;
            case ".png":
            case ".jpg":
            case ".psd":
            case ".tiff":
            case ".tga":
            case ".gif":
                assetType = AssetType.Image;
                break;
            case ".mp3":
            case ".aif":
            case ".wav":
            case ".ogg":
                assetType = AssetType.Audio;
                break;
            case ".mp4":
            case ".mov":
            case ".mpg":
            case ".mpeg":
            case ".avi":
            case ".asf":
                assetType = AssetType.Video;
                break;
            case ".unity":
                assetType = AssetType.Scene;
                break;
            default:
                assetType = AssetType.Other;
                break;
        }
    }

    /// <summary>
    /// 添加父级文件
    /// </summary>
    /// <param name="info"></param>
    public void AddParent(AssetInfo info)
    {
        if (parentList==null)
        {
            parentList= new List<AssetInfo>();
        }
        if (!parentList.Contains(info))
        {
            parentList.Add(info);
        }
    }

    /// <summary>
    /// 添加子级文件
    /// </summary>
    /// <param name="info"></param>
    public void AddChild(AssetInfo info)
    {
        if (childList==null)
        {
            childList= new List<AssetInfo>();
        }
        if (!childList.Contains(info))
        {
            childList.Add(info);
        }
    }

    /// <summary>
    /// 得到最顶层的父级
    /// </summary>
    /// <returns></returns>
    public List<AssetInfo> FindTopParent()
    {
        List<AssetInfo> list = new List<AssetInfo>();
        if (IsTop())
        {
            return list;
        }
        for (int i = 0; i < parentList.Count; i++)
        {
            AssetInfo info = parentList[i];
            if (info.parentList==null||info.parentList.Count==0)
            {
                list.Add(info);
            }
        }
        return list;
    }

    /// <summary>
    /// 是不是顶级文件
    /// </summary>
    /// <returns></returns>
    public bool IsTop()
    {
        return parentList==null||parentList.Count==0;
    }

    /// <summary>
    /// 得到该文件所属的图集文件
    /// </summary>
    /// <returns></returns>
    public AssetInfo GetBelongSpriteAtlas()
    {
        AssetInfo atlasInfo = null;
        if (assetType!=AssetType.Image||IsTop())
        {
            return atlasInfo;
        }
        for (int i = 0; i < parentList.Count; i++)
        {
            AssetInfo parentInfo = parentList[i];
            if (parentInfo.assetType==AssetType.SpriteAtlas)
            {
                atlasInfo = parentInfo;
                break;
            }
        }
        return atlasInfo;
    }

    /// <summary>
    /// 得到最底层的子依赖
    /// </summary>
    /// <returns></returns>
    public List<AssetInfo> FindBottomChild()
    {
        List<AssetInfo> list = new List<AssetInfo>();
        if (childList==null||childList.Count==0)
        {
            return list;
        }
        for (int i = 0; i < parentList.Count; i++)
        {
            AssetInfo info = childList[i];
            if (info.childList==null||info.childList.Count==0)
            {
                list.Add(info);
            }
        }
        return list;
    }
    
    /// <summary>
    /// 获取目标物体所有的依赖
    /// </summary>
    /// <param name="objPath">目标物体路径(Assets/xx/xx.abc)</param>
    /// <returns></returns>
    public List<string> GetDepends()
    {
        List<string> list = null;
        string[] dependArr =AssetDatabase.GetDependencies(path,true);
        if (dependArr!=null&&dependArr.Length>0)
        {
            list=new List<string>();
            foreach (var dependPath in dependArr)
            {
                if (string.IsNullOrEmpty(Path.GetExtension(dependPath)))
                    continue;
                Object obj = AssetDatabase.LoadMainAssetAtPath(dependPath);
                if (obj is MonoScript || obj is LightingDataAsset)
                    continue;
                if (dependPath == path)
                    continue;
                if (dependPath.EndsWith(".cs"))
                    continue;
                if (!dependPath.StartsWith("Assets"))
                    continue;
                if (!list.Contains(dependPath))
                {
                    list.Add(dependPath);
                }
                
            }
        }
        return list;
    }
}




  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

司军礼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值