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}(下次打包生效)"); } }