基于FTP下载资源的废弃的热更新方案

基于FTP下载资源的废弃的热更新方案
由于查资料据说FTP在手机上会被拦截现在的手游全部使用HTTP下载资源基于FTP下载资源的热更新方案已废弃。代码存在这里。FtpWebRequest导致Unity编辑器被阻塞下载完成后才继续打印日志没有立即打印全部下载完后一下全打印。甚至包括开始FTP下载前的打印。事后看日期是之前打印的。整个过程中编辑器不可操作。然后我在开始热更新前加断点。结果是已经到断点了控制台没有打印还在进入播放模式。疑似Assembly-CSharp先开始执行然后编辑器跟上。我怀疑是Assembly-CSharp执行完当前函数编辑器打印才出现。或者是执行完当前帧打印才出现。FtpWebRequest同步全阻塞版能下载资源但全程无打印无法操作编辑器。void HotUpdate2() { string ABChecklistPath_local Path.Combine(Application.persistentDataPath, RootSO.Single.ABChecklist_local); string ABChecklistPath_remote Path.Combine(Application.persistentDataPath, RootSO.Single.ABChecklist); logAction?.Invoke(检查本地资源清单文件…); if (!File.Exists(ABChecklistPath_local)) {//第一次打开 logAction?.Invoke(本地资源清单文件不存在下载); bool downloadABListOK DownloadABChecklist(logAction); if (downloadABListOK) { logAction?.Invoke(下载成功); string json File.ReadAllText(ABChecklistPath_remote); aBCheckListRemote JsonConvert.DeserializeObjectABCheckList(json); if (aBCheckListRemote null) { logAction?.Invoke(AB清单文件反序列化失败); onUpdateOver?.Invoke(false); return; } else { bool downloadABOK DownloadAll(); if (downloadABOK) { File.Move(ABChecklistPath_remote, ABChecklistPath_local); } onUpdateOver?.Invoke(downloadABOK); } } } else { string json File.ReadAllText(ABChecklistPath_local); aBCheckListLocal JsonConvert.DeserializeObjectABCheckList(json); if (aBCheckListLocal null) { logAction?.Invoke(本地资源清单文件损坏); } bool downloadABListOK DownloadABChecklist(logAction); if (downloadABListOK) { logAction?.Invoke(下载成功。读取并解析…); string json2 File.ReadAllText(ABChecklistPath_remote); aBCheckListRemote JsonConvert.DeserializeObjectABCheckList(json2); if (aBCheckListRemote ! null) {//对比资源 bool compareOK AddUpdateRemove(); if (!compareOK) { onUpdateOver?.Invoke(false); return; } } else { logAction?.Invoke(服务器资源清单文件损坏); onUpdateOver?.Invoke(false); } } else { logAction?.Invoke(下载资源清单失败); onUpdateOver?.Invoke(false); } } } bool DownloadAll() { ListABInfo abToUpdate new(); foreach (var item in aBCheckListRemote.ABInfos.Values) { abToUpdate.Add(item); } int numabToUpdate.Count; int i 0; foreach (var item in abToUpdate) { string localName item.name; if (MyFTPManager.Single.DownLoadFile(localName, RootSO.Single.ResServerUrl, Application.persistentDataPath, RootSO.Single.userName, RootSO.Single.password, null)) { //File.Move(localName, item.name); i; showAction?.Invoke($下载资源包{i}/{num}); logAction?.Invoke($更新{item.name}完成); } else { logAction?.Invoke($下载资源包{item.name}失败\n); return false; } } return true; }FTP同步协程等帧版然后改成协程每下载一个包等一帧依然编辑器大部分时间被阻塞。IEnumerator HotUpdate2IE() { string ABChecklistPath_local Path.Combine(Application.persistentDataPath, RootSO.Single.ABChecklist_local); string ABChecklistPath_remote Path.Combine(Application.persistentDataPath, RootSO.Single.ABChecklist); logAction?.Invoke(检查本地资源清单文件…); yield return null; if (!File.Exists(ABChecklistPath_local)) {//第一次打开 logAction?.Invoke(本地资源清单文件不存在下载); bool downloadABListOK DownloadABChecklist(logAction); if (downloadABListOK) { logAction?.Invoke(下载成功); string json File.ReadAllText(ABChecklistPath_remote); aBCheckListRemote JsonConvert.DeserializeObjectABCheckList(json); if (aBCheckListRemote null) { logAction?.Invoke(AB清单文件反序列化失败); onUpdateOver?.Invoke(false); yield break; } else { AsyncReturnboolresultnew AsyncReturnbool(); yield return DownloadAllIE(result); if (result.data) { File.Move(ABChecklistPath_remote, ABChecklistPath_local); } onUpdateOver?.Invoke(result.data); } } } else { string json File.ReadAllText(ABChecklistPath_local); aBCheckListLocal JsonConvert.DeserializeObjectABCheckList(json); if (aBCheckListLocal null) { logAction?.Invoke(本地资源清单文件损坏); } bool downloadABListOK DownloadABChecklist(logAction); if (downloadABListOK) { logAction?.Invoke(下载成功。读取并解析…); string json2 File.ReadAllText(ABChecklistPath_remote); aBCheckListRemote JsonConvert.DeserializeObjectABCheckList(json2); if (aBCheckListRemote ! null) {//对比资源 bool compareOK AddUpdateRemove(); if (!compareOK) { onUpdateOver?.Invoke(false); yield break; } } else { logAction?.Invoke(服务器资源清单文件损坏); onUpdateOver?.Invoke(false); } } else { logAction?.Invoke(下载资源清单失败); onUpdateOver?.Invoke(false); } } } IEnumerator DownloadAllIE(AsyncReturnboolresult) { ListABInfo abToUpdate new(); foreach (var item in aBCheckListRemote.ABInfos.Values) { abToUpdate.Add(item); } int num abToUpdate.Count; int i 0; foreach (var item in abToUpdate) { string localName item.name; if (MyFTPManager.Single.DownLoadFile(localName, RootSO.Single.FTPServerUrl, Application.persistentDataPath, RootSO.Single.userName, RootSO.Single.password, null)) { //File.Move(localName, item.name); i; showAction?.Invoke($下载资源包{i}/{num}); logAction?.Invoke($更新{item.name}完成); } else { logAction?.Invoke($下载资源包{item.name}失败\n); result.data false; yield break; } yield return null; } result.ok true; }考虑使用GetResponseAsync或者UnityWebRequest。FTP异步版我们发现异步、阻塞这些东西是先在实战中发现痛点后自然而然有的。而如果没有经历过这些很难理解很多更复杂的设计为什么存在。然后发现底层用async后一直到最上层全部要改成async。用async写了从底到上一套方法发现FTP下载中编辑器还是阻塞。async void HotUpdate2Async() { string ABChecklistPath_local Path.Combine(Application.persistentDataPath, RootSO.Single.ABChecklist_local); string ABChecklistPath_remote Path.Combine(Application.persistentDataPath, RootSO.Single.ABChecklist); logAction?.Invoke(检查本地资源清单文件…); if (!File.Exists(ABChecklistPath_local)) {//第一次打开 logAction?.Invoke(本地资源清单文件不存在下载); bool downloadABListOK await DownloadABChecklistAsync(logAction); if (downloadABListOK) { logAction?.Invoke(下载成功); string json File.ReadAllText(ABChecklistPath_remote); aBCheckListRemote JsonConvert.DeserializeObjectABCheckList(json); if (aBCheckListRemote null) { logAction?.Invoke(AB清单文件解析失败); onUpdateOver?.Invoke(false); return; } else { bool downloadABOK await DownloadAllAsync(); if (downloadABOK) { File.Move(ABChecklistPath_remote, ABChecklistPath_local); } onUpdateOver?.Invoke(downloadABOK); } } } else { string json File.ReadAllText(ABChecklistPath_local); aBCheckListLocal JsonConvert.DeserializeObjectABCheckList(json); if (aBCheckListLocal null) { logAction?.Invoke(本地资源清单文件损坏); } bool downloadABListOK await DownloadABChecklistAsync(logAction); if (downloadABListOK) { logAction?.Invoke(下载成功。读取并解析…); string json2 File.ReadAllText(ABChecklistPath_remote); aBCheckListRemote JsonConvert.DeserializeObjectABCheckList(json2); if (aBCheckListRemote ! null) {//对比资源 bool compareOK await AddUpdateRemoveAsync(); onUpdateOver?.Invoke(compareOK); } else { logAction?.Invoke(服务器资源清单文件损坏); onUpdateOver?.Invoke(false); } } else { logAction?.Invoke(下载资源清单失败); onUpdateOver?.Invoke(false); } } } async Taskbool DownloadAllAsync() { ListABInfo abToUpdate new(); foreach (var item in aBCheckListRemote.ABInfos.Values) { abToUpdate.Add(item); } int num abToUpdate.Count; int i 0; foreach (var item in abToUpdate) { showAction?.Invoke($下载资源包{i}/{num}); string localName item.name; bool okawait MyFTPManager.Single.DownLoadFileAsync(localName, RootSO.Single.FTPServerUrl, Application.persistentDataPath, RootSO.Single.userName, RootSO.Single.password, null); if (ok) { //File.Move(localName, item.name); i; logAction?.Invoke($更新{item.name}完成); } else { logAction?.Invoke($下载资源包{item.name}失败\n); return false; } } return true; } async Taskbool DownloadABChecklistAsync(UnityActionstring callback) { bool okawait MyFTPManager.Single.DownLoadFileAsync(RootSO.Single.ABChecklist, RootSO.Single.FTPServerUrl, Application.persistentDataPath, RootSO.Single.userName, RootSO.Single.password, callback); return ok; } async Taskbool AddUpdateRemoveAsync() { ListABInfo abToUpdate new(); foreach (var item in aBCheckListRemote.ABInfos.Values) { if (!aBCheckListLocal.ABInfos.ContainsKey(item.name)) {//服务器有本地没有的要下载 abToUpdate.Add(item); logAction?.Invoke($需要更新{item.name}); } else { if (aBCheckListLocal.ABInfos[item.name].MD5 ! item.MD5) { abToUpdate.Add(item); logAction?.Invoke($需要更新{item.name}); } } } foreach (var item in aBCheckListLocal.ABInfos.Values) { if (!aBCheckListRemote.ABInfos.ContainsKey(item.name)) { logAction?.Invoke($需要删除{item.name}); File.Delete(Path.Combine(SandboxPath, item.name)); } } foreach (var item in abToUpdate) { bool ok await MyFTPManager.Single.DownLoadFileAsync(item.name, RootSO.Single.FTPServerUrl, Application.persistentDataPath, RootSO.Single.userName, RootSO.Single.password, null); if (ok) { logAction?.Invoke($更新{item.name}完成); } else { logAction?.Invoke($下载资源包{item.name}失败\n); return false; } } return true; }FTP服务器搭建FTP协议笔记-CSDN博客总结使用FTP的热更新全程同步下载直接阻塞编辑器打印任何日志、提示都会滞后。不能用。同步FTP协程每个资源包等一帧能打印提示了大部分时间仍然阻塞无法操作编辑器async FTP。能提示、能操作但有卡顿。然后查资料知道FTP在手机平台可能被拦截现在手游下载资源包都用HTTP/HTTPS那么我们不再讨论用FTP做热更新。