Lua热更关键代码笔记取自LuaFrameWork

1、

  void Awake() {

            CheckExtractResource(); //释放资源
   }
        /// <summary>
        /// 释放资源  -- 检测资源是否已经放到持久化路径里
        /// </summary>
        public void CheckExtractResource() { 
            bool isExists = Directory.Exists(Util.DataPath) &&      //  判断是否存在持久化路径 ,以及路径下有 Lua ,和 files.txt文件 
              Directory.Exists(Util.DataPath + "lua/") && File.Exists(Util.DataPath + "files.txt");   
            if (isExists || AppConst.DebugMode)  {   //  如果存在  
                StartCoroutine(OnUpdateResource());  // 检测更新 
                return;   //文件已经解压过了,自己可添加检查文件列表逻辑
            }
            StartCoroutine(OnExtractResource());   //启动释放协成  -- 先解包(把文件复制到持久化路径),再更新
        }

2、

        /// <summary>
        /// 释放资源 (从Unity中的StreamingAssets中,复制文件到对应平台的持久化路径中)
        /// </summary>
        /// <returns></returns>
        IEnumerator OnExtractResource() {
            string dataPath = Util.DataPath;  //数据目录     --    持久化数据目录  
            string resPath = Util.AppContentPath(); //游戏包资源目录    -- Unity 中StreamingAssets的数据在各平台的路径

            if (Directory.Exists(dataPath)) Directory.Delete(dataPath, true);
            Directory.CreateDirectory(dataPath);

            string infile = resPath + "files.txt";
            string outfile = dataPath + "files.txt";
            if (File.Exists(outfile)) File.Delete(outfile);

            string message = "正在解包文件:>files.txt";
            Debug.Log(infile);
            Debug.Log(outfile);
            // 先复制files.txt 文件 ,然后根据文件的内容复制其他文件
            if (Application.platform == RuntimePlatform.Android) {
                WWW www = new WWW(infile);
                yield return www;
                if (www.isDone) {
                    File.WriteAllBytes(outfile, www.bytes);
                }
                yield return 0;
            } else File.Copy(infile, outfile, true);
            yield return new WaitForEndOfFrame();

            //释放所有文件到数据目录(根据files.txt文件进行复制)
            string[] files = File.ReadAllLines(outfile); 
            foreach (var file in files) {
                string[] fs = file.Split('|');
                infile = resPath + fs[0];  //
                outfile = dataPath + fs[0];

                message = "正在解包文件:>" + fs[0];
                Debug.Log("正在解包文件:>" + infile);
                facade.SendMessageCommand(NotiConst.UPDATE_MESSAGE, message);

                string dir = Path.GetDirectoryName(outfile);
                if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);

                if (Application.platform == RuntimePlatform.Android) {
                    WWW www = new WWW(infile);
                    yield return www;

                    if (www.isDone) {
                        File.WriteAllBytes(outfile, www.bytes);  
                    }
                    yield return 0;
                } else {
                    if (File.Exists(outfile)) {
                        File.Delete(outfile);
                    }
                    File.Copy(infile, outfile, true); // 把infile 的文件复制到 outfile里 ,如果outfile里有,就覆盖
                }
                yield return new WaitForEndOfFrame();
            }
            message = "解包完成!!!";
            facade.SendMessageCommand(NotiConst.UPDATE_MESSAGE, message);
            yield return new WaitForSeconds(0.1f);

            message = string.Empty;
            //释放完成,开始启动更新资源
            StartCoroutine(OnUpdateResource());
        }

