using System.IO;
using HybridCLR;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;
///
/// 打包后把这次构建裁剪出来的 AOT 补充元数据 dll 刷进 StreamingAssets/HybridCLR/AOT。
///
/// 为什么要它:运行时 Launcher 会去 StreamingAssets/HybridCLR/AOT 读这些 dll 做"补充元数据"
/// (HybridCLR 的 LoadMetadataForAOTAssembly)。它们是构建过程裁剪出来的,HybridCLR 不会自动
/// 替你放进 StreamingAssets —— 漏了这一步,一旦改到 AOT 代码(GameFramework / Launcher /
/// Assembly-CSharp 这类),就会出现类型/函数缺失甚至黑屏。
///
/// 同步范围:只刷新 StreamingAssets/HybridCLR/AOT 里**已经存在**的那些 *.dll.bytes
/// (用它的文件名去裁剪产物目录里找同名 dll)。所以要在元数据列表里增减程序集,
/// 只需在 StreamingAssets/HybridCLR/AOT 下增删对应的 *.dll.bytes 文件即可。
///
/// ⚠ 时序:AOT dll 是"这次构建"才产出的,所以这一步只能在构建结束(Postprocess)后执行,
/// 也就是说这次构建用的仍是上一次同步的结果,**下一次构建**才会带上最新元数据。
/// 所以:改了 AOT 代码 → 连续打两次包(或打完第一次后手动再打一次)。
///
/// 想临时关掉自动同步,把 AutoSyncOnBuild 改成 false;也可以手动执行菜单
/// Tools/刷新AOT元数据到StreamingAssets。
///
public class AOTMetadataStreamingAssetsSync : IPostprocessBuildWithReport
{
/// 打包后是否自动同步 AOT 补充元数据
private const bool AutoSyncOnBuild = true;
/// 运行时读取补充元数据的目录(相对项目根)
private const string StreamingAOTDir = "Assets/StreamingAssets/HybridCLR/AOT";
private const string BytesSuffix = ".bytes";
public int callbackOrder => 0;
public void OnPostprocessBuild(BuildReport report)
{
if (!AutoSyncOnBuild) return;
Sync(report.summary.platform);
}
[MenuItem("Tools/刷新AOT元数据到StreamingAssets")]
public static void SyncActive()
{
Sync(EditorUserBuildSettings.activeBuildTarget);
EditorUtility.DisplayDialog("AOT 元数据",
"已把最新的 AOT 补充元数据刷进 StreamingAssets/HybridCLR/AOT", "好");
}
/// 按 StreamingAssets 里现有的 *.dll.bytes,从本次构建的裁剪产物目录刷新同名 dll。
private static void Sync(BuildTarget target)
{
string srcDir = SettingsUtil.GetAssembliesPostIl2CppStripDir(target);
if (!Directory.Exists(srcDir))
{
Debug.LogWarning($"[AOTMeta] 找不到裁剪后的 AOT dll 目录: {srcDir}(还没构建过?)");
return;
}
if (!Directory.Exists(StreamingAOTDir))
{
Debug.LogWarning($"[AOTMeta] 目录不存在: {StreamingAOTDir}");
return;
}
int copied = 0;
foreach (var dst in Directory.GetFiles(StreamingAOTDir))
{
if (!dst.EndsWith(".dll" + BytesSuffix)) continue;
// 磁盘文件形如 "GameFramework.dll.bytes" → 源文件名 "GameFramework.dll"
string dllName = Path.GetFileName(dst);
dllName = dllName.Substring(0, dllName.Length - BytesSuffix.Length);
string src = Path.Combine(srcDir, dllName);
if (!File.Exists(src))
{
Debug.LogWarning($"[AOTMeta] 裁剪产物里没有 {dllName},跳过({src})");
continue;
}
File.Copy(src, dst, true);
copied++;
}
AssetDatabase.Refresh();
Debug.Log($"[AOTMeta] 已同步 {copied} 个 AOT 补充元数据 dll 到 {StreamingAOTDir}(下次打包生效)");
}
}