Unity逻辑热更新

声明:
原博链接: http://blog.csdn.net/janeky/article/details/17652021
只是把自己研究实践的过程记录下来

先直接上代码:两个类,一个检测资源更新,有更新则下载到本地(ResUpdate),一个是逻辑热更新(LogicUpdate)
一、资源对比更新并下载。
资源是否更新了是通过比对服务器与客户端的 资源版本表: version.txt
该文本文档内容为:

Cube.assetbundle,78a6cd06388449d16aea5f6eae395abf
hotab.assetbundle,7ae97ca818017fcb7879c56d6a350676
Sphere.assetbundle,c58c93cffdc73669e10d3f449e1fa29c
version.txt,f864be607802fcc71b622d7ea5383c8f

工具地址:https://github.com/kenro/File_Md5_Generator


public
class ResUpdate : MonoBehaviour { public static readonly string VERSION_FILE="version.txt"; public static readonly string LOCAL_RES_URL="file://"+Application.dataPath+"/Res/"; public static readonly string SERVER_RES_URL = "file:///F:/HotUpdateTest/ab/"; public static readonly string LOCAL_RES_PATH=Application.dataPath+"/Res/"; private Dictionary<string,string> LocalResVersion; private Dictionary<string,string> ServerResVersion; private List<string> NeedDownFiles; private bool NeedUpdateLocalVersionFile = false; // Use this for initialization void Start () { LocalResVersion = new Dictionary<string, string> (); ServerResVersion = new Dictionary<string, string> (); NeedDownFiles = new List<string> (); //加载本地version配置 StartCoroutine(DownLoad(LOCAL_RES_URL + VERSION_FILE, delegate(WWW localVersion) { //保存本地的version ParseVersionFile(localVersion.text, LocalResVersion); StartCoroutine(DownLoad(SERVER_RES_URL + VERSION_FILE, delegate(WWW serverVersion) { //保存服务端version ParseVersionFile(serverVersion.text, ServerResVersion); //对比本地和服务端版本 CompareVersion(); //加载需要更新的资源 DownLoadRes(); })); })); } /// <summary> /// 保存version /// </summary> /// <param name="content"></param> /// <param name="dict"></param> private void ParseVersionFile(string content,Dictionary<string,string> dict) { if (content==null||content.Length==0) { return; } string[] items = content.Split(new char[] { ' ' }); foreach (string item in items) { string[] info = item.Split(new char[] { ',' }); if (info!=null&&info.Length==2) { dict.Add(info[0], info[1]); } } } /// <summary> /// 对比本地和服务端版本 /// </summary> private void CompareVersion() { foreach (var version in ServerResVersion) { string fileName = version.Key; string serverMd5 = version.Value; //新增的资源 if (!LocalResVersion.ContainsKey(fileName)) { NeedDownFiles.Add(fileName); } else { //需要替换的资源 string localMd5; //使用安全的获取方式,即:获取失败就直接替换资源 LocalResVersion.TryGetValue(fileName, out localMd5); if (!serverMd5.Equals(localMd5)) { NeedDownFiles.Add(fileName); } } //本次有更新,同时更新本地的version.tex NeedUpdateLocalVersionFile = NeedDownFiles.Count > 0; } } /// <summary> /// 加载需要更新的资源 /// </summary> private void DownLoadRes() { if (NeedDownFiles.Count==0) { UpdateLocalVersionFile(); return; } string file = NeedDownFiles[0]; NeedDownFiles.RemoveAt(0); StartCoroutine(DownLoad(SERVER_RES_URL + file, delegate(WWW w) { //将下载的资源替换本地的资源 ReplaceLocalRes(file, w.bytes); DownLoadRes(); })); } /// <summary> /// 更新本地的version配置 /// </summary> private void UpdateLocalVersionFile() { if (NeedUpdateLocalVersionFile) { StringBuilder versions = new StringBuilder(); foreach (var item in ServerResVersion) { versions.Append(item.Key).Append(",").Append(item.Value).Append(" "); } FileStream stream = new FileStream(LOCAL_RES_PATH + VERSION_FILE, FileMode.Create); byte[] data = Encoding.UTF8.GetBytes(versions.ToString()); stream.Write(data, 0, data.Length); //这里可能是多余的,Flush本来是在没有Close的时候也会 //将缓存中的数据写入到文件中 //但是这里紧接着下面就是Close stream.Flush(); stream.Close(); } // 测试用:显示加载的资源包 StartCoroutine(Show()); } /// <summary> /// 测试用:显示加载的资源包 /// </summary> /// <returns></returns> private IEnumerator Show() { WWW asset = new WWW(LOCAL_RES_URL + "Sphere.assetbundle"); yield return asset; AssetBundle bundle = asset.assetBundle; Instantiate(bundle.LoadAsset("Sphere")); ///这是U3D没有处理好的一个环节。在WWW加载资源完毕后,对资源进行instantiate后,对其资源进行unload,这时问题就发生 了,instantiate处理渲染需要一定的时间,虽然很短,但也是需要1,2帧的时间。此时进行unload会对资源渲染造成影响,以至于没有贴图或 者等等问题发生。 //解决办法: //自己写个时间等待代码,最好不要用WaitForSeconds,U3D的API,这个东西很撮,恶心死我了。。。 //我估计它这个类写的有问题,检查了好长时间,最后还是自己写了几行代码来替换这个类,解决了问题。 //等待个0.5秒到1秒之后再进行Unload。这样就不会出现instantiate渲染中就运行unload的情况了。 yield return null; bundle.Unload(false); } /// <summary> /// 替换本地资源 /// </summary> /// <param name="fileName"></param> /// <param name="data"></param> private void ReplaceLocalRes(string fileName,byte[] data) { string filePath = LOCAL_RES_PATH + fileName; FileStream stream = new FileStream(LOCAL_RES_PATH + fileName, FileMode.Create); stream.Write(data, 0, data.Length); stream.Flush(); stream.Close(); } /// <summary> /// 加载资源(服务器和本地) /// </summary> /// <param name="url"></param> /// <param name="finishFun"></param> /// <returns></returns> private IEnumerator DownLoad(string url,HandleFinishDownload finishFun) { using (WWW www = new WWW(url)) { yield return www; if (finishFun != null) { finishFun(www); } } } public delegate void HandleFinishDownload(WWW www); }


二、逻辑热更新
将逻辑代码生成Dll,将其打包成assetbundl前将其后缀改为.bytes,不然会报错
public class LogicUpdate : MonoBehaviour
{
    private static readonly string DLL_URL = "file:///D:/HostServer/Blood/AssetBundle/test.assetbundle";

    void Start()
    {
        StartCoroutine(loadDllScript());
    }

    private IEnumerator loadDllScript()
    {
        WWW www = new WWW(DLL_URL);
        yield return www;
        AssetBundle bundle = www.assetBundle;
        TextAsset asset = bundle.LoadAsset("test", typeof(TextAsset)) as TextAsset;

        System.Reflection.Assembly assembly = System.Reflection.Assembly.Load(asset.bytes);
        Type script1 = assembly.GetType("Script");
        GameObject obj = new GameObject();
        obj.AddComponent(script1);

        //Type script2 = assembly.GetType("Script2");
        //obj.AddComponent(script2);
    }  


 
原文地址:https://www.cnblogs.com/jasonlai/p/4757509.html