华佗AB打包预制加载

该代码实现了一个Unity中的AssetBundle管理类ABManager,用于加载和管理AssetBundle资源,包括从内存加载、按需加载、引用计数以及资源释放。同时,提供了一个ABTool编辑器扩展,用于构建AssetBundle包和生成版本信息。ABTool支持从特定目录获取dll和预制体,打包成AB包,并生成版本信息文件供热更新使用。

在这里插入图片描述
在这里插入图片描述

using Script;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;

public class ABData
{
    public AssetBundle ab;
    public int num;
}
public class ABManager :Singleton<ABManager>
{
    public string SPath = Application.streamingAssetsPath + "/";
    public Dictionary<string, byte[]> assetDatas = new Dictionary<string, byte[]>();
    public Dictionary<string, List<string>> reflist = new Dictionary<string, List<string>>();
    public  Dictionary<string, ABData> abDic = new Dictionary<string,ABData>();
    public byte[] GetAssetData(string dllName)
    {
        return assetDatas[dllName];
    }
    public AssetBundle LoadAB(string dllName)
    {
        return AssetBundle.LoadFromMemory(GetAssetData(dllName));
    }
    public T Load<T>(string refname,string abName,string assetName) where T : UnityEngine.Object
    {
        AssetBundle ab;
        if (abDic.ContainsKey(abName))
        {
            ab = abDic[abName].ab;
            abDic[abName].num++;
        }
        else
        {
            ab = AssetBundle.LoadFromFile(SPath + abName);
            ABData data = new ABData();
            data.ab = ab;
            data.num = 1;
            abDic.Add(abName, data);
        }
        if (ab != null)
        {
            if (!reflist.ContainsKey(refname))
            {
                reflist.Add(refname, new List<string>());
            }
            reflist[refname].Add(abName);
        }
        return ab.LoadAsset<T>(assetName);
    }
    public GameObject Load(string abName,string assetName)
    {
        AssetBundle ab;
        if (abDic.ContainsKey(abName))
        {
            ab = abDic[abName].ab;
            abDic[abName].num++;
        }
        else
        {
            ab = AssetBundle.LoadFromFile(SPath + abName);
            ABData data = new ABData();
            data.ab = ab;
            data.num = 1;
            abDic.Add(abName, data);
        }
        if (ab != null)
        {
            if (!reflist.ContainsKey(assetName))
            {
                reflist.Add(assetName, new List<string>());
            }
            reflist[assetName].Add(abName);
        }
        return ab.LoadAsset<GameObject>(assetName);
    }
    public Type LoadScript(string abName,string assetName)
    {
        Assembly ass = Assembly.Load(GetAssetData(abName));
        return ass.GetType(assetName);
    }
    public void Release(string refname)
    {
        if (reflist.ContainsKey(refname))
        {
            foreach (var abName in reflist[refname])
            {
                if (abDic.ContainsKey(abName))
                {
                    abDic[abName].num--;
                    if (abDic[abName].num <= 0)
                    {
                        ScheduleOnce.Ins.AddSchedule(9, (obj) =>
                        {
                            object[] arr = obj as object[];
                            ABData data = arr[0] as ABData;
                            if (data.num <= 0)
                            {
                                data.ab.Unload(true);
                                abDic.Remove(abName);
                                Debug.Log("释放成功");
                            }
                        }, abDic[abName]);
                    }
                }
            }
            reflist.Remove(refname);
        }
    }
}

using System.Collections.Generic;
using System.IO;
using System.Linq;
using HybridCLR.Editor;
using UnityEditor;
using UnityEngine;
using System.Text;
using System.Security.Cryptography;
using Unity.Plastic.Newtonsoft.Json;

public class ABTool : Editor
{
    static string dllpath = Application.dataPath + "/../" + HybridCLRSettings.Instance.hotUpdateDllCompileOutputRootDir;

    //[MenuItem("ABTool/生成AB包/Android")]
    //public static void CreatAB_Android()
    //{
    //    var target = BuildTarget.Android;
    //    CreatAB(target);
    //}

