using HybridCLR; using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Threading.Tasks; using UnityEngine; using UnityEngine.Networking; using LitJson; using TMPro; using UnityEngine.UI; public class LoadDll : MonoBehaviour { public GameObject EditorGame; static LoadDll instance; private void Awake() { instance = this; } void Start() { this.transform.SetParent(OpenXRCamera.Instance.head.transform); this.transform.localPosition = Vector3.zero; this.transform.localEulerAngles = Vector3.zero; //PlayerPrefs.DeleteAll(); #if ISLOCAL EditorGame.SetActive(true); this.gameObject.SetActive(false); #else StartCoroutine(DownLoadAssets()); #endif } private static Dictionary s_assetDatas = new Dictionary(); public static byte[] ReadBytesFromStreamingAssets(string dllName) { return s_assetDatas[dllName]; } private string GetWebRequestPath(string asset) { var path = $"{Application.streamingAssetsPath}/{asset}"; if (!path.Contains("://")) { path = "file://" + path; } return path; } private static List AOTMetaAssemblyFiles { get; } = new List() { "mscorlib.dll.bytes", "System.dll.bytes", "System.Core.dll.bytes", "litjson.dll.bytes" }; public Text text; public Text text2; public Slider slider; string HotUpdateScripts = "HotUpdateScripts"; string HotUpdateAssets = "HotUpdateAssets"; IEnumerator DownLoadAssets() { text.text = "正在获取网关数据"; for (int i = 0; i < AOTMetaAssemblyFiles.Count; i++) { yield return DownLoadLocal(AOTMetaAssemblyFiles[i]); } slider.gameObject.SetActive(false); while (HttpSDKAction.Instance.jsonData==null || HttpSDKAction.Instance.jsonData=="") { yield return null; } JsonData data = new JsonData(); string scUrl = ""; string artUrl = ""; try { data = JsonMapper.ToObject(HttpSDKAction.Instance.jsonData); scUrl = data[HotUpdateScripts].ToString(); artUrl = data[HotUpdateAssets].ToString(); } catch { } if(scUrl != "") { if (!bool.Parse(data["isHotUpdate"].ToString())) { text.text = "正在下载代码"; yield return DownLoadAssets(scUrl, HotUpdateScripts, false); text.text = "正在下载配置"; yield return DownLoadAssets(artUrl, HotUpdateAssets, false); } else if (PlayerPrefs.GetString("HotUpdateVersion") == data["HotUpdateVersion"].ToString()) { text.text = "正在编译代码"; string filePath = PlayerPrefs.GetString(HotUpdateScripts); Task Tb = File.ReadAllBytesAsync(filePath); yield return Tb; slider.gameObject.SetActive(false); Assembly.Load(Tb.Result); text.text = "正在解析配置"; filePath = PlayerPrefs.GetString(HotUpdateAssets); Task Tb2 = File.ReadAllBytesAsync(filePath); yield return Tb2; text.text = "正在解析配置"; slider.gameObject.SetActive(false); AssetBundleCreateRequest acr = AssetBundle.LoadFromMemoryAsync(Tb2.Result); while (!acr.isDone) { text2.text = (acr.progress*100).ToString("F2") + "%"; slider.value = float.Parse((acr.progress ).ToString("F2")); yield return null; } slider.gameObject.SetActive(true); AssetBundleRequest abr = acr.assetBundle.LoadAssetAsync("LocalAsset"); text.text = "正在加载配置"; while (!abr.isDone) { text2.text = (abr.progress * 100).ToString("F2") + "%"; slider.value = float.Parse((abr.progress ).ToString("F2")); yield return null; } copyGameObject(abr.asset); this.gameObject.SetActive(false); } else { text.text = "正在下载代码"; yield return DownLoadAssets(scUrl, HotUpdateScripts); text.text = "正在下载配置"; yield return DownLoadAssets(artUrl, HotUpdateAssets); } } else { text.text = "正在下载代码"; yield return DownLoadAssets(scUrl, HotUpdateScripts, false); text.text = "正在下载配置"; yield return DownLoadAssets(artUrl, HotUpdateAssets, false); } } public IEnumerator DownLoadLocal(string name) { slider.gameObject.SetActive(true); UnityWebRequest www = UnityWebRequest.Get(GetWebRequestPath(name)); www.SendWebRequest(); while (!www.isDone) { text2.text = (www.downloadProgress * 100).ToString("F2") + "%"; slider.value = float.Parse((www.downloadProgress).ToString("F2")); yield return null; } #if UNITY_2020_1_OR_NEWER if (www.result != UnityWebRequest.Result.Success) { Debug.Log(www.error); } #else if (www.isHttpError || www.isNetworkError) { Debug.Log(www.error); } #endif HomologousImageMode mode = HomologousImageMode.SuperSet; LoadImageErrorCode err = RuntimeApi.LoadMetadataForAOTAssembly(www.downloadHandler.data, mode); Debug.Log($"LoadMetadataForAOTAssembly:{name}. mode:{mode} ret:{err}"); } public IEnumerator DownLoadAssets(string dllPath,string name,bool isRemote=true) { slider.gameObject.SetActive(true); if(!isRemote) { dllPath = GetWebRequestPath(name); } UnityWebRequest www = UnityWebRequest.Get(dllPath); www.SendWebRequest(); while (!www.isDone) { text2.text = (www.downloadProgress * 100).ToString("F2") + "%"; slider.value = float.Parse((www.downloadProgress ).ToString("F2")); yield return null; } #if UNITY_2020_1_OR_NEWER if (www.result != UnityWebRequest.Result.Success) { Debug.Log(www.error); } #else if (www.isHttpError || www.isNetworkError) { Debug.Log(www.error); } #endif else { if(name == HotUpdateScripts) { text.text = "正在编译代码"; slider.gameObject.SetActive(false); Assembly.Load(www.downloadHandler.data); string fileName = HotUpdateScripts; if (!Directory.Exists(Application.persistentDataPath + "/HotUpdate")) Directory.CreateDirectory(Application.persistentDataPath + "/HotUpdate" ); string filePathname = Application.persistentDataPath + "/HotUpdate/" + fileName; // if (File.Exists(filePathname)) // File.Delete(filePathname); File.WriteAllBytes(filePathname, www.downloadHandler.data); PlayerPrefs.SetString(HotUpdateScripts, filePathname); } else { text.text = "正在解析配置"; slider.gameObject.SetActive(false); AssetBundleCreateRequest acr = AssetBundle.LoadFromMemoryAsync(www.downloadHandler.data); while (!acr.isDone) { text2.text = (acr.progress * 100).ToString("F2") + "%"; slider.value = float.Parse((acr.progress ).ToString("F2")); yield return null; } slider.gameObject.SetActive(true); AssetBundleRequest abr = acr.assetBundle.LoadAssetAsync("LocalAsset"); text.text = "正在加载配置"; while (!abr.isDone) { text2.text = (abr.progress * 100).ToString("F2") + "%"; slider.value = float.Parse((abr.progress ).ToString("F2")); yield return null; } copyGameObject(abr.asset); this.gameObject.SetActive(false); string fileName = HotUpdateAssets; if (!Directory.Exists(Application.persistentDataPath + "/HotUpdate")) Directory.CreateDirectory(Application.persistentDataPath + "/HotUpdate"); string filePathname = Application.persistentDataPath + "/HotUpdate/" + fileName; // if (File.Exists(filePathname)) // File.Delete(filePathname); File.WriteAllBytes(filePathname, www.downloadHandler.data); PlayerPrefs.SetString(HotUpdateAssets, filePathname); } } } void copyGameObject(UnityEngine.Object o) { Instantiate(o); } private static Assembly _hotUpdateAss; /// /// 为aot assembly加载原始metadata, 这个代码放aot或者热更新都行。 /// 一旦加载后,如果AOT泛型函数对应native实现不存在,则自动替换为解释模式执行 /// private static void LoadMetadataForAOTAssemblies() { /// 注意,补充元数据是给AOT dll补充元数据,而不是给热更新dll补充元数据。 /// 热更新dll不缺元数据,不需要补充,如果调用LoadMetadataForAOTAssembly会返回错误 /// HomologousImageMode mode = HomologousImageMode.SuperSet; foreach (var aotDllName in AOTMetaAssemblyFiles) { byte[] dllBytes = ReadBytesFromStreamingAssets(aotDllName); // 加载assembly对应的dll,会自动为它hook。一旦aot泛型函数的native函数不存在,用解释器版本代码 LoadImageErrorCode err = RuntimeApi.LoadMetadataForAOTAssembly(dllBytes, mode); Debug.Log($"LoadMetadataForAOTAssembly:{aotDllName}. mode:{mode} ret:{err}"); } } void StartGame() { // LoadMetadataForAOTAssemblies(); /* #if !UNITY_EDITOR _hotUpdateAss = Assembly.Load(ReadBytesFromStreamingAssets("HotUpdate.dll.bytes")); #else _hotUpdateAss = System.AppDomain.CurrentDomain.GetAssemblies().First(a => a.GetName().Name == "HotUpdate"); #endif */ // Type entryType = _hotUpdateAss.GetType("Entry"); // entryType.GetMethod("Start").Invoke(null, null); } }