NLDClient-yudde/ProjectNLD/Assets/Editor/Common/BuildLauncherInEditor.cs

361 lines
14 KiB
C#
Raw Normal View History

2024-11-21 18:56:50 +08:00
using System;
using System.Collections.Generic;
using System.IO;
2025-09-04 14:41:40 +08:00
using System.Reflection;
2024-11-21 18:56:50 +08:00
using AutoBuild.Helper;
using HybridCLR.Editor;
using HybridCLR.Editor.Commands;
using HybridCLR.Editor.Installer;
2025-09-04 14:41:40 +08:00
using HybridCLR.Editor.Link;
using HybridCLR.Editor.Meta;
using Obfuz;
using Obfuz.Settings;
2025-10-17 13:12:28 +08:00
using Obfuz.Unity;
2025-09-04 14:41:40 +08:00
using Obfuz4HybridCLR;
2024-11-21 18:56:50 +08:00
using PhxhSDK.AOT.VersionUpdate;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
/// <summary>
/// 编辑器下打包
/// </summary>
class BuildLauncher
{
private const string HybirdCLRGenerateDir = "/HybridCLRGenerate";
private const string HybirdCLRGenerateLinkPath = "Assets/HybridCLRGenerate/link.xml";
private const string GameLauncherSceneName = "Assets/Scenes/GameLauncher.unity";
private static bool enableHotUpdate;
/// <summary>
/// 开启热更
/// </summary>
public static void SetEnableHotUpdate(bool isEnable)
{
Debug.Log($"是否开启热更新:{isEnable}");
var gameLauncherScene = EditorSceneManager.OpenScene(GameLauncherSceneName, OpenSceneMode.Additive);
if (!gameLauncherScene.IsValid())
{
Debug.LogError($"无法加载场景{GameLauncherSceneName}");
return;
}
var gameLauncher = UnityEngine.Object.FindObjectOfType<GameLauncher>();
if (gameLauncher == null)
{
Debug.LogError("找不到GameLauncher");
return;
}
gameLauncher.enableHotUpdate = isEnable;
EditorSceneManager.MarkSceneDirty(gameLauncherScene);
EditorSceneManager.SaveScene(gameLauncherScene);
EditorSceneManager.CloseScene(gameLauncherScene, false);
HybridCLR.Editor.SettingsUtil.Enable = isEnable;
if (!isEnable)
{
//删除HybirdCLR生成的link文件
AssetDatabase.DeleteAsset(HybirdCLRGenerateLinkPath);
}
}
/// <summary>
/// 构建热更
/// </summary>
public static void BuildHotUpdateDlls()
{
var controller = new InstallerController();
bool isObfuzEnabled = ObfuzSettings.Instance.buildPipelineSettings.enable;
// 非混淆构建时强制重新安装 HybridCLR
// 混淆构建的 GeneratePolymorphicCodes() 会修改 LocalIl2CppData/hybridclr/metadata/PolymorphicDefs.h
// 将 kFormatVariantVersion 写为随机非零值并持久化到磁盘。
// 若非混淆构建不重装,该文件残留,导致编译出的 APK native 库要求 polymorphic 格式 DLL
// 而实际装载的是标准 DLL运行时抛出 BadImageFormatException: LoadImageErrorCode:8 (UNMATCH_FORMAT_VARIANT)。
bool needInstall = !controller.HasInstalledHybridCLR()
|| controller.InstalledLibil2cppVersion != controller.PackageVersion
|| !isObfuzEnabled;
if (needInstall)
{
Debug.Log($"[BuildHotUpdateDlls] Reinstalling HybridCLR: installed='{controller.InstalledLibil2cppVersion}' package='{controller.PackageVersion}' isObfuzEnabled={isObfuzEnabled}");
2024-11-21 18:56:50 +08:00
controller.InstallDefaultHybridCLR();
}
2025-09-04 14:41:40 +08:00
2024-11-21 18:56:50 +08:00
BuildUtils.SetFileReadable(Application.dataPath + HybirdCLRGenerateDir);
2025-09-04 14:41:40 +08:00
// 清空 HybridCLRData/HotUpdateDlls/ 源目录,防止残留上次构建(混淆/非混淆)的 DLL 污染本次产物
var hotUpdateDllSourceDir = SettingsUtil.GetHotUpdateDllsOutputDirByTarget(EditorUserBuildSettings.activeBuildTarget);
if (Directory.Exists(hotUpdateDllSourceDir))
{
Directory.Delete(hotUpdateDllSourceDir, true);
Debug.Log($"[BuildHotUpdateDlls] Cleared hotupdate dll source dir: {hotUpdateDllSourceDir}");
}
2025-10-20 16:14:01 +08:00
if (ObfuzSettings.Instance.buildPipelineSettings.enable)
{
ObfuzMenu.GenerateEncryptionVM();
ObfuzMenu.SaveSecretFile();
2025-10-17 13:12:28 +08:00
var kedrType = Type.GetType("KedrExtensionMenu, Assembly-CSharp-Editor");
if (kedrType != null)
{
var method = kedrType.GetMethod("GenerateAll",
BindingFlags.Public | BindingFlags.Static);
method?.Invoke(null, null);
}
else
{
Debug.LogWarning("[Obfuz] KedrExtensionMenu not found, falling back to PrebuildCommandExt");
PrebuildCommandExt.GenerateAll();
}
2026-03-13 16:06:07 +08:00
HotUpadeEditorHelper.CopyObfuscatedDllToTarget();
2025-10-20 16:14:01 +08:00
}
else
{
PrebuildCommand.GenerateAll();
2026-03-13 16:06:07 +08:00
HotUpadeEditorHelper.CopyHotUpdateDll();
2025-10-20 16:14:01 +08:00
}
2025-10-17 13:12:28 +08:00
2024-11-21 18:56:50 +08:00
HotUpadeEditorHelper.CopyMetaDataDll();
if (ObfuzSettings.Instance.polymorphicDllSettings.enable)
{
HotUpadeEditorHelper.ConvertOriginalDllToPolymorphicDll();
}
2024-11-21 18:56:50 +08:00
}
/// <summary>
/// 打包面板初始化
/// </summary>
public static void Init(BuildTarget buildTarget,
string workSpace,
string appVersion,
string profileName,
bool developmentBuild,
bool hotUpdate)
{
EditorUserBuildSettings.development = developmentBuild;
YooAssetBuildBase.BuildTargetPlatform = buildTarget;
YooAssetBuildBase.profileName = profileName;
YooAssetBuildBase.JudgmentPlatform(buildTarget.ToString());
YooAssetBuildBase.workSpace = string.IsNullOrEmpty(workSpace) ? "WorkSpace" : workSpace;
PlayerSettings.bundleVersion = appVersion;
YooAssetBuildBase.appVersion = appVersion;
enableHotUpdate = hotUpdate;
if (profileName.Equals("AllLocal"))
{
List<string> appendDefineList = new() { "AllLocal" };
var currentTargetGroup = BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget);
var oldDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(currentTargetGroup);
BatchBuild._oldDefines = oldDefines;
var newDefineList = new List<string>();
newDefineList.AddRange(oldDefines.Split(';'));
for (var i = 0; i < newDefineList.Count; i++)
{
var define = newDefineList[i];
if (string.IsNullOrEmpty(define))
continue;
if (appendDefineList.Contains(define))
appendDefineList.Remove(define);
}
newDefineList.AddRange(appendDefineList);
PlayerSettings.SetScriptingDefineSymbolsForGroup(currentTargetGroup, string.Join(";", newDefineList));
}
}
/// <summary>
/// 编辑器下构建资源
/// </summary>
public static void BuildResource()
{
UpdateLocalInfo info = new()
{
workSpace = YooAssetBuildBase.workSpace,
2025-05-26 18:25:17 +08:00
accessKeyId = YooAssetBuildBase.appConfigAccessKeyId,
accessKeySecret = YooAssetBuildBase.appConfigAccessKeySecret,
bucketName = YooAssetBuildBase.appConfigBucketName,
configOriginalUrl = YooAssetBuildBase.appConfigURL,
2025-06-11 16:12:05 +08:00
//httpUrl = YooAssetBuildBase.httpURL,
2025-05-26 18:25:17 +08:00
httpAccessKey = YooAssetBuildBase.httpAccessKey,
httpKey = YooAssetBuildBase.httpKey,
version = YooAssetBuildBase.appVersion,
2025-01-07 19:44:51 +08:00
isDev = YooAssetBuildBase.isDev,
2025-08-22 13:15:44 +08:00
isOversea = YooAssetBuildBase.isOversea,
2025-05-13 15:27:38 +08:00
buildTicks = DateTime.Now.Ticks,
buildCode = BatchBuild.GetBundleVersionCode(),
};
2024-11-21 18:56:50 +08:00
PackDataInst.CreateResourceJson(info);
BuildTargetGroup currentTargetGroup = BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget);
string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(currentTargetGroup);
#if DEVELOPMENT_BUILD || DEBUG
2025-05-13 15:27:38 +08:00
ExtBuildInfoHelper.CreateFirstExtBuildInfo(info.buildTicks, info.workSpace, info.version, info.buildCode, true, defines);
#else
ExtBuildInfoHelper.CreateFirstExtBuildInfo(info.buildTicks, info.workSpace, info.version, false, defines);
#endif
2024-11-21 18:56:50 +08:00
SetEnableHotUpdate(enableHotUpdate);
if (enableHotUpdate)
{
BuildHotUpdateDlls();
}
YooAssetBuildBase.BuildResourceInEditor();
}
/// <summary>
/// 编辑器下构建资源和Player
/// </summary>
public static void BuildResourceAndPlayer()
{
UpdateLocalInfo info = new()
2024-11-21 18:56:50 +08:00
{
workSpace = YooAssetBuildBase.workSpace,
2025-05-26 18:25:17 +08:00
accessKeyId = YooAssetBuildBase.appConfigAccessKeyId,
accessKeySecret = YooAssetBuildBase.appConfigAccessKeySecret,
bucketName = YooAssetBuildBase.appConfigBucketName,
configOriginalUrl = YooAssetBuildBase.appConfigURL,
2025-06-11 16:12:05 +08:00
//httpUrl = YooAssetBuildBase.httpURL,
2025-05-26 18:25:17 +08:00
httpAccessKey = YooAssetBuildBase.httpAccessKey,
httpKey = YooAssetBuildBase.httpKey,
2024-11-21 18:56:50 +08:00
version = YooAssetBuildBase.appVersion,
2025-01-07 19:44:51 +08:00
isDev = YooAssetBuildBase.isDev,
2025-08-22 13:15:44 +08:00
isOversea = YooAssetBuildBase.isOversea,
2025-05-13 15:27:38 +08:00
buildTicks = DateTime.Now.Ticks,
buildCode = BatchBuild.GetBundleVersionCode(),
2024-11-21 18:56:50 +08:00
};
PackDataInst.CreateResourceJson(info);
BuildTargetGroup currentTargetGroup = BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget);
string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(currentTargetGroup);
#if DEVELOPMENT_BUILD || DEBUG
2025-05-13 15:27:38 +08:00
ExtBuildInfoHelper.CreateFirstExtBuildInfo(info.buildTicks, info.workSpace, info.version, info.buildCode, true, defines);
#else
ExtBuildInfoHelper.CreateFirstExtBuildInfo(info.buildTicks, info.workSpace, info.version, false, defines);
#endif
2024-11-21 18:56:50 +08:00
SetEnableHotUpdate(enableHotUpdate);
if (enableHotUpdate)
{
BuildHotUpdateDlls();
}
YooAssetBuildBase.BuildContentAndPlayerInEditor();
ExtBuildInfoHelper.CreateVertifyBuildInfo(info.workSpace, info.version);
if (!string.IsNullOrEmpty(BatchBuild._oldDefines))
BatchBuild._RevertScriptDefines();
2024-12-30 13:27:51 +08:00
var aotDllStorePath = BatchBuild.GetAotDllStorePath(info.workSpace, info.version);
2024-11-21 18:56:50 +08:00
var aotDllPath = SettingsUtil.GetAssembliesPostIl2CppStripDir(EditorUserBuildSettings.activeBuildTarget);
DirectoryInfo dir = new(aotDllPath);
if (Directory.Exists(aotDllStorePath))
Directory.Delete(aotDllStorePath, true);
Directory.CreateDirectory(aotDllStorePath);
FileInfo[] files = dir.GetFiles();
foreach (FileInfo file in files)
{
file.CopyTo(Path.Combine(aotDllStorePath, file.Name), false);
}
}
/// <summary>
/// 只构建Player
/// </summary>
public static void BuildPlayer()
{
YooAssetBuildBase.BuildPlayerInEditor();
}
/// <summary>
/// 编辑器下热更
/// </summary>
public static void UpdatePreviousBuild(string workSpace, string version, BuildTarget buildTarget)
{
ExtBuildInfoHelper.VertifyExitBuildInfo(YooAssetBuildBase.workSpace, YooAssetBuildBase.appVersion);
Debug.Log("开始检查AOT版本");
2024-12-30 13:27:51 +08:00
if (BatchBuild.CheckAotOutDate(YooAssetBuildBase.workSpace, YooAssetBuildBase.appVersion))
2024-11-21 18:56:50 +08:00
{
Debug.Log("AOT版本检查通过");
BuildHotUpdateDlls();
}
else
{
Debug.LogError("AOT版本不匹配请重新打AOT包");
}
BuildTargetGroup currentTargetGroup = BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget);
string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(currentTargetGroup);
2024-11-21 18:56:50 +08:00
// 写入打包信息到Yoo_Build_Cache
#if DEVELOPMENT_BUILD || DEBUG
ExtBuildInfoHelper.UpdateExtBuildInfo(YooAssetBuildBase.workSpace, YooAssetBuildBase.appVersion, true, defines);
#else
ExtBuildInfoHelper.UpdateExtBuildInfo(YooAssetBuildBase.workSpace, YooAssetBuildBase.appVersion, false, defines);
#endif
2024-11-21 18:56:50 +08:00
YooAssetBuildBase.BuildOnlyResUpdate();
ExtBuildInfoHelper.CreateVertifyBuildInfo(YooAssetBuildBase.workSpace, YooAssetBuildBase.appVersion);
YooAssetBuildBase.UploadToServerYooAsset(workSpace, version, buildTarget);
/*try
{
}
catch (Exception e)
{
DebugUtil.LogError($"[Build Exception]:{e.Message} \r\n {e.StackTrace}");
throw;
}*/
}
public static void UploadToServer(string workSpace, string version, BuildTarget buildTarget)
{
YooAssetBuildBase.UploadToServerYooAsset(workSpace, version, buildTarget);
}
2025-09-04 14:41:40 +08:00
public static void GenerateObfuzLinkXml()
{
//CompileDllCommand.CompileDllActiveBuildTarget();
PrebuildCommandExt.CompileAndObfuscateDll();
BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
ObfuzSettings obfuzSettings = ObfuzSettings.Instance;
List<string> assemblySearchDirs = new()
{
SettingsUtil.GetHotUpdateDllsOutputDirByTarget(target),
};
ObfuscatorBuilder builder = ObfuscatorBuilder.FromObfuzSettings(obfuzSettings, target, true);
builder.InsertTopPriorityAssemblySearchPaths(assemblySearchDirs);
Obfuscator obfuz = builder.Build();
obfuz.Run();
List<string> hotfixAssemblies = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved;
var analyzer = new Analyzer(new PathAssemblyResolver(builder.CoreSettingsFacade.obfuscatedAssemblyOutputPath));
var refTypes = analyzer.CollectRefs(hotfixAssemblies);
// HyridCLR中 LinkXmlWritter不是public的在其他程序集无法访问只能通过反射操作
var linkXmlWriter = typeof(SettingsUtil).Assembly.GetType("HybridCLR.Editor.Link.LinkXmlWriter");
var writeMethod = linkXmlWriter.GetMethod("Write", BindingFlags.Public | BindingFlags.Instance);
var instance = Activator.CreateInstance(linkXmlWriter);
string linkXmlOutputPath = $"{Application.dataPath}/Obfuz/link.xml";
writeMethod.Invoke(instance, new object[] { linkXmlOutputPath, refTypes });
Debug.Log($"[GenerateLinkXmlForObfuscatedAssembly] output:{linkXmlOutputPath}");
AssetDatabase.Refresh();
}
2024-11-21 18:56:50 +08:00
}