承接上一篇:http://blog.csdn.net/lyh916/article/details/51146693
上一篇基本实现了更新下载,很多时候,我们还需要将更新文件数,下载速度等信息显示在界面上,所以这篇就说下怎么做。
效果图:
Ps:上面的下载速度为Infinity(无穷大),具体原因不明,估计是我使用的是编辑器链接本地服务器,而且更新的文件很小,所以就快得飞起吧!
分析:
这里我把它分为两部分:
a.信息的获取:其实上面显示的信息,都可以通过GameManager.cs获取到。
b.信息的显示:在GameManager.cs中,我们可以发现,当获取到消息后,就会通过facade.SendMessageCommand把消息进行发送,然后被AppView.cs进行捕获处理。
因此目标就很明确了:修改GameManager和AppView。
1.首先,看下facade.SendMessageCommand,它可以发送各种的消息,消息的定义在NotiConst.cs。这里我们把消息的种类扩充一下。
using UnityEngine; using System.Collections; public class NotiConst { /// <summary> /// Controller层消息通知 /// </summary> public const string START_UP = "StartUp"; //启动框架 public const string DISPATCH_MESSAGE = "DispatchMessage"; //派发信息 /// <summary> /// View层消息通知 /// </summary> //解包要展示的相关参数 public const string EXTRACT_FILE_NAME = "EXTRACT_FILE_NAME"; //解包文件名 public const string EXTRACT_FINISH_ONE = "EXTRACT_FINISH_ONE"; //解包完一个文件 public const string EXTRACT_ALL_COUNT = "EXTRACT_ALL_COUNT"; //解包总文件数 //更新要展示的相关参数 public const string UPDATE_SPEED = "UPDATE_SPEED"; //下载速度 public const string UPDATE_FILE_NAME = "UPDATE_FILE_NAME"; //下载文件名 public const string UPDATE_FINISH_ONE = "UPDATE_FINISH_ONE"; //下载完一个文件 public const string UPDATE_ALL_COUNT = "UPDATE_ALL_COUNT"; //下载总文件数 //线程相关 public const string THREAD_EXTRACT = "THREAD_EXTRACT"; //线程解包 public const string THREAD_DOWNLOAD = "THREAD_DOWNLOAD"; //线程下载 }
2.然后就是准备好解包和更新的参数,并把这些参数发送出去。
修改GameManager.cs
using UnityEngine; using System; using System.Collections; using System.Collections.Generic; using LuaInterface; using System.Reflection; using System.IO; namespace LuaFramework { public class GameManager : Manager { protected static bool initialize = false; private List<string> downloadFiles = new List<string>(); /// <summary> /// 初始化游戏管理器 /// </summary> void Awake() { Init(); } /// <summary> /// 初始化 /// </summary> void Init() { if (AppConst.ExampleMode) { InitGui(); } DontDestroyOnLoad(gameObject); //防止销毁自己 CheckExtractResource(); //释放资源 Screen.sleepTimeout = SleepTimeout.NeverSleep; Application.targetFrameRate = AppConst.GameFrameRate; } /// <summary> /// 初始化GUI /// </summary> public void InitGui() { string name = "UI Root"; GameObject gui = GameObject.Find(name); if (gui != null) return; GameObject prefab = Util.LoadPrefab(name); gui = Instantiate(prefab) as GameObject; gui.name = name; } /// <summary> /// 释放资源 /// </summary> public void CheckExtractResource() { hadExtractResource = Directory.Exists(Util.DataPath) && Directory.Exists(Util.DataPath + "lua/") && File.Exists(Util.DataPath + "files.txt"); if (hadExtractResource || AppConst.DebugMode) { ResManager.initialize(OnResourceInited); //StartCoroutine(OnUpdateResource());//在第二次解包后就更新 return; //文件已经解压过了,自己可添加检查文件列表逻辑 } StartCoroutine(OnExtractResource()); //启动释放协成 } bool hadExtractResource; bool firstExtractResource = true; IEnumerator OnExtractResource() { string dataPath = Util.DataPath; //数据目录 string resPath = Util.AppContentPath(); //游戏包资源目录 string infile = resPath + "files.txt"; string outfile = dataPath + "files.txt"; string message = ""; if (firstExtractResource) { //创建Util.DataPath目录 if (Directory.Exists(dataPath)) Directory.Delete(dataPath, true); Directory.CreateDirectory(dataPath); if (File.Exists(outfile)) File.Delete(outfile); //解包files.txt message = "正在解包文件:>files.txt"; Debug.Log("正在解包文件:>files.txt"); //facade.SendMessageCommand(NotiConst.EXTRACT_FILE_NAME, message); 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(); } List<string> willExtractFileName = new List<string>(); //释放文件到数据目录,过滤要解包的文件 string[] files = File.ReadAllLines(outfile); foreach (var file in files) { string[] fs = file.Split('|'); infile = resPath + fs[0]; outfile = dataPath + fs[0]; //start是主界面的包,需要自行修改 bool a = fs[0].StartsWith("lua/") || fs[0].StartsWith("StreamingAssets") ||fs[0].StartsWith("start"); if (firstExtractResource && !a) continue; if (!firstExtractResource && a) continue; //message = "正在解包文件:>" + fs[0]; //Debug.Log("正在解包文件:>" + infile); //facade.SendMessageCommand(NotiConst.EXTRACT_FILE_NAME, fs[0]); string dir = Path.GetDirectoryName(outfile); if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); willExtractFileName.Add(fs[0]); } //第二次解包才显示信息 if (!firstExtractResource && (willExtractFileName.Count > 0)) facade.SendMessageCommand(NotiConst.EXTRACT_ALL_COUNT, willExtractFileName.Count); for (int i = 0; i < willExtractFileName.Count; i++) { Debug.Log("正在解包:" + willExtractFileName[i]); string from = resPath + willExtractFileName[i]; string to = dataPath + willExtractFileName[i]; if (Application.platform == RuntimePlatform.Android) { if (!firstExtractResource) facade.SendMessageCommand(NotiConst.EXTRACT_FILE_NAME, willExtractFileName[i]); WWW www = new WWW(from); yield return www; if (www.isDone) { File.WriteAllBytes(to, www.bytes); if (!firstExtractResource) facade.SendMessageCommand(NotiConst.EXTRACT_FINISH_ONE, 0); } yield return 0; } else { if (File.Exists(to)) { File.Delete(to); } if (!firstExtractResource) facade.SendMessageCommand(NotiConst.EXTRACT_FILE_NAME, willExtractFileName[i]); File.Copy(from, to, true); if (!firstExtractResource) facade.SendMessageCommand(NotiConst.EXTRACT_FINISH_ONE, 0); } yield return new WaitForEndOfFrame(); } ; if (firstExtractResource) { ResManager.initialize(OnResourceInited); } else { message = "解包完成!!!"; //facade.SendMessageCommand(NotiConst.UPDATE_MESSAGE, message); //释放完成,开始启动更新资源 StartCoroutine(OnUpdateResource()); } yield return new WaitForSeconds(0.1f); message = string.Empty; } /// <summary> /// 启动更新下载,这里只是个思路演示,此处可启动线程下载更新 /// </summary> IEnumerator OnUpdateResource() { downloadFiles.Clear(); if (!AppConst.UpdateMode) { //ResManager.initialize(OnResourceInited); yield break; } string dataPath = Util.DataPath; //数据目录 string url = AppConst.WebUrl; 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); } File.WriteAllBytes(dataPath + "files.txt", www.bytes); string filesText = www.text; string[] files = filesText.Split('\n'); List<string> willDownLoadUrl = new List<string>();//from List<string> willDownLoadFileName = new List<string>(); List<string> willDownLoadDestination = new List<string>();//to string message = string.Empty; for (int i = 0; i < files.Length; i++) { if (string.IsNullOrEmpty(files[i])) continue; string[] keyValue = files[i].Split('|'); string f = keyValue[0]; string localfile = (dataPath + f).Trim(); string path = Path.GetDirectoryName(localfile); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } string fileUrl = url + keyValue[0] + "?v=" + random; bool canUpdate = !File.Exists(localfile); if (!canUpdate) { string remoteMd5 = keyValue[1].Trim(); string localMd5 = Util.md5file(localfile); canUpdate = !remoteMd5.Equals(localMd5); if (canUpdate) File.Delete(localfile); } 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); * */ willDownLoadUrl.Add(fileUrl);//下载地址 willDownLoadFileName.Add(keyValue[0]); willDownLoadDestination.Add(localfile);//目标文件路径 } } if (willDownLoadUrl.Count > 0) facade.SendMessageCommand(NotiConst.UPDATE_ALL_COUNT, willDownLoadUrl.Count); for (int i = 0; i < willDownLoadUrl.Count; i++) { Debug.Log("要下载的文件:" + willDownLoadUrl[i]); //这里都是资源文件,用线程下载 facade.SendMessageCommand(NotiConst.UPDATE_FILE_NAME, willDownLoadFileName[i]); BeginDownload(willDownLoadUrl[i], willDownLoadDestination[i]); //while (!(IsDownOK(willDownLoadDestination[i]))) { yield return new WaitForEndOfFrame(); } } yield return new WaitForEndOfFrame(); message = "更新完成!!"; //facade.SendMessageCommand(NotiConst.UPDATE_MESSAGE, message); //ResManager.initialize(OnResourceInited); } /// <summary> /// 是否下载完成 /// </summary> bool IsDownOK(string file) { return downloadFiles.Contains(file); } /// <summary> /// 线程下载 /// </summary> void BeginDownload(string url, string file) { //线程下载 object[] param = new object[2] {url, file}; ThreadEvent ev = new ThreadEvent(); ev.Key = NotiConst.THREAD_DOWNLOAD; ev.evParams.AddRange(param); ThreadManager.AddEvent(ev, OnThreadCompleted); //线程下载 } /// <summary> /// 线程完成 /// </summary> /// <param name="data"></param> void OnThreadCompleted(NotiData data) { switch (data.evName) { case NotiConst.THREAD_EXTRACT: //解压一个完成 // break; case NotiConst.THREAD_DOWNLOAD: //下载一个完成 downloadFiles.Add(data.evParam.ToString()); break; } } void OnUpdateFailed(string file) { string message = "更新失败!>" + file; Debug.Log(message); //facade.SendMessageCommand(NotiConst.UPDATE_MESSAGE, message); } /// <summary> /// 资源初始化结束 /// </summary> public void OnResourceInited() { LuaManager.InitStart(); LuaManager.DoFile("Logic/Game"); //加载游戏 LuaManager.DoFile("Logic/Network"); //加载网络 NetManager.OnInit(); //初始化网络 Util.CallMethod("Game", "OnInitOK"); //初始化完成 initialize = true; //初始化完 //类对象池测试 var classObjPool = ObjPoolManager.CreatePool<TestObjectClass>(OnPoolGetElement, OnPoolPushElement); //方法1 //objPool.Release(new TestObjectClass("abcd", 100, 200f)); //var testObj1 = objPool.Get(); //方法2 ObjPoolManager.Release<TestObjectClass>(new TestObjectClass("abcd", 100, 200f)); var testObj1 = ObjPoolManager.Get<TestObjectClass>(); Debugger.Log("TestObjectClass--->>>" + testObj1.ToString()); //游戏对象池测试 var prefab = Resources.Load("TestGameObjectPrefab", typeof(GameObject)) as GameObject; var gameObjPool = ObjPoolManager.CreatePool("TestGameObject", 5, 10, prefab); var gameObj = Instantiate(prefab) as GameObject; gameObj.name = "TestGameObject_01"; gameObj.transform.localScale = Vector3.one; gameObj.transform.localPosition = Vector3.zero; ObjPoolManager.Release("TestGameObject", gameObj); var backObj = ObjPoolManager.Get("TestGameObject"); backObj.transform.SetParent(null); Debug.Log("TestGameObject--->>>" + backObj); if (hadExtractResource) { StartCoroutine(OnUpdateResource()); } else { firstExtractResource = false;//进行二次解包 hadExtractResource = true; StartCoroutine(OnExtractResource()); } } /// <summary> /// 当从池子里面获取时 /// </summary> /// <param name="obj"></param> void OnPoolGetElement(TestObjectClass obj) { Debug.Log("OnPoolGetElement--->>>" + obj); } /// <summary> /// 当放回池子里面时 /// </summary> /// <param name="obj"></param> void OnPoolPushElement(TestObjectClass obj) { Debug.Log("OnPoolPushElement--->>>" + obj); } /// <summary> /// 析构函数 /// </summary> void OnDestroy() { if (NetManager != null) { NetManager.Unload(); } if (LuaManager != null) { LuaManager.Close(); } Debug.Log("~GameManager was destroyed"); } } }
3.接着就是把信息显示出来了。
修改AppView.cs
using UnityEngine; using LuaFramework; using System.Collections.Generic; public class AppView : View { private string message; ///<summary> /// 监听的消息 ///</summary> List<string> MessageList { get { return new List<string>() { NotiConst.EXTRACT_FILE_NAME, NotiConst.EXTRACT_FINISH_ONE, NotiConst.EXTRACT_ALL_COUNT, NotiConst.UPDATE_SPEED, NotiConst.UPDATE_FILE_NAME, NotiConst.UPDATE_FINISH_ONE, NotiConst.UPDATE_ALL_COUNT, }; } } void Awake() { RemoveMessage(this, MessageList); RegisterMessage(this, MessageList); } /// <summary> /// 处理View消息 /// </summary> /// <param name="message"></param> public override void OnMessage(IMessage message) { string name = message.Name; object body = message.Body; this.message = message.Name; switch (name) { case NotiConst.EXTRACT_FILE_NAME: extractFileName = body.ToString(); break; case NotiConst.EXTRACT_FINISH_ONE: extractNowCount++; break; case NotiConst.EXTRACT_ALL_COUNT: extractAllCount = (int)body; break; case NotiConst.UPDATE_SPEED: updateSpeed = body.ToString(); break; case NotiConst.UPDATE_FILE_NAME: updateFileName = body.ToString(); break; case NotiConst.UPDATE_FINISH_ONE: updateNowCount++; break; case NotiConst.UPDATE_ALL_COUNT: updateAllCount = (int)body; break; } } string extractFileName; int extractNowCount = 0; int extractAllCount = 0; string updateFileName; int updateNowCount = 0; int updateAllCount = 0; string updateSpeed; void OnGUI() { if (string.IsNullOrEmpty(message)) return; if (message.StartsWith("EXTRACT_")) { GUILayout.Label("正在解包的文件:" + extractFileName); GUILayout.Label("当前解包数:" + extractNowCount); GUILayout.Label("总的解包数:" + extractAllCount); } else if (message.StartsWith("UPDATE_")) { GUILayout.Label("正在下载的文件:" + updateFileName); GUILayout.Label("当前下载数:" + updateNowCount); GUILayout.Label("总的下载数:" + updateAllCount); GUILayout.Label("下载速度:" + updateSpeed); } } }
4.最后,因为消息类型变了,所以还要修改ThreadManager.cs
using System.Collections; using System.Threading; using System.Collections.Generic; using System.IO; using System.Diagnostics; using System.Net; using System; using Debug = UnityEngine.Debug; public class ThreadEvent { public string Key; public List<object> evParams = new List<object>(); } public class NotiData { public string evName; public object evParam; public NotiData(string name, object param) { this.evName = name; this.evParam = param; } } namespace LuaFramework { /// <summary> /// 当前线程管理器,同时只能做一个任务 /// </summary> public class ThreadManager : Manager { private Thread thread; private Action<NotiData> func; private Stopwatch sw = new Stopwatch(); private string currDownFile = string.Empty; static readonly object m_lockObj = new object(); static Queue<ThreadEvent> events = new Queue<ThreadEvent>(); delegate void ThreadSyncEvent(NotiData data); private ThreadSyncEvent m_SyncEvent; void Awake() { m_SyncEvent = OnSyncEvent; thread = new Thread(OnUpdate); } // Use this for initialization void Start() { thread.Start(); } /// <summary> /// 添加到事件队列 /// </summary> public void AddEvent(ThreadEvent ev, Action<NotiData> func) { lock (m_lockObj) { this.func = func; events.Enqueue(ev); } } /// <summary> /// 通知事件 /// </summary> /// <param name="state"></param> private void OnSyncEvent(NotiData data) { if (this.func != null) func(data); //回调逻辑层 facade.SendMessageCommand(data.evName, data.evParam); //通知View层 } // Update is called once per frame void OnUpdate() { while (true) { lock (m_lockObj) { if (events.Count > 0) { ThreadEvent e = events.Dequeue(); try { switch (e.Key) { case NotiConst.THREAD_EXTRACT: { //解压文件 OnExtractFile(e.evParams); } break; case NotiConst.THREAD_DOWNLOAD: { //下载文件 OnDownloadFile(e.evParams); } break; } } catch (System.Exception ex) { UnityEngine.Debug.LogError(ex.Message); } } } Thread.Sleep(1); } } /// <summary> /// 下载文件 /// </summary> void OnDownloadFile(List<object> evParams) { string url = evParams[0].ToString(); currDownFile = evParams[1].ToString(); using (WebClient client = new WebClient()) { sw.Start(); client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged); client.DownloadFileAsync(new System.Uri(url), currDownFile); } } private void ProgressChanged(object sender, DownloadProgressChangedEventArgs e) { //UnityEngine.Debug.Log(e.ProgressPercentage); /* UnityEngine.Debug.Log(string.Format("{0} MB's / {1} MB's", (e.BytesReceived / 1024d / 1024d).ToString("0.00"), (e.TotalBytesToReceive / 1024d / 1024d).ToString("0.00"))); */ //float value = (float)e.ProgressPercentage / 100f; string value = string.Format("{0} kb/s", (e.BytesReceived / 1024d / sw.Elapsed.TotalSeconds).ToString("0.00")); NotiData data = new NotiData(NotiConst.UPDATE_SPEED, value); if (m_SyncEvent != null) m_SyncEvent(data); if (e.ProgressPercentage == 100 && e.BytesReceived == e.TotalBytesToReceive) { sw.Reset(); data = new NotiData(NotiConst.UPDATE_FINISH_ONE, 0); if (m_SyncEvent != null) m_SyncEvent(data); } } /// <summary> /// 调用方法 /// </summary> void OnExtractFile(List<object> evParams) { Debugger.LogWarning("Thread evParams: >>" + evParams.Count); ///------------------通知更新面板解压完成-------------------- //NotiData data = new NotiData(NotiConst.UPDATE_DOWNLOAD, null); //if (m_SyncEvent != null) m_SyncEvent(data); } /// <summary> /// 应用程序退出 /// </summary> void OnDestroy() { thread.Abort(); } } }
作者:lyh916 发表于2016/8/14 16:29:41 原文链接
阅读:44 评论:0 查看评论