原理
透過http獲取到遠端程式碼,並下載加來替換掉本次使用的程式碼
編輯器啟動本地伺服器(程式碼示例)
#if !NO_HYBRIDCLR
using HybridCLR;
#endif
using System;
using System.Reflection;
using UnityEngine;
/// <summary>
/// 啟動流程-載入並應用dll
/// </summary>
public class LoadDllLaunchTask : LaunchTask
{
/// <inheritdoc/>
public override void Run()
{
TestLogManager.Instance.StartRecord(TestLogManager.TestLogKey.Launch_LoadDll);
LoadDllHotFix();
}
/// <inheritdoc/>
protected override void OnFinished()
{
}
/// <summary>
/// 載入dll熱修內容
/// </summary>
private void LoadDllHotFix()
{
byte[] hotBytes = null;
LoadDlls((name, bytes) => {
if (name.ToLower() == "hotfixassembly")
{
hotBytes = bytes;
}
else
{
RuntimeApi.LoadMetadataForAOTAssembly(bytes, HomologousImageMode.SuperSet);
Debug.Log($"載入AOT成功 {name}");
}
SetComplete();
}, () => {
if (hotBytes == null)
{
Debug.LogError("載入熱更程式碼失敗");
return;
}
Assembly.Load(hotBytes);
Debug.Log($"載入熱更程式碼成功");
TestLogManager.Instance.EndRecord(TestLogManager.TestLogKey.Launch_LoadDll);
SetComplete();
});
}
private void LoadDlls(Action<string, byte[]> dllLoaded, Action allCompleted)
{
string RemoteDllURL = Launch.Instance.RemoteDllURL;
if (string.IsNullOrEmpty(RemoteDllURL))
{
ResourceLoader.LoadAllAsset("Dll", (objects, str) =>
{
if (objects == null)
{
Debug.LogError("載入熱更程式碼失敗");
return;
}
for (int i = 0; i < objects.Length; i++)
{
TextAsset textAsset = objects[i] as TextAsset;
dllLoaded(textAsset.name, textAsset.bytes);
}
allCompleted();
});
}
else
{
RemoteDllLoader loader = new RemoteDllLoader();
loader.Initialize(RemoteDllURL, dict =>
{
foreach (var pair in dict)
{
dllLoaded(pair.Key, pair.Value);
}
allCompleted();
});
}
}
}
使用遠端程式碼資源(程式碼示例)
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using UnityEngine;
using UnityEngine.Networking;
/// <summary>
/// 遠端載入本機Dll
/// </summary>
public class RemoteDllLoader
{
#region Properties
private string serverURL;
private ZipArchive zipArchive;
#endregion
#region Public Methods
/// <summary>
/// 初始化
/// </summary>
/// <param name="serverURL">伺服器地址</param>
/// <param name="completed">完成回撥</param>
public void Initialize(string serverURL, Action<Dictionary<string, byte[]>> completed)
{
serverURL = serverURL.TrimEnd('/');
this.serverURL = serverURL;
var request = UnityWebRequest.Get(this.serverURL + "?code_zip=true");
var asyncOp = request.SendWebRequest();
asyncOp.completed += asyncOperation =>
{
#if UNITY_2020_1_OR_NEWER
var isNetError = !(request.result == UnityWebRequest.Result.InProgress ||
request.result == UnityWebRequest.Result.Success);
#else
bool isNetError = request.isHttpError || request.isNetworkError;
#endif
if (isNetError)
{
Debug.LogErrorFormat("請求程式碼資源失敗:{0}\n{1}", request.url, request.error);
}
else
{
var data = request.downloadHandler.data;
Debug.Log("請求程式碼資源成功");
zipArchive = new ZipArchive(new MemoryStream(data), ZipArchiveMode.Read);
}
Dictionary<string, byte[]> codeMap = new Dictionary<string, byte[]>();
for (var i = 0; i < zipArchive.Entries.Count; i++)
{
var entry = zipArchive.Entries[i];
using (var stream = entry.Open())
{
byte[] bytes = new byte[entry.Length];
stream.Read(bytes, 0, bytes.Length);
codeMap.Add(entry.Name, bytes);
}
}
completed(codeMap);
};
}
#endregion
#region Internal Methods
#endregion
}
adb連線
adb reverse tcp:1234 tcp:1234