3、

 /// <summary>
        /// 启动更新下载,这里只是个思路演示,此处可启动线程下载更新
        /// </summary>
        IEnumerator OnUpdateResource() {
            if (!AppConst.UpdateMode) {
                OnResourceInited();
                yield break;
            }
            string dataPath = Util.DataPath;  //数据目录 -- 持久话数据目录 
            string url = AppConst.WebUrl;    // 更新的地址
            string message = string.Empty;
            string random = DateTime.Now.ToString("yyyymmddhhmmss");   // 时间格式 年月日时分秒
            string listUrl = url + "files.txt?v=" + random;   // 链接 +  参数 
            Debug.LogWarning("LoadUpdate---->>>" + listUrl);

            WWW www = new WWW(listUrl); yield return www;
            if (www.error != null) {
                OnUpdateFailed(string.Empty);
                yield break;
            }
            if (!Directory.Exists(dataPath)) {
                Directory.CreateDirectory(dataPath);
            }
            // 创建一个新文件,在其中写入指定的字节数组,然后关闭该文件。如果目标文件已存在,则覆盖该文件。 -- 持久化数据目录里写入 files.txt 文件 
            File.WriteAllBytes(dataPath + "files.txt", www.bytes);   //以字节数组(只读)的形式返回获取的web页面的内容。 
            string filesText = www.text;         // 以字符串的形式返回获取的web页面的内容(只读)。
            string[] files = filesText.Split('\n'); // 切割整个文件为一条条数据( AssetBundle|Md5)

            for (int i = 0; i < files.Length; i++) {
                if (string.IsNullOrEmpty(files[i])) continue; //判断是否为null或空字符串
                string[] keyValue = files[i].Split('|');
                string f = keyValue[0];             //AssetBundle
                string localfile = (dataPath + f).Trim();  //(持久化路径 + AssetBundle) 删掉起始和结尾的空格
                string path = Path.GetDirectoryName(localfile);  //返回指定路径字符串的目录信息。
                if (!Directory.Exists(path)) {
                    Directory.CreateDirectory(path);
                }
                string fileUrl = url + f + "?v=" + random;
                bool canUpdate = !File.Exists(localfile);
                if (!canUpdate) {  // 本地有当前 AssetBundle文件  -- 判断Md5
                    string remoteMd5 = keyValue[1].Trim();
                    string localMd5 = Util.md5file(localfile);  // 计算文件的md5值 
                    canUpdate = !remoteMd5.Equals(localMd5); // 服务端 md5 和本地的md5不相等
                    if (canUpdate) File.Delete(localfile);  // 删除本地的AssetBundle资源
                }
                if (canUpdate) {   //本地缺少文件
                    Debug.Log(fileUrl);
                    message = "downloading>>" + fileUrl;
                    facade.SendMessageCommand(NotiConst.UPDATE_MESSAGE, message);
                    /*
                    www = new WWW(fileUrl); yield return www;
                    if (www.error != null) {
                        OnUpdateFailed(path);   //
                        yield break;
                    }
                    File.WriteAllBytes(localfile, www.bytes);
                     */
                    //这里都是资源文件,用线程下载
                    BeginDownload(fileUrl, localfile);
                    while (!(IsDownOK(localfile))) { yield return new WaitForEndOfFrame(); }
                }
            }
            yield return new WaitForEndOfFrame();

            message = "更新完成!!";
            facade.SendMessageCommand(NotiConst.UPDATE_MESSAGE, message);

            OnResourceInited();
        }

4、计算 MD5
    (1)

    /// <summary>
        /// 计算文件的MD5值
        /// </summary>
        public static string md5file(string file) {
            try {
                FileStream fs = new FileStream(file, FileMode.Open);
                System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
                byte[] retVal = md5.ComputeHash(fs);
                fs.Close();

                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < retVal.Length; i++) {
                    sb.Append(retVal[i].ToString("x2"));   //  Append 等于 sb = sb+(字符串)   ToString("x2") 转化为小写的16进制,不足2位前补0
                }
                return sb.ToString();
            } catch (Exception ex) {
                throw new Exception("md5file() fail, error:" + ex.Message);
            }
        }

(2)


        /// <summary>
        /// 计算字符串的MD5值
        /// </summary>
        public static string md5(string source) {
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            byte[] data = System.Text.Encoding.UTF8.GetBytes(source); //在派生类中重写时,将指定字符串中的所有字符编码为一个字节序列
            byte[] md5Data = md5.ComputeHash(data, 0, data.Length);
            md5.Clear();

            string destString = "";
            for (int i = 0; i < md5Data.Length; i++) {
                destString += System.Convert.ToString(md5Data[i], 16).PadLeft(2, '0'); //   PadLeft,向左补满 2 位
            }
            destString = destString.PadLeft(32, '0');
            return destString;
        }

终结:1、首先判断当前平台的持久化路径中是否有需要下载的资源文件。

            2、如果没有,复制资源文件到当前平台的持久化路径中。先复制files.txt文件,再根据文件内的内容进行逐个复制。

            3、如果有,进行更新检测:

                                (1)WWW类加载files.txt文件,并写入持久化路径中(存在则覆盖)

                                (2)读取files.txt中的内容,分割为每条数据(包含资源文件名,MD5)(以下针对分割的每条数据来说)

                                (3)根据资源文件名,加本地文件路径,判断当前持久化路径内是否存在,如果不存在,直接下载

                                (4)如果存在,解析本地文件MD5,并判断是否于服务端资源本条文件数据的MD5是否相等,不相等删掉本地资源,下载服务端资源。

发布了26 篇原创文章 · 获赞 8 · 访问量 5799

猜你喜欢

转载自blog.csdn.net/LM514104/article/details/89372989