93 lines
3.8 KiB
C#
93 lines
3.8 KiB
C#
using System.IO;
|
||
using HybridCLR;
|
||
using UnityEditor;
|
||
using UnityEditor.Build;
|
||
using UnityEditor.Build.Reporting;
|
||
using UnityEngine;
|
||
|
||
/// <summary>
|
||
/// 打包后把这次构建裁剪出来的 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。
|
||
/// </summary>
|
||
public class AOTMetadataStreamingAssetsSync : IPostprocessBuildWithReport
|
||
{
|
||
/// <summary>打包后是否自动同步 AOT 补充元数据</summary>
|
||
private const bool AutoSyncOnBuild = true;
|
||
|
||
/// <summary>运行时读取补充元数据的目录(相对项目根)</summary>
|
||
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", "好");
|
||
}
|
||
|
||
/// <summary>按 StreamingAssets 里现有的 *.dll.bytes,从本次构建的裁剪产物目录刷新同名 dll。</summary>
|
||
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}(下次打包生效)");
|
||
}
|
||
}
|