Unity3d热更新(三):更新资源流程

1.生成配置文件

在资源打包AssetBundle后,需要计算资源文件的MD5值,生成配置文件。下面给出一个例子:

[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. // 获取Res文件夹下所有文件的相对路径和MD5值  
  2. string[] files = Directory.GetFiles(resPath, "*", SearchOption.AllDirectories);  
  3. StringBuilder versions = new StringBuilder();  
  4. for (int i = 0, len = files.Length; i < len; i++)  
  5. {  
  6.     string filePath = files[i];  
  7.     string extension = filePath.Substring(files[i].LastIndexOf("."));  
  8.     if (extension == ".unity3d")  
  9.     {  
  10.         string relativePath = filePath.Replace(resPath, "").Replace("\\", "/");  
  11.         string md5 = MD5File(filePath);  
  12.         versions.Append(relativePath).Append(",").Append(md5).Append("\n");  
  13.     }  
  14. }  
  15. // 生成配置文件  
  16. FileStream stream = new FileStream(resPath + "version.txt", FileMode.Create);  
  17. byte[] data = Encoding.UTF8.GetBytes(versions.ToString());  
  18. stream.Write(data, 0, data.Length);  
  19. stream.Flush();  
  20. stream.Close();  
其中生成MD5值的方法如下:

[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public static string MD5File(string file)  
  2. {  
  3.     try  
  4.     {  
  5.         FileStream fs = new FileStream(file, FileMode.Open);  
  6.         System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();  
  7.         byte[] retVal = md5.ComputeHash(fs);  
  8.         fs.Close();  
  9.         StringBuilder sb = new StringBuilder();  
  10.         for (int i = 0; i < retVal.Length; i++)  
  11.         {  
  12.             sb.Append(retVal[i].ToString("x2"));  
  13.         }  
  14.         return sb.ToString();  
  15.     }  
  16.     catch (Exception ex)  
  17.     {  
  18.         throw new Exception("md5file() fail, error:" + ex.Message);  
  19.     }  
  20. }  

2.版本比较

先加载本地的version.txt,将结果缓存起来。下载服务器的version.txt,与本地的version进行比较,筛选出需要更新和新增的资源。

3.下载资源

依次下载更新的资源,如果本地已经有旧资源,则替换之,否则就新建保存起来。

4.更新本地版本配置文件version.txt

用服务器的version.txt替换掉本地的version.txt。这样做是为了确保下次启动的时候,不会再重复更新了。


关于上述的流程,下面有个小例子。这里没有用到web服务器,而是将本地的另外一个文件夹作为资源服务器目录。这里的目录只针对windows下的版本进行测试。如果要在手机平台上,需要记得更新相关的路径。

[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. using UnityEngine;    
  2. using System.Collections;    
  3. using System.Collections.Generic;    
  4. using System.Text;    
  5. using System.IO;    
  6.     
  7. public class ResUpdate : MonoBehaviour    
  8. {    
  9.     public static readonly string VERSION_FILE = "version.txt";    
  10.     public static readonly string LOCAL_RES_URL = "file://" + Application.dataPath + "/Res/";    
  11.     public static readonly string SERVER_RES_URL = "file:///C:/Res/";    
  12.     public static readonly string LOCAL_RES_PATH = Application.dataPath + "/Res/";    
  13.     
  14.     private Dictionary LocalResVersion;    
  15.     private Dictionary ServerResVersion;    
  16.     private List NeedDownFiles;    
  17.     private bool NeedUpdateLocalVersionFile = false;    
  18.     
  19.     void Start()    
  20.     {    
  21.         //初始化    
  22.         LocalResVersion = new Dictionary();    
  23.         ServerResVersion = new Dictionary();    
  24.         NeedDownFiles = new List();    
  25.     
  26.         //加载本地version配置    
  27.         StartCoroutine(DownLoad(LOCAL_RES_URL + VERSION_FILE, delegate(WWW localVersion)    
  28.         {    
  29.             //保存本地的version    
  30.             ParseVersionFile(localVersion.text, LocalResVersion);    
  31.             //加载服务端version配置    
  32.             StartCoroutine(this.DownLoad(SERVER_RES_URL + VERSION_FILE, delegate(WWW serverVersion)    
  33.             {    
  34.                 //保存服务端version    
  35.                 ParseVersionFile(serverVersion.text, ServerResVersion);    
  36.                 //计算出需要重新加载的资源    
  37.                 CompareVersion();    
  38.                 //加载需要更新的资源    
  39.                 DownLoadRes();    
  40.             }));    
  41.     
  42.         }));    
  43.     }    
  44.     
  45.     //依次加载需要更新的资源    
  46.     private void DownLoadRes()    
  47.     {    
  48.         if (NeedDownFiles.Count == 0)    
  49.         {    
  50.             UpdateLocalVersionFile();    
  51.             return;    
  52.         }    
  53.     
  54.         string file = NeedDownFiles[0];    
  55.         NeedDownFiles.RemoveAt(0);    
  56.     
  57.         StartCoroutine(this.DownLoad(SERVER_RES_URL + file, delegate(WWW w)    
  58.         {    
  59.             //将下载的资源替换本地就的资源    
  60.             ReplaceLocalRes(file, w.bytes);    
  61.             DownLoadRes();    
  62.         }));    
  63.     }    
  64.     
  65.     private void ReplaceLocalRes(string fileName, byte[] data)    
  66.     {    
  67.         string filePath = LOCAL_RES_PATH + fileName;    
  68.         FileStream stream = new FileStream(LOCAL_RES_PATH + fileName, FileMode.Create);    
  69.         stream.Write(data, 0, data.Length);    
  70.         stream.Flush();    
  71.         stream.Close();    
  72.     }    
  73.     
  74.     //显示资源    
  75.     private IEnumerator Show()    
  76.     {    
  77.         WWW asset = new WWW(LOCAL_RES_URL + "cube.assetbundle");    
  78.         yield return asset;    
  79.         AssetBundle bundle = asset.assetBundle;    
  80.         Instantiate(bundle.Load("Cube"));    
  81.         bundle.Unload(false);    
  82.     }    
  83.     
  84.     //更新本地的version配置    
  85.     private void UpdateLocalVersionFile()    
  86.     {    
  87.         if (NeedUpdateLocalVersionFile)    
  88.         {    
  89.             StringBuilder versions = new StringBuilder();    
  90.             foreach (var item in ServerResVersion)    
  91.             {    
  92.                 versions.Append(item.Key).Append(",").Append(item.Value).Append("\n");    
  93.             }    
  94.     
  95.             FileStream stream = new FileStream(LOCAL_RES_PATH + VERSION_FILE, FileMode.Create);    
  96.             byte[] data = Encoding.UTF8.GetBytes(versions.ToString());    
  97.             stream.Write(data, 0, data.Length);    
  98.             stream.Flush();    
  99.             stream.Close();    
  100.         }    
  101.         //加载显示对象    
  102.         StartCoroutine(Show());    
  103.     }    
  104.     
  105.     private void CompareVersion()    
  106.     {    
  107.         foreach (var version in ServerResVersion)    
  108.         {    
  109.             string fileName = version.Key;    
  110.             string serverMd5 = version.Value;    
  111.             //新增的资源    
  112.             if (!LocalResVersion.ContainsKey(fileName))    
  113.             {    
  114.                 NeedDownFiles.Add(fileName);    
  115.             }    
  116.             else    
  117.             {    
  118.                 //需要替换的资源    
  119.                 string localMd5;    
  120.                 LocalResVersion.TryGetValue(fileName, out localMd5);    
  121.                 if (!serverMd5.Equals(localMd5))    
  122.                 {    
  123.                     NeedDownFiles.Add(fileName);    
  124.                 }    
  125.             }    
  126.         }    
  127.         //本次有更新,同时更新本地的version.txt    
  128.         NeedUpdateLocalVersionFile = NeedDownFiles.Count > 0;    
  129.     }    
  130.     
  131.     private void ParseVersionFile(string content, Dictionary dict)    
  132.     {    
  133.         if (content == null || content.Length == 0)    
  134.         {    
  135.             return;    
  136.         }    
  137.         string[] items = content.Split(new char[] { '\n' });    
  138.         foreach (string item in items)    
  139.         {    
  140.             string[] info = item.Split(new char[] { ',' });    
  141.             if (info != null && info.Length == 2)    
  142.             {    
  143.                 dict.Add(info[0], info[1]);    
  144.             }    
  145.         }    
  146.     
  147.     }    
  148.     
  149.     private IEnumerator DownLoad(string url, HandleFinishDownload finishFun)    
  150.     {    
  151.         WWW www = new WWW(url);    
  152.         yield return www;    
  153.         if (finishFun != null)    
  154.         {    
  155.             finishFun(www);    
  156.         }    
  157.         www.Dispose();    
  158.     }    
  159.     
  160.     public delegate void HandleFinishDownload(WWW www);    
  161. }  
展开阅读全文

没有更多推荐了,返回首页