    [MenuItem("ABTool/生成AB包(Windows64)")]
    public static void CreateAB()
    {
        BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
        //找到对应目录
        DirectoryInfo direction = new DirectoryInfo(dllpath + "/" + target);
        //获取目录下所有文件
        FileInfo[] files = direction.GetFiles("*", SearchOption.AllDirectories);
        //把所有dll文件拷贝到S目录下
        foreach (var item in files)
        {
            if (item.Name.EndsWith(".dll"))
            {
                string dllPath = $"{dllpath + "/" + target}/{item.Name}";
                string dllBytesPath = $"{Application.streamingAssetsPath}/{item.Name}.bytes";
                File.Copy(dllPath, dllBytesPath, true);
                Debug.Log($"hotfix dll {dllPath}->{dllBytesPath}");
            }
        }
        //预制体
        List<AssetBundleBuild> abs = new List<AssetBundleBuild>();
        //找到预制体目录下所有目录
        AddABPath(abs, $"{Application.dataPath}/Prefabs/");
        AddABPath(abs, $"{Application.dataPath}/Resources/");
        //构造AB包放到S目录下
        BuildPipeline.BuildAssetBundles(Application.streamingAssetsPath, abs.ToArray(), BuildAssetBundleOptions.None, target);
        AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
    }
    public static void AddABPath(List<AssetBundleBuild> abs, string path)
    {
        DirectoryInfo directoryInfo = new DirectoryInfo(path);
        DirectoryInfo[] directions = directoryInfo.GetDirectories();
        //每个目录打一个AB包
        for (int i = 0; i < directions.Length; i++)
        {
            List<string> prefabAbssets = new List<string>();
            Debug.Log("打包文件夹:" + directions[i].Name);
            FileInfo[] fileinfos = directions[i].GetFiles("*", SearchOption.AllDirectories);
            Debug.Log("目录下文件个数:" + fileinfos.Length);
            foreach (var item in fileinfos)
            {
                if (item.Name.EndsWith(".meta"))
                {
                    continue;
                }
                Debug.Log("打包文件:" + item.Name);
                prefabAbssets.Add(item.FullName.Replace("\\", "/"));
                AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
            }

            AssetBundleBuild PrefabsAb = new AssetBundleBuild
            {
                assetBundleName = directions[i].Name,
                assetNames = prefabAbssets.Select(s => ToReleateAssetPath(s)).ToArray(),
            };
            abs.Add(PrefabsAb);
        }
    }
    public static string ToReleateAssetPath(string s)
    {
        string path = s.Substring(s.IndexOf("Assets/"));
        Debug.Log(path);
        return path;
    }
    [MenuItem("ABTool/生产version")]
    public static void MakeVersion()
    {
        string json = AssetDatabase.LoadAssetAtPath<TextAsset>("Assets/Resources/Config/Config.json").text;
        Config config = JsonConvert.DeserializeObject<Config>(json);
        List<VersionData> versionDatas = new List<VersionData>();
        //第一条数据是假数据,用来判断是否需要热更新
        VersionData version = new VersionData();
        //判断使用测试版还是正式版热更新地址

        version.abName = config.isBate ? config.hotPath_Bate : config.hotPath;
        version.len = config.upid;//更新号
        version.md5 = config.version;//版本号
        versionDatas.Add(version);
        //找到S目录下所有文件
        string[] files = Directory.GetFiles(Application.streamingAssetsPath, ".", SearchOption.AllDirectories);
        foreach (var item in files)
        {
            //获取后缀名
            string extensionName = Path.GetExtension(item);
            //排除.meta和manifest文件
            if (extensionName.Contains("meta") || extensionName.Contains("manifest")) continue;
            Debug.Log(item);
            string abName = item.Replace(Application.dataPath, "Assets");
            abName = abName.Replace("\\", "/");
            string assetBundleNamee = "";
            assetBundleNamee = abName.Replace("Assets/StreamingAssets/", string.Empty);
            VersionData versionData = new VersionData();
            versionData.abName = assetBundleNamee;
            versionData.len = File.ReadAllBytes(item).Length;
            versionData.md5 = FileMD5(item);
            versionDatas.Add(versionData);
        }
        string versionInfo = JsonConvert.SerializeObject(versionDatas);
        File.WriteAllText(Application.streamingAssetsPath + "/version.text", versionInfo, Encoding.UTF8);
        AssetDatabase.Refresh();
        Debug.Log("version.text创建完成");
    }
    static string FileMD5(string filepath)
    {
        FileStream fileStream = new FileStream(filepath, FileMode.Open);
        MD5 mD5 = new MD5CryptoServiceProvider();
        byte[] bytes = mD5.ComputeHash(fileStream);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.Length; i++)
        {
            sb.Append(bytes[i].ToString("x2"));
        }
        return sb.ToString();
    }
}

在Resources下创建一个json文件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Config : MonoBehaviour
{
    public bool isEditor;
    public bool isBate;
    public string version;
    public int upid;
    public string hotPath;
    public string hotPath_Bate;
    public string host;
    public int port;
    public string host_Bate;
    public int port_Bate;
}

在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值