using System;
using System.Collections;
using System.Linq;
using System.Reflection;
using AOT.Boot;
using UnityEngine;
using YooAsset;
#if !UNITY_EDITOR
using HybridCLR;
#endif
namespace AOT.HotUpdate
{
///
/// 加载热更程序集并调用稳定入口 HotUpdate.Entry.Start(BootContext)。
///
public static class HotUpdateLoader
{
const string EntryTypeName = "HotUpdate.Entry";
const string EntryMethodName = "Start";
public static IEnumerator LoadAndStart(BootContext ctx, BootSettings settings, Action onError)
{
#if UNITY_EDITOR
if (settings.EditorDirectHotUpdate || ctx.Package == null)
{
var err = InvokeEntry(FindLoadedAssembly("HotUpdate.Runtime"), ctx);
if (err != null) onError?.Invoke(err);
yield break;
}
#endif
if (ctx.Package == null)
{
onError?.Invoke("ResourcePackage 为空,无法加载热更 DLL");
yield break;
}
var handle = ctx.Package.LoadAssetAsync(settings.HotUpdateDllLocation);
yield return handle;
if (handle.Status != EOperationStatus.Succeeded)
{
onError?.Invoke($"加载热更 DLL 失败: {handle.Error}");
yield break;
}
var raw = handle.GetAssetObject();
if (raw == null)
{
onError?.Invoke("热更 DLL RawFileObject 为空");
yield break;
}
byte[] dllBytes = raw.GetBytes();
handle.Release();
if (dllBytes == null || dllBytes.Length < 64)
{
onError?.Invoke($"热更 DLL 字节异常 length={dllBytes?.Length ?? 0}");
yield break;
}
Debug.Log($"[HotUpdateLoader] RawFile loaded location={settings.HotUpdateDllLocation} bytes={dllBytes.Length}");
#if UNITY_EDITOR
// 编辑器域内已加载同名程序集,不能重复 Assembly.Load;验证 RawFile 后走反射入口。
{
var err = InvokeEntry(FindLoadedAssembly("HotUpdate.Runtime"), ctx);
if (err != null) onError?.Invoke(err);
yield break;
}
#else
// AOT 补充元数据:后续由 HybridCLR Generate 产物批量加载。
// HybridCLR.RuntimeApi.LoadMetadataForAOTAssembly(metaBytes, HomologousImageMode.SuperSet);
Assembly asm;
try
{
asm = Assembly.Load(dllBytes);
}
catch (Exception e)
{
onError?.Invoke($"Assembly.Load 失败: {e.Message}");
yield break;
}
var invokeErr = InvokeEntry(asm, ctx);
if (invokeErr != null)
onError?.Invoke(invokeErr);
#endif
}
static Assembly FindLoadedAssembly(string name)
{
return AppDomain.CurrentDomain.GetAssemblies()
.FirstOrDefault(a => string.Equals(a.GetName().Name, name, StringComparison.Ordinal));
}
static string InvokeEntry(Assembly asm, BootContext ctx)
{
if (asm == null)
return "未找到热更程序集 HotUpdate.Runtime";
var type = asm.GetType(EntryTypeName, throwOnError: false);
if (type == null)
return $"未找到类型 {EntryTypeName}";
var method = type.GetMethod(EntryMethodName, BindingFlags.Public | BindingFlags.Static);
if (method == null)
return $"未找到方法 {EntryTypeName}.{EntryMethodName}";
try
{
method.Invoke(null, new object[] { ctx });
return null;
}
catch (Exception e)
{
var inner = e is TargetInvocationException tie && tie.InnerException != null
? tie.InnerException
: e;
return $"调用热更入口失败: {inner.Message}";
}
}
}
}