/// <summary> /// 热更协程 /// </summary> IEnumerator coGo(context currContext) { using ( SafeRecall_0 safeRecall = new SafeRecall_0(() => m_CurrContext = null) ) { //装载内部版本文件包 { List <string> packs = new List <string>(); packs.Add("rom_version"); PacketLoader loader = new PacketLoader(); loader.Start(PackType.Res, packs, null); //等待资源装载完成 while (loader.Result == PacketLoader.ResultEnum.Loading) { yield return(null); } } //比对包外应用版本号 { AppVersionComparison(); NotifyProgress(currContext, 0.01f); yield return(null); } //获取远程资源包主版本 MainVersionContent remote_main_pack_version = null; { IEnumerator coit = coPackMainVersionComparison( currContext, (vf) => remote_main_pack_version = vf ); while (coit.MoveNext()) { yield return(null); } } if (currContext.m_State == STATE.stopd) { yield break; //已经终止 } NotifyProgress(currContext, 0.02f); yield return(null); string runtimePlatform = RuntimePlatformStr(); //主资源版本信息 string exmain_pack_path = FileSystem.persistentDataPath + "/pack_main_version.xml"; { MainVersionContent local_main_pack_version = MainVersionContent.FromFile(exmain_pack_path); //从外部文件夹获取资源主版本 if (local_main_pack_version == null) //从外部文件读取失败,则从资源包读取 { //string path = string.Format("{0}/pack_main_version", runtimePlatform); //TextAsset versionAsset = Resources.Load(path) as TextAsset; //string xmlstr = FileSystem.byte2string(versionAsset.bytes); string xmlstr = PacketManage.Single.GetPacket("rom_version").LoadString("pack_main_version"); local_main_pack_version = MainVersionContent.FromXmlDocument(xmlstr); //将版本信息写入外部文件夹 local_main_pack_version.OutFile(exmain_pack_path); } //检查应用标识和平台标识是否一致 bool IdentifierError; do { IdentifierError = false; if ( local_main_pack_version.Identifier != remote_main_pack_version.Identifier || local_main_pack_version.Platform != remote_main_pack_version.Platform ) { IdentifierError = true; currContext.m_State = STATE.netError; if (currContext.m_OnNetError != null) { currContext.m_OnNetError(ErrorNo.RemoteMainVersionFmtError, "远程版本文件标识符错误"); } while (true) { if (currContext.m_State == STATE.stopd)//用户选择停止工作 { yield break; } else if (currContext.m_State == STATE.doing)//用户选择重试 { break; } else { yield return(null); if (currContext.m_State == STATE.stopd) { yield break; } } } } } while (IdentifierError); //检查大版本更新 if (local_main_pack_version.AppVersion != remote_main_pack_version.AppVersion) { //应用软件升级 if (currContext.m_OnUpgradeApp != null) { currContext.m_OnUpgradeApp(); } yield break; } //比对主版本号 if (int.Parse(local_main_pack_version.PackVersion) >= int.Parse(remote_main_pack_version.PackVersion)) { NotifyProgress(currContext, 1f); if (currContext.m_OnComplate != null) { currContext.m_OnComplate(); } yield break; //本地资源主版本号>=远程资源主版本号 表示无需更新资源 } } NotifyProgress(currContext, 0.03f); yield return(null); Dictionary <string, int> remote_res_version = new Dictionary <string, int>(); //远程资源版本信息 Dictionary <string, int> remote_script_version = new Dictionary <string, int>(); //远程脚本版本信息 Dictionary <string, int> local_res_version = new Dictionary <string, int>(); //本地资源版本信息 Dictionary <string, int> local_script_version = new Dictionary <string, int>(); //本地远程脚本版本信息 //获取远程版本比对信息 string remote_Identifier = ""; string remote_Platform = ""; { XmlDocument remote_version_doc = null; do { string version_url = url + "/pack_version.zip";//版本文件url WWW www = new WWW(version_url); yield return(www); if (www.error == null) { //解压缩版本比对文件 byte[] xmlbytes = MonoEX.LZMA.Decompress(www.bytes, 0); string xmlstr = FileSystem.byte2string(xmlbytes); try { remote_version_doc = new XmlDocument(); remote_version_doc.LoadXml(xmlstr); XmlElement xmlNode = remote_version_doc.SelectSingleNode("xml") as XmlElement; remote_Identifier = xmlNode.GetAttribute("Identifier"); remote_Platform = xmlNode.GetAttribute("Platform"); { XmlElement resNode = remote_version_doc.SelectSingleNode("xml/pack_res") as XmlElement; foreach (XmlNode aNode in resNode.SelectNodes("a")) { XmlElement aElement = aNode as XmlElement; string n = aElement.GetAttribute("n"); int v = int.Parse(aElement.GetAttribute("v")); remote_res_version.Add(n, v); } } { XmlElement resNode = remote_version_doc.SelectSingleNode("xml/pack_script") as XmlElement; foreach (XmlNode aNode in resNode.SelectNodes("a")) { XmlElement aElement = aNode as XmlElement; string n = aElement.GetAttribute("n"); int v = int.Parse(aElement.GetAttribute("v")); remote_script_version.Add(n, v); } } } catch (Exception) { remote_version_doc = null; } if (remote_version_doc == null) { currContext.m_State = STATE.netError; if (currContext.m_OnNetError != null) { currContext.m_OnNetError(ErrorNo.RemoteVersionFmtError, "远程版本信息文件格式有误"); } while (true) { if (currContext.m_State == STATE.stopd)//用户选择停止工作 { yield break; } else if (currContext.m_State == STATE.doing)//用户选择重试 { break; } else { yield return(null); if (currContext.m_State == STATE.stopd) { yield break; } } } } } else { currContext.m_State = STATE.netError; if (currContext.m_OnNetError != null) { currContext.m_OnNetError(ErrorNo.GetRemoteVersionFailed, "获取" + version_url + "失败"); } while (true) { if (currContext.m_State == STATE.stopd)//用户选择停止工作 { yield break; } else if (currContext.m_State == STATE.doing)//用户选择重试 { break; } else { yield return(null); if (currContext.m_State == STATE.stopd) { yield break; } } } } } while (remote_version_doc == null); } NotifyProgress(currContext, 0.04f); yield return(null); //获取本地包内版本信息文件 { //string path = string.Format("{0}/pack_version", runtimePlatform); //TextAsset versionAsset = Resources.Load(path) as TextAsset; //string xmlstr = FileSystem.byte2string(versionAsset.bytes); var xmlstr = PacketManage.Single.GetPacket("rom_version").LoadString("pack_version"); XmlDocument local_version_doc = new XmlDocument(); local_version_doc.LoadXml(xmlstr); //检查应用标识和平台标识是否一致 bool IdentifierError; do { IdentifierError = false; XmlElement xmlNode = local_version_doc.SelectSingleNode("xml") as XmlElement; if ( remote_Identifier != xmlNode.GetAttribute("Identifier") || remote_Platform != xmlNode.GetAttribute("Platform") ) { IdentifierError = true; currContext.m_State = STATE.netError; if (currContext.m_OnNetError != null) { currContext.m_OnNetError(ErrorNo.RemoteVersionFmtError, "远程版本文件标识符错误"); } while (true) { if (currContext.m_State == STATE.stopd)//用户选择停止工作 { yield break; } else if (currContext.m_State == STATE.doing)//用户选择重试 { break; } else { yield return(null); if (currContext.m_State == STATE.stopd) { yield break; } } } } } while (IdentifierError); { XmlElement resNode = local_version_doc.SelectSingleNode("xml/pack_res") as XmlElement; foreach (XmlNode aNode in resNode.SelectNodes("a")) { XmlElement aElement = aNode as XmlElement; string n = aElement.GetAttribute("n"); int v = int.Parse(aElement.GetAttribute("v")); local_res_version.Add(n, v); } } { XmlElement resNode = local_version_doc.SelectSingleNode("xml/pack_script") as XmlElement; foreach (XmlNode aNode in resNode.SelectNodes("a")) { XmlElement aElement = aNode as XmlElement; string n = aElement.GetAttribute("n"); int v = int.Parse(aElement.GetAttribute("v")); local_script_version.Add(n, v); } } } NotifyProgress(currContext, 0.05f); yield return(null); List <string> NeedDownloadRes = BuildNeedDownload(remote_res_version, local_res_version, "pack_res"); List <string> NeedDownloadScript = BuildNeedDownload(remote_script_version, local_script_version, "pack_script"); NotifyProgress(currContext, 0.06f); yield return(null); float start_p = 0.06f; int pack_count = NeedDownloadRes.Count + NeedDownloadScript.Count; int currindex = 0; //更新资源 foreach (string name in NeedDownloadRes) { bool isok = false; int reUpdate = 0; do { string pack_url = string.Format("{0}/pack_res/{1}.zip", url, name); //UnityEngine.Debug.Log("热更资源" + pack_url + "路径" + name); WWW www = new WWW(pack_url); yield return(www); if (www.error == null) { //byte[] filebytes = MonoEX.LZMA.Decompress(www.bytes, 0); byte[] filebytes = www.bytes; string pack_file = FileSystem.MakeExternalPackPath("pack_res", name); string pack_file_version = FileSystem.MakeExternalPackPath("pack_res", name + ".xml"); //判定是否可以读取信息 读取信息失败则重新下载一次 if (reUpdate <= 1) { int fileleng = filebytes.Length - 20; byte[] tail = new byte[20]; Buffer.BlockCopy(filebytes, fileleng, tail, 0, 20); string tailstr = Encoding.Default.GetString(tail); string[] tailInfo = tailstr.Split('#'); //判断文件完整性 int filel = Int32.Parse(tailInfo[2]); string farversion = remote_res_version[name].ToString(); //判断当前版本信息与自身携带的信息 if (tailInfo.Length != 3 || tailInfo[0] != farversion || fileleng < filel) { if (reUpdate < 1) { //失败 重新下载一次 reUpdate++; //UnityEngine.Debug.Log("失败一次 重新下载 版本号对比:" + tailInfo[0] + "-----" + farversion); continue; } else { //失败过一次则直接解压 //UnityEngine.Debug.Log("失败第二次 直接解压 文件长度对比:" + fileleng + "-----" + filel); FileStream fren = File.OpenWrite(pack_file); fren.Write(filebytes, 0, filebytes.Length); fren.Close(); } } else { using (FileStream fren = new FileStream(pack_file, FileMode.Create)) { fren.Write(filebytes, 0, fileleng); fren.Close(); } //保存版本信息 //UnityEngine.Debug.Log("更新成功"); VersionContent version = new VersionContent(farversion); version.OutFile(pack_file_version); } } else { //UnityEngine.Debug.Log("更新成功 版本失败"); using (FileStream fren = File.OpenWrite(pack_file)) { fren.Write(filebytes, 0, filebytes.Length); fren.Close(); } } reUpdate = 0; isok = true; currindex++; NotifyProgress(currContext, start_p + (1f - start_p) * ((float)currindex / (float)pack_count)); } else { currContext.m_State = STATE.netError; if (currContext.m_OnNetError != null) { currContext.m_OnNetError(ErrorNo.GetRemotePackFailed, "获取" + pack_url + "失败"); } while (true) { if (currContext.m_State == STATE.stopd)//用户选择停止工作 { yield break; } else if (currContext.m_State == STATE.doing)//用户选择重试 { break; } else { yield return(null); if (currContext.m_State == STATE.stopd) { yield break; } } } } } while (!isok); } //更新脚本 foreach (string name in NeedDownloadScript) { bool isok = false; do { string pack_url = string.Format("{0}/pack_script/{1}.zip", url, name); WWW www = new WWW(pack_url); yield return(www); if (www.error == null) { byte[] filebytes = MonoEX.LZMA.Decompress(www.bytes, 0); string pack_file = FileSystem.MakeExternalPackPath("pack_script", name); using (FileStream fs = File.OpenWrite(pack_file)) { fs.Write(filebytes, 0, filebytes.Length); fs.Close(); } //保存版本信息 string pack_file_version = FileSystem.MakeExternalPackPath("pack_script", name + ".xml"); VersionContent version = new VersionContent(remote_script_version[name].ToString()); version.OutFile(pack_file_version); isok = true; currindex++; NotifyProgress(currContext, start_p + (1f - start_p) * ((float)currindex / (float)pack_count)); } else { currContext.m_State = STATE.netError; if (currContext.m_OnNetError != null) { currContext.m_OnNetError(ErrorNo.GetRemotePackFailed, "获取" + pack_url + "失败"); } while (true) { if (currContext.m_State == STATE.stopd)//用户选择停止工作 { yield break; } else if (currContext.m_State == STATE.doing)//用户选择重试 { break; } else { yield return(null); if (currContext.m_State == STATE.stopd) { yield break; } } } } } while (!isok); } remote_main_pack_version.OutFile(exmain_pack_path);//更新完成后改写主资源版本信息 DoComplate(currContext); } }
/// <summary> /// 包主版本号比对 /// </summary> /// <returns></returns> IEnumerator coPackMainVersionComparison(context currContext, Action <MainVersionContent> recall) { using (SafeRecall_1 <MainVersionContent> SafeRecall = new SafeRecall_1 <MainVersionContent>(recall)) { MainVersionContent remote_version = null; do { string version_url = url + "/pack_main_version.xml";//包主版本文件url WWW www = new WWW(version_url); while (!www.isDone && www.error == null) { yield return(null); } if (www.error == null) { string xmlstr = FileSystem.byte2string(www.bytes); try { remote_version = MainVersionContent.FromXmlDocument(xmlstr); } catch (Exception) { remote_version = null; } if (remote_version == null) { currContext.m_State = STATE.netError; if (currContext.m_OnNetError != null) { currContext.m_OnNetError(ErrorNo.RemoteMainVersionFmtError, "远程版本信息文件格式有误"); } while (true) { if (currContext.m_State == STATE.stopd)//用户选择停止工作 { yield break; } else if (currContext.m_State == STATE.doing)//用户选择重试 { break; } else { yield return(null); if (currContext.m_State == STATE.stopd) { yield break; } } } } } else { currContext.m_State = STATE.netError; if (currContext.m_OnNetError != null) { currContext.m_OnNetError(ErrorNo.GetRemoteMainVersionFailed, "获取" + version_url + "失败"); } while (true) { if (currContext.m_State == STATE.stopd)//用户选择停止工作 { yield break; } else if (currContext.m_State == STATE.doing)//用户选择重试 { break; } else { yield return(null); if (currContext.m_State == STATE.stopd) { yield break; } } } } } while (remote_version == null); SafeRecall.Value = remote_version; } }