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