using TFramework; using System.Collections; using System.Collections.Generic; using UnityEngine; using System; using UnityEngine.Networking; #if HybridCLR using HybridCLR; #endif namespace TModule.Runtime { public class HotfixManager : MonoBehaviour { public bool m_isEnableHotfix = true; public string m_resServerUrl; public string m_updateHandle; public string m_versionFileName; /// ///本地资源存放路径 /// public string LocalResFilePath { get; private set; } /// /// 本地版本文件存放路径 /// private string _loaclVersionPath; /// /// 待下载资源列表 /// private List _NeedDownloadResList = new List(); /// /// 本地资源列表 /// private List _LocalResList = new List(); /// /// 检查版本文件进行事件 /// private Action OnCheckVersion; /// /// 版本文件检查完成事件 /// private Action OnCheckVersionOver; /// /// 版本文件检查出错事件 /// private Action OnCheckVersionError; /// /// 检查进度 /// private float _checkProgress; /// /// 超时时间 /// public const int DOWNLOADTIMEOUT = 5; public float TotalSize { get { float szie = 0; _NeedDownloadResList.ForEach(p => szie += (float)p.m_size); return szie; } } void Start() { if (m_isEnableHotfix) { } } /// /// 检查版本文件 /// public void InitCheckVersion(Action checkVersion, Action checkVersionOver, Action checkVersionError = null) { if (string.IsNullOrEmpty(AssetConfig.ResUrl)) { Log.Error("未指定资源服务器地址"); return; } OnCheckVersion = checkVersion; OnCheckVersionOver = checkVersionOver; OnCheckVersionError = checkVersionError; _checkProgress = 0; string strVersionPath = AssetConfig.ResUrl + m_versionFileName; StartCoroutine(DowloadVersion(strVersionPath)); } /// /// 对比版本文件 /// /// private void OnInitVersionCallBack(List arg0) { _loaclVersionPath = LocalResFilePath + m_versionFileName; if (FileOperations.FileExists(_loaclVersionPath)) { List clienData = FileOperations.ReadJsonData>(_loaclVersionPath); foreach (var item in arg0) { _checkProgress += 1.0f / arg0.Count / 2; _checkProgress = _checkProgress >= 1 ? 1 : _checkProgress; OnCheckVersion?.Invoke(_checkProgress); VersionDataEntity dataEntity = clienData.Find(p => p.m_fullName == item.m_fullName); //已有资源 if (dataEntity != null) { //对比MD5 if (dataEntity.m_md5 != item.m_md5) _NeedDownloadResList.Add(item); } else _NeedDownloadResList.Add(item);//新资源 } } else arg0.ForEach(p => { _NeedDownloadResList.Add(p); _checkProgress += 1.0f / arg0.Count / 2; _checkProgress = _checkProgress >= 1 ? 1 : _checkProgress; OnCheckVersion?.Invoke(_checkProgress); }); if (_NeedDownloadResList.Count > 0) OnCheckVersionOver?.Invoke(TotalSize); else OnCheckVersionOver?.Invoke(0); } /// /// 下载版本文件 /// /// /// /// private IEnumerator DowloadVersion(string url) { UnityWebRequest www = UnityWebRequest.Get(url); www.timeout = DOWNLOADTIMEOUT; yield return www.SendWebRequest(); while (!www.isDone) { _checkProgress = www.downloadProgress / 2; OnCheckVersion?.Invoke(_checkProgress); } if (www.result != UnityWebRequest.Result.ProtocolError && www.result != UnityWebRequest.Result.ConnectionError) { string content = www.downloadHandler.text; _checkProgress = 0.5f; OnInitVersionCallBack(content.JsonStrToObject>()); Debug.Log(content); } else { Debug.Log("下载失败:" + www.error); OnCheckVersionError?.Invoke(www.error); } } /// /// 保存版本文件 /// private void SaveLoaclVersion() => FileOperations.WriteJsonData(_LocalResList, _loaclVersionPath); /// /// 更新版本文件 /// /// public void ModifyLocaData(VersionDataEntity entity) { if (_LocalResList == null) return; bool isExists = false; for (int i = 0; i < _LocalResList.Count; i++) { if (_LocalResList[i].m_fullName.Equals(entity.m_fullName, StringComparison.CurrentCultureIgnoreCase)) { _LocalResList[i].m_md5 = entity.m_md5; _LocalResList[i].m_fullName = entity.m_fullName; _LocalResList[i].m_size = entity.m_size; isExists = true; break; } } if (!isExists) { _LocalResList.Add(entity); } SaveLoaclVersion(); } private static void LoadMetadataForAOTAssemblies() { List aotMetaAssemblyFiles = new List() { "mscorlib.dll", "System.dll", "System.Core.dll", }; /// 注意,补充元数据是给AOT dll补充元数据,而不是给热更新dll补充元数据。 /// 热更新dll不缺元数据,不需要补充,如果调用LoadMetadataForAOTAssembly会返回错误 /// #if HybridCLR HomologousImageMode mode = HomologousImageMode.SuperSet; foreach (var aotDllName in aotMetaAssemblyFiles) { byte[] dllBytes = FileOperations.SafeReadAllBytes(AssetConfig.AssetBundleRootPath + aotDllName + ".bytes"); // 加载assembly对应的dll,会自动为它hook。一旦aot泛型函数的native函数不存在,用解释器版本代码 LoadImageErrorCode err = RuntimeApi.LoadMetadataForAOTAssembly(dllBytes, mode); Debug.Log($"LoadMetadataForAOTAssembly:{aotDllName}. mode:{mode} ret:{err}"); } #else Log.Error("当前非热更环境!请先安装HybridCLR"); #endif } } }