#if ENABLE_HOOK_TEST_CASE using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using UnityEditor; using UnityEditor.Callbacks; using UnityEngine; using System.Linq; namespace MonoHook.Test { // 有需求时可以打开,也可以手动按需注册Hook [InitializeOnLoad] public class BuildPipeline_StripDll_HookTest { /// /// 裁剪执行完毕的回调,可能会被调用多次,一般而言同一次打包只需要处理第一次回调 /// public static Action OnAssemblyStripped; // 尝试 Hook 4个函数,至少一个被调用就可以达到要求 private static MethodHook _hook_PostprocessBuildPlayer_CompleteBuild; private static MethodHook _hook_Default_PostProcess; private static MethodHook _hook_ReportBuildResults; private static MethodHook _hook_StripAssembliesTo; #region Fake Internal Structures public struct BuildPostProcessArgs { public BuildTarget target; public int subTarget; public string stagingArea; public string stagingAreaData; public string stagingAreaDataManaged; public string playerPackage; public string installPath; public string companyName; public string productName; public Guid productGUID; public BuildOptions options; public UnityEditor.Build.Reporting.BuildReport report; internal /*RuntimeClassRegistry*/object usedClassRegistry; } public sealed class BeeDriverResult { public /*NodeResult*/object[] NodeResults { get; set; } public bool Success { get; set; } public /*Message*/object[] BeeDriverMessages { get; set; } public override string ToString() => Success.ToString(); } #endregion static BuildPipeline_StripDll_HookTest() { InstallHook(); #if ENABLE_HOOK_TEST_CASE OnAssemblyStripped = DemoStripCallback; #endif } /// /// 示例裁剪回调函数 /// /// /// /// static void DemoStripCallback(string outputFolder, BuildPostProcessArgs args, BeeDriverResult result) { if (outputFolder != null) Debug.Log($"stripped outputFolder is:{outputFolder}"); else if (args.stagingAreaDataManaged != null) Debug.Log($"stripped staging folder is:{args.stagingAreaDataManaged}"); else if (result != null) Debug.Log($"stripped result is: {result.Success}"); else Debug.Log("stripped test called"); } public static void InstallHook() { do { Type type = Type.GetType("UnityEditor.PostprocessBuildPlayer,UnityEditor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"); if (type == null) { Debug.LogError($"can not find type: UnityEditor.PostprocessBuildPlayer"); break; } MethodInfo miTarget = type.GetMethod("PostProcessCompletedBuild", BindingFlags.Static | BindingFlags.Public); if (miTarget == null) { Debug.LogError($"can not find method: UnityEditor.PostprocessBuildPlayer.PostProcessCompletedBuild"); break; } MethodInfo miReplace = typeof(BuildPipeline_StripDll_HookTest).GetMethod(nameof(PostprocessBuildPlayer_CompleteBuild_Replace), BindingFlags.Static | BindingFlags.NonPublic); MethodInfo miProxy = typeof(BuildPipeline_StripDll_HookTest).GetMethod(nameof(PostprocessBuildPlayer_CompleteBuild_Proxy), BindingFlags.Static | BindingFlags.NonPublic); _hook_PostprocessBuildPlayer_CompleteBuild = new MethodHook(miTarget, miReplace, miProxy); _hook_PostprocessBuildPlayer_CompleteBuild.Install(); Debug.Log("Hook BuildPipeline_StripDll_HookTest.PostprocessBuildPlayer_CompleteBuild installed"); } while (false); do { Type type = Type.GetType("UnityEditor.Modules.DefaultBuildPostprocessor,UnityEditor.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"); if (type == null) { Debug.LogError($"can not find type: UnityEditor.Modules.DefaultBuildPostprocessor"); break; } MethodInfo[] miTargets = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly); MethodInfo miTarget = (from mi in miTargets where mi.Name == "PostProcess" && mi.GetParameters().Length == 2 select mi).FirstOrDefault(); if (miTarget == null) { Debug.LogError($"can not find method: UnityEditor.Modules.DefaultBuildPostprocessor.PostProcess"); break; } MethodInfo miReplace = typeof(BuildPipeline_StripDll_HookTest).GetMethod(nameof(Default_PostProcess_Replace), BindingFlags.Static | BindingFlags.NonPublic); MethodInfo miProxy = typeof(BuildPipeline_StripDll_HookTest).GetMethod(nameof(Default_PostProcess_Proxy), BindingFlags.Static | BindingFlags.NonPublic); _hook_Default_PostProcess = new MethodHook(miTarget, miReplace, miProxy); _hook_Default_PostProcess.Install(); Debug.Log("Hook BuildPipeline_StripDll_HookTest.PostProcess installed"); } while (false); do { Type type = Type.GetType("UnityEditor.Modules.BeeBuildPostprocessor,UnityEditor.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"); if (type == null) { Debug.LogError($"can not find type: UnityEditor.Modules.BeeBuildPostprocessor"); break; } MethodInfo miTarget = type.GetMethod("ReportBuildResults", BindingFlags.Instance | BindingFlags.NonPublic); if (miTarget == null) { Debug.LogError($"can not find method: UnityEditor.Modules.BeeBuildPostprocessor.ReportBuildResults"); break; } MethodInfo miReplace = typeof(BuildPipeline_StripDll_HookTest).GetMethod(nameof(ReportBuildResults_Replace), BindingFlags.Static | BindingFlags.NonPublic); MethodInfo miProxy = typeof(BuildPipeline_StripDll_HookTest).GetMethod(nameof(ReportBuildResults_Proxy), BindingFlags.Static | BindingFlags.NonPublic); _hook_ReportBuildResults = new MethodHook(miTarget, miReplace, miProxy); _hook_ReportBuildResults.Install(); Debug.Log("Hook BuildPipeline_StripDll_HookTest.ReportBuildResults installed"); } while (false); do { Type type = Type.GetType("UnityEditorInternal.AssemblyStripper,UnityEditor.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"); if (type == null) { Debug.LogError($"can not find type: UnityEditorInternal.AssemblyStripper"); break; } MethodInfo miTarget = type.GetMethod("StripAssembliesTo", BindingFlags.Static | BindingFlags.NonPublic); if (miTarget == null) { Debug.LogError($"can not find method: UnityEditorInternal.AssemblyStripper.StripAssembliesTo"); break; } MethodInfo miReplace = typeof(BuildPipeline_StripDll_HookTest).GetMethod(nameof(StripAssembliesTo_Replace), BindingFlags.Static | BindingFlags.NonPublic); MethodInfo miProxy = typeof(BuildPipeline_StripDll_HookTest).GetMethod(nameof(StripAssembliesTo_Proxy), BindingFlags.Static | BindingFlags.NonPublic); _hook_StripAssembliesTo = new MethodHook(miTarget, miReplace, miProxy); _hook_StripAssembliesTo.Install(); Debug.Log("Hook BuildPipeline_StripDll_HookTest.StripAssembliesTo installed"); } while (false); } public static void UninstallHook() { _hook_PostprocessBuildPlayer_CompleteBuild?.Uninstall(); _hook_Default_PostProcess?.Uninstall(); _hook_ReportBuildResults?.Uninstall(); _hook_StripAssembliesTo?.Uninstall(); } static void PostprocessBuildPlayer_CompleteBuild_Replace(BuildPostProcessArgs args) { Debug.Log("PostprocessBuildPlayer_CompleteBuild_Replace called"); OnAssemblyStripped?.Invoke(null, args, null); PostprocessBuildPlayer_CompleteBuild_Proxy(args); } static void Default_PostProcess_Replace(object obj, BuildPostProcessArgs args, out /*BuildProperties*/ object outProperties) { try { // 注意:此函数中途可能会被 Unity throw Exception Default_PostProcess_Proxy(obj, args, out outProperties); } catch(Exception ex) { throw ex; } finally { Debug.Log("PostProcess_Replace called"); OnAssemblyStripped?.Invoke(null, args, null); } } static void ReportBuildResults_Replace(object obj, BeeDriverResult result) { // TODO: 可以在这里把 Library\Bee\artifacts\WinPlayerBuildProgram\ManagedStripped 目录下的文件复制出来 Debug.Log("ReportBuildResults_Replace called"); OnAssemblyStripped?.Invoke(null, default(BuildPostProcessArgs), result); ReportBuildResults_Proxy(obj, result); } static bool StripAssembliesTo_Replace(string outputFolder, out string output, out string error, IEnumerable linkXmlFiles, /*UnityLinkerRunInformation*/ object runInformation) { bool ret = StripAssembliesTo_Proxy(outputFolder, out output, out error, linkXmlFiles, runInformation); // TODO: 可以在这里把 Temp\StagingArea\Data\Managed\tempStrip 目录下的文件复制出来 Debug.Log("StripAssembliesTo_Replace called"); OnAssemblyStripped?.Invoke(outputFolder, default(BuildPostProcessArgs), null); return ret; } #region Proxy Methods [MethodImpl(MethodImplOptions.NoOptimization)] static void PostprocessBuildPlayer_CompleteBuild_Proxy(BuildPostProcessArgs args) { Debug.Log("dummy code" + 200); Debug.Log(args.companyName); } [MethodImpl(MethodImplOptions.NoOptimization)] static void Default_PostProcess_Proxy(object obj, BuildPostProcessArgs args, out /*BuildProperties*/ object outProperties) { Debug.Log("dummy code" + 100); outProperties = null; } [MethodImpl(MethodImplOptions.NoOptimization)] static void ReportBuildResults_Proxy(object obj, /*BeeDriverResult*/ object result) { // dummy code Debug.Log("something" + obj.ToString() + result.ToString() + 2); } [MethodImpl(MethodImplOptions.NoOptimization)] static bool StripAssembliesTo_Proxy(string outputFolder, out string output, out string error, IEnumerable linkXmlFiles, /*UnityLinkerRunInformation*/ object runInformation) { Debug.Log("StripAssembliesTo_Proxy called"); output = null; error = null; return true; } #endregion } } #endif