#if UNITY_2018_1_OR_NEWER && !UNITY_2020_1_OR_NEWER using System.Collections; using System.Collections.Generic; using UnityEditor; using UnityEditor.Build; using UnityEditor.Build.Reporting; using UnityEngine; using UnityEngine.SceneManagement; using System.Linq; using System.IO; using System; using UnityEditor.UnityLinker; using System.Reflection; using UnityEditor.Il2Cpp; using HybridCLR.Editor.GlobalManagers; #if UNITY_ANDROID using UnityEditor.Android; #endif namespace HybridCLR { public class BuildProcessor_2019 : IPreprocessBuildWithReport, IPostprocessBuildWithReport #if UNITY_ANDROID , IPostGenerateGradleAndroidProject #endif , IProcessSceneWithReport, IFilterBuildAssemblies, IPostBuildPlayerScriptDLLs, IUnityLinkerProcessor, IIl2CppProcessor { /// /// 需要在Prefab上挂脚本的热更dll名称列表,不需要挂到Prefab上的脚本可以不放在这里 /// 但放在这里的dll即使勾选了 AnyPlatform 也会在打包过程中被排除 /// /// 另外请务必注意!: 需要挂脚本的dll的名字最好别改,因为这个列表无法热更(上线后删除或添加某些非挂脚本dll没问题) /// static List monoDllNames = new List() { "HotFix.dll"}; static MethodInfo s_BuildReport_AddMessage; int IOrderedCallback.callbackOrder => 0; static BuildProcessor_2019() { s_BuildReport_AddMessage = typeof(BuildReport).GetMethod("AddMessage", BindingFlags.Instance | BindingFlags.NonPublic); } void IPreprocessBuildWithReport.OnPreprocessBuild(BuildReport report) { if (!Application.isBatchMode && !EditorUtility.DisplayDialog("确认", "建议 Build 之前先打包 AssetBundle\r\n是否继续?", "继续", "取消")) { s_BuildReport_AddMessage.Invoke(report, new object[] { LogType.Exception, "用户取消", "BuildFailedException" }); return; } } string[] IFilterBuildAssemblies.OnFilterAssemblies(BuildOptions buildOptions, string[] assemblies) { // 将热更dll从打包列表中移除 List newNames = new List(assemblies.Length); foreach(string assembly in assemblies) { bool found = false; foreach(string removeName in monoDllNames) { if(assembly.EndsWith(removeName, StringComparison.OrdinalIgnoreCase)) { found = true; break; } } if(!found) newNames.Add(assembly); } return newNames.ToArray(); } [Serializable] public class ScriptingAssemblies { public List names; public List types; } void IPostprocessBuildWithReport.OnPostprocessBuild(BuildReport report) { AddBackHotFixAssembliesTo_BinFile(report, null); } #if UNITY_ANDROID void IPostGenerateGradleAndroidProject.OnPostGenerateGradleAndroidProject(string path) { // 由于 Android 平台在 OnPostprocessBuild 调用时已经生成完 apk 文件,因此需要提前调用 AddBackHotFixAssembliesTo_BinFile(null, path); } #endif private void AddBackHotFixAssembliesTo_BinFile(BuildReport report, string path) { /* * Unity2019 中 dll 加载列表存储在 globalgamemanagers 文件中,此列表在游戏启动时自动加载, * 不在此列表中的dll在资源反序列化时无法被找到其类型 * 因此 OnFilterAssemblies 中移除的条目需要再加回来 */ #if UNITY_ANDROID string[] binFiles = new string[] { "Temp/gradleOut/unityLibrary/src/main/assets/bin/Data/globalgamemanagers" }; // report.files 不包含 Temp/gradleOut 等目录 #else // 直接出包和输出vs工程时路径不同,report.summary.outputPath 记录的是前者路径 string[] binFiles = Directory.GetFiles(Path.GetDirectoryName(report.summary.outputPath), "globalgamemanagers", SearchOption.AllDirectories); #endif if (binFiles.Length == 0) { Debug.LogError("can not find file ScriptingAssemblies.json"); return; } foreach (string binPath in binFiles) { var binFile = new UnityBinFile(); binFile.LoadFromFile(binPath); ScriptsData scriptsData = binFile.scriptsData; foreach (string name in monoDllNames) { if(!scriptsData.dllNames.Contains(name)) { scriptsData.dllNames.Add(name); scriptsData.dllTypes.Add(16); // user dll type } } binFile.scriptsData = scriptsData; binFile.RebuildAndFlushToFile(binPath); } } void IProcessSceneWithReport.OnProcessScene(Scene scene, BuildReport report) { } void IPostBuildPlayerScriptDLLs.OnPostBuildPlayerScriptDLLs(BuildReport report) { } string IUnityLinkerProcessor.GenerateAdditionalLinkXmlFile(BuildReport report, UnityLinkerBuildPipelineData data) { return String.Empty; } void IUnityLinkerProcessor.OnBeforeRun(BuildReport report, UnityLinkerBuildPipelineData data) { } void IUnityLinkerProcessor.OnAfterRun(BuildReport report, UnityLinkerBuildPipelineData data) { } void IIl2CppProcessor.OnBeforeConvertRun(BuildReport report, Il2CppBuildPipelineData data) { } #if UNITY_IOS // hook UnityEditor.BuildCompletionEventsHandler.ReportPostBuildCompletionInfo() ? 因为没有 mac 打包平台因此不清楚 #endif } } #endif