2025-06-11 16:12:05 +08:00
|
|
|
|
using AutoBuild.Helper;
|
|
|
|
|
|
using Cysharp.Threading.Tasks;
|
|
|
|
|
|
using HybridCLR.Editor;
|
2023-10-19 15:00:19 +08:00
|
|
|
|
using HybridCLR.Editor.Commands;
|
2025-06-11 16:12:05 +08:00
|
|
|
|
using HybridCLR.Editor.HotUpdate;
|
2026-01-13 13:20:29 +08:00
|
|
|
|
using PhxhSDK;
|
2024-02-26 12:58:19 +08:00
|
|
|
|
using PhxhSDK.AOT.VersionUpdate;
|
2025-06-11 16:12:05 +08:00
|
|
|
|
using System;
|
2024-05-15 17:15:25 +08:00
|
|
|
|
using System.Collections.Generic;
|
2024-08-21 17:45:27 +08:00
|
|
|
|
using System.IO;
|
2026-03-05 18:53:46 +08:00
|
|
|
|
using System.Linq;
|
2026-03-18 19:05:23 +08:00
|
|
|
|
using System.Text;
|
2025-10-22 18:09:39 +08:00
|
|
|
|
using Obfuz.Settings;
|
2025-06-11 16:12:05 +08:00
|
|
|
|
using UnityEditor;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using BuildTarget = UnityEditor.BuildTarget;
|
|
|
|
|
|
using Debug = UnityEngine.Debug;
|
2025-05-22 19:00:34 +08:00
|
|
|
|
using Directory = System.IO.Directory;
|
2025-06-23 13:44:52 +08:00
|
|
|
|
using YamlDotNet.Serialization;
|
2025-09-04 14:41:40 +08:00
|
|
|
|
using Obfuz4HybridCLR;
|
2023-10-19 15:00:19 +08:00
|
|
|
|
|
2024-05-15 17:15:25 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Jenkins打包
|
|
|
|
|
|
/// </summary>
|
2023-10-19 15:00:19 +08:00
|
|
|
|
internal class BatchBuild
|
|
|
|
|
|
{
|
2024-04-12 18:06:06 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 批处理更新设置
|
|
|
|
|
|
/// jenkins打包新包时使用该方法
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static void ApplyPlayerSetting()
|
|
|
|
|
|
{
|
2026-03-21 12:15:05 +08:00
|
|
|
|
InitChannelConfigFromYaml();
|
2024-05-15 17:15:25 +08:00
|
|
|
|
YooAssetBuildBase.Init();
|
2023-10-19 15:00:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-11-19 14:12:28 +08:00
|
|
|
|
public static string _oldDefines;
|
2024-05-15 17:15:25 +08:00
|
|
|
|
|
2024-09-26 16:35:41 +08:00
|
|
|
|
/// <summary>
|
2024-09-27 17:11:55 +08:00
|
|
|
|
/// 只在DEBUG下有
|
2024-09-26 16:35:41 +08:00
|
|
|
|
/// </summary>
|
2024-09-27 17:11:55 +08:00
|
|
|
|
private const string DEBUG = "DEBUG";
|
2025-05-13 15:27:38 +08:00
|
|
|
|
|
2025-06-12 14:17:31 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// dev上传地址
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private const string Dev_PostUrl = "http://dev_openapi.kedrgame.com/api/v1/";
|
2025-06-23 13:44:52 +08:00
|
|
|
|
|
2025-06-12 14:17:31 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Pre上传地址
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private const string Pre_PostUrl = "http://pre_openapi.kedrgame.com/api/v1/";
|
2025-06-23 13:44:52 +08:00
|
|
|
|
|
2025-08-22 13:15:44 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 海外Release上传地址
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private const string Oversea_Release_PostUrl = "http://intl_openapi.kedrgame.com/api/v1/";
|
|
|
|
|
|
|
2025-06-12 14:17:31 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Release上传地址
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private const string Release_PostUrl = "http://openapi.kedrgame.com/api/v1/";
|
2026-03-18 19:05:23 +08:00
|
|
|
|
|
|
|
|
|
|
private static void WriteEncryptedJsonResource(string resourceFileNameWithoutExtension, string json)
|
|
|
|
|
|
{
|
|
|
|
|
|
var resourcesPath = "Assets/Resources";
|
|
|
|
|
|
var jsonPath = Path.Combine(resourcesPath, resourceFileNameWithoutExtension + ".json");
|
|
|
|
|
|
var bytesPath = Path.Combine(resourcesPath, resourceFileNameWithoutExtension + ".bytes");
|
|
|
|
|
|
|
|
|
|
|
|
if (!Directory.Exists(resourcesPath))
|
|
|
|
|
|
{
|
|
|
|
|
|
Directory.CreateDirectory(resourcesPath);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (File.Exists(jsonPath))
|
|
|
|
|
|
{
|
|
|
|
|
|
File.Delete(jsonPath);
|
|
|
|
|
|
var metaPath = jsonPath + ".meta";
|
|
|
|
|
|
if (File.Exists(metaPath))
|
|
|
|
|
|
{
|
|
|
|
|
|
File.Delete(metaPath);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var encryptedBytes = LocalInfoEncrypt.Encrypt(Encoding.UTF8.GetBytes(json));
|
|
|
|
|
|
File.WriteAllBytes(bytesPath, encryptedBytes);
|
|
|
|
|
|
}
|
2025-06-24 13:11:59 +08:00
|
|
|
|
|
2024-11-19 14:12:28 +08:00
|
|
|
|
public static void _RevertScriptDefines()
|
2024-02-26 17:54:26 +08:00
|
|
|
|
{
|
|
|
|
|
|
var currentTargetGroup = BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget);
|
|
|
|
|
|
PlayerSettings.SetScriptingDefineSymbolsForGroup(currentTargetGroup, _oldDefines);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2024-05-15 17:15:25 +08:00
|
|
|
|
/// 批处理构建Resources和Player
|
2024-02-26 17:54:26 +08:00
|
|
|
|
/// jenkins打包新包时使用该方法
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static void BuildContentAndPlayer()
|
2025-06-23 13:57:08 +08:00
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
InitChannelConfigFromYaml();
|
|
|
|
|
|
|
|
|
|
|
|
bool enableHotUpdate = YooAssetBuildBase.Init();
|
|
|
|
|
|
string bundleVersionCode = GetBundleVersionCode();
|
|
|
|
|
|
|
|
|
|
|
|
// 写入版本信息到Resources/LocalInfo.json
|
|
|
|
|
|
UpdateLocalInfo info = new()
|
|
|
|
|
|
{
|
|
|
|
|
|
workSpace = YooAssetBuildBase.workSpace,
|
|
|
|
|
|
accessKeyId = YooAssetBuildBase.appConfigAccessKeyId,
|
|
|
|
|
|
accessKeySecret = YooAssetBuildBase.appConfigAccessKeySecret,
|
|
|
|
|
|
bucketName = YooAssetBuildBase.appConfigBucketName,
|
|
|
|
|
|
configOriginalUrl = YooAssetBuildBase.appConfigURL,
|
|
|
|
|
|
//httpUrl = YooAssetBuildBase.httpURL,
|
|
|
|
|
|
httpAccessKey = YooAssetBuildBase.httpAccessKey,
|
2025-05-26 18:25:17 +08:00
|
|
|
|
httpKey = YooAssetBuildBase.httpKey,
|
2024-09-25 13:51:04 +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 = bundleVersionCode,
|
2025-10-16 13:34:26 +08:00
|
|
|
|
pathRoot = "Build",
|
2026-03-05 13:27:06 +08:00
|
|
|
|
phxhBiAccessKeyId = YooAssetBuildBase.phxhBiAccessKeyId,
|
|
|
|
|
|
phxhBiScretKey = YooAssetBuildBase.phxhBiScretKey,
|
2026-03-05 15:22:58 +08:00
|
|
|
|
wxPayAppId = YooAssetBuildBase.wxPayAppId,
|
2026-03-19 12:44:23 +08:00
|
|
|
|
thinkingDataAppId = YooAssetBuildBase.thinkingDataAppId,
|
|
|
|
|
|
thinkingDataServerUrl = YooAssetBuildBase.thinkingDataServerUrl,
|
2024-09-25 13:51:04 +08:00
|
|
|
|
};
|
2024-08-12 12:52:59 +08:00
|
|
|
|
PackDataInst.CreateResourceJson(info);
|
|
|
|
|
|
|
2025-05-13 15:27:38 +08:00
|
|
|
|
BuildTargetGroup currentTargetGroup =
|
|
|
|
|
|
BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget);
|
2024-12-19 13:05:50 +08:00
|
|
|
|
string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(currentTargetGroup);
|
|
|
|
|
|
|
2024-08-12 12:52:59 +08:00
|
|
|
|
// 写入打包信息到Yoo_Build_Cache
|
2025-10-16 12:35:37 +08:00
|
|
|
|
bool isDebugBuild = false;
|
2024-12-19 13:05:50 +08:00
|
|
|
|
#if DEVELOPMENT_BUILD || DEBUG
|
2025-10-16 12:35:37 +08:00
|
|
|
|
isDebugBuild = true;
|
2024-12-19 13:05:50 +08:00
|
|
|
|
#endif
|
2025-10-16 12:35:37 +08:00
|
|
|
|
ExtBuildInfoHelper.CreateFirstExtBuildInfo(info.buildTicks, info.workSpace, info.version, info.buildCode,
|
|
|
|
|
|
isDebugBuild, defines);
|
2024-05-15 17:15:25 +08:00
|
|
|
|
|
2024-01-24 13:18:47 +08:00
|
|
|
|
BuildLauncher.SetEnableHotUpdate(enableHotUpdate);
|
|
|
|
|
|
if (enableHotUpdate)
|
|
|
|
|
|
BuildLauncher.BuildHotUpdateDlls();
|
|
|
|
|
|
|
2026-03-23 17:59:27 +08:00
|
|
|
|
YooAssetBuildBase.BuildContentAndPlayer();
|
2025-05-13 15:27:38 +08:00
|
|
|
|
|
2025-11-06 15:06:38 +08:00
|
|
|
|
// 写入打包信息到Yoo_Build_Cache
|
|
|
|
|
|
ExtBuildInfoHelper.CreateVertifyBuildInfo(info.workSpace, info.version);
|
|
|
|
|
|
|
2024-01-24 13:18:47 +08:00
|
|
|
|
// 还原宏
|
2024-02-26 17:54:26 +08:00
|
|
|
|
_RevertScriptDefines();
|
2024-08-21 17:45:27 +08:00
|
|
|
|
|
2025-10-22 18:09:39 +08:00
|
|
|
|
// 缓存打包时的文件
|
|
|
|
|
|
_CacheBuildFiles(info);
|
2025-05-22 19:00:34 +08:00
|
|
|
|
|
2025-10-22 13:53:44 +08:00
|
|
|
|
PostLoginKey(info.version); // 上传Aot loginKey
|
2023-11-23 14:41:25 +08:00
|
|
|
|
}
|
2024-01-24 13:18:47 +08:00
|
|
|
|
catch (Exception e)
|
2023-11-27 19:53:34 +08:00
|
|
|
|
{
|
2024-01-24 15:51:08 +08:00
|
|
|
|
//Build Exception用于在日志文件中定位此次打包的异常
|
2024-01-24 13:18:47 +08:00
|
|
|
|
Debug.LogError($"[Build Exception]:{e.Message} \r\n {e.StackTrace}");
|
|
|
|
|
|
throw;
|
2023-11-27 19:53:34 +08:00
|
|
|
|
}
|
2023-10-19 15:00:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-22 18:09:39 +08:00
|
|
|
|
private static void _CacheAotDlls(UpdateLocalInfo info)
|
|
|
|
|
|
{
|
|
|
|
|
|
string aotDllStorePath = GetAotDllStorePath(info.workSpace, info.version);
|
|
|
|
|
|
string 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);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void _CacheObfuzFiles(UpdateLocalInfo info)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 备份 Assets/Obfuz/SymbolObfus 文件夹
|
|
|
|
|
|
// 备份 Library/Obfuz/{buildTarget} 文件夹
|
|
|
|
|
|
var obfuzSymbolPath = Application.dataPath + "/Obfuz/SymbolObfus";
|
|
|
|
|
|
var obfuzBuildPath = Application.dataPath + $"/../Library/Obfuz/{EditorUserBuildSettings.activeBuildTarget}";
|
|
|
|
|
|
var cacheObfuzPath = Application.dataPath + $"/../Yoo_Build_Cache/{info.workSpace}/{info.version}/CacheObfuz";
|
|
|
|
|
|
var cacheObfuzSymbolPath = cacheObfuzPath + "/SymbolObfus";;
|
|
|
|
|
|
var cacheObfuzBuildPath = cacheObfuzPath + $"/{EditorUserBuildSettings.activeBuildTarget}";
|
|
|
|
|
|
if (Directory.Exists(cacheObfuzPath))
|
|
|
|
|
|
Directory.Delete(cacheObfuzPath, true);
|
|
|
|
|
|
Directory.CreateDirectory(cacheObfuzPath);
|
|
|
|
|
|
DirectoryCopyHelper.CopyDirectory(obfuzSymbolPath, cacheObfuzSymbolPath);
|
|
|
|
|
|
DirectoryCopyHelper.CopyDirectory(obfuzBuildPath, cacheObfuzBuildPath);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void _CacheBuildFiles(UpdateLocalInfo info)
|
|
|
|
|
|
{
|
|
|
|
|
|
_CacheAotDlls(info);
|
|
|
|
|
|
|
|
|
|
|
|
if (ObfuzSettings.Instance.buildPipelineSettings.enable)
|
|
|
|
|
|
{
|
|
|
|
|
|
_CacheObfuzFiles(info);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-10-19 15:00:19 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 批处理增量更新资源
|
2024-02-26 12:58:19 +08:00
|
|
|
|
/// jenkins打包增量更新时使用该方法
|
2023-10-19 15:00:19 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static void UpdatePreviousBuild()
|
|
|
|
|
|
{
|
2024-01-24 15:51:08 +08:00
|
|
|
|
try
|
|
|
|
|
|
{
|
2025-11-12 16:23:34 +08:00
|
|
|
|
DebugUtil.Log($"初始化渠道配置:{DateTime.Now}");
|
2025-06-24 13:11:59 +08:00
|
|
|
|
InitChannelConfigFromYaml();
|
2025-11-12 16:23:34 +08:00
|
|
|
|
DebugUtil.Log($"初始化渠道配置完成:{DateTime.Now}");
|
2025-05-13 15:27:38 +08:00
|
|
|
|
|
2024-05-15 17:15:25 +08:00
|
|
|
|
var enableHotUpdate = YooAssetBuildBase.Init();
|
2025-11-12 16:23:34 +08:00
|
|
|
|
DebugUtil.Log($"YooAssetBuildBase初始化设置完成:{DateTime.Now}");
|
2025-05-13 15:27:38 +08:00
|
|
|
|
|
2024-09-02 13:32:23 +08:00
|
|
|
|
ExtBuildInfoHelper.VertifyExitBuildInfo(YooAssetBuildBase.workSpace, YooAssetBuildBase.appVersion);
|
2025-11-12 16:23:34 +08:00
|
|
|
|
DebugUtil.Log($"验证ExBuildInfo完成:{DateTime.Now}");
|
2025-05-13 15:27:38 +08:00
|
|
|
|
|
2026-03-25 19:13:42 +08:00
|
|
|
|
var skipCheck = true;
|
|
|
|
|
|
|
2024-01-24 15:51:08 +08:00
|
|
|
|
if (enableHotUpdate)
|
2024-08-21 19:06:36 +08:00
|
|
|
|
{
|
2026-03-25 19:13:42 +08:00
|
|
|
|
if (skipCheck)
|
2024-08-27 19:32:49 +08:00
|
|
|
|
{
|
2026-03-25 19:13:42 +08:00
|
|
|
|
Debug.Log("跳过检查AOT版本");
|
2024-08-22 14:10:32 +08:00
|
|
|
|
BuildLauncher.BuildHotUpdateDlls();
|
2024-08-27 19:32:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2026-03-25 19:13:42 +08:00
|
|
|
|
Debug.Log("开始检查AOT版本");
|
|
|
|
|
|
DebugUtil.Log($"开始检查AOT Dll:{DateTime.Now}");
|
|
|
|
|
|
if (CheckAotOutDate(YooAssetBuildBase.workSpace, YooAssetBuildBase.appVersion))
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Log("AOT版本检查通过");
|
|
|
|
|
|
DebugUtil.Log($"检查AOT Dll完成:{DateTime.Now}");
|
|
|
|
|
|
BuildLauncher.BuildHotUpdateDlls();
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
DebugUtil.Log($"检查AOT Dll完成:{DateTime.Now}");
|
|
|
|
|
|
Debug.LogError("AOT版本不匹配,请重新打AOT包");
|
|
|
|
|
|
}
|
2024-08-27 19:32:49 +08:00
|
|
|
|
}
|
2026-03-25 19:13:42 +08:00
|
|
|
|
|
2024-08-27 19:32:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Log("未开启热更");
|
2024-08-21 19:06:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-12 16:23:34 +08:00
|
|
|
|
BuildTargetGroup currentTargetGroup = BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget);
|
2024-12-19 13:05:50 +08:00
|
|
|
|
string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(currentTargetGroup);
|
2026-03-26 17:01:12 +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-12-19 13:05:50 +08:00
|
|
|
|
|
2025-11-12 16:23:34 +08:00
|
|
|
|
DebugUtil.Log($"开始打包热更资源:{DateTime.Now}");
|
2025-11-11 15:28:37 +08:00
|
|
|
|
bool result = YooAssetBuildBase.BuildOnlyResUpdate();
|
2025-11-12 16:23:34 +08:00
|
|
|
|
DebugUtil.Log($"打包热更资源完成:{DateTime.Now}");
|
|
|
|
|
|
|
2025-11-11 15:28:37 +08:00
|
|
|
|
_RevertScriptDefines();
|
|
|
|
|
|
|
|
|
|
|
|
if (result)
|
|
|
|
|
|
{
|
2026-03-26 17:01:12 +08:00
|
|
|
|
|
2024-05-15 17:15:25 +08:00
|
|
|
|
|
2025-11-06 15:14:17 +08:00
|
|
|
|
ExtBuildInfoHelper.CreateVertifyBuildInfo(YooAssetBuildBase.workSpace, YooAssetBuildBase.appVersion);
|
2025-11-11 15:28:37 +08:00
|
|
|
|
}
|
2025-11-06 15:14:17 +08:00
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("打包资源失败");
|
|
|
|
|
|
throw new Exception("YooAsset打包资源失败");
|
|
|
|
|
|
}
|
2024-01-24 15:51:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
//Build Exception用于在日志文件中定位此次打包的异常
|
|
|
|
|
|
Debug.LogError($"[Build Exception]:{e.Message} \r\n {e.StackTrace}");
|
|
|
|
|
|
throw;
|
|
|
|
|
|
}
|
2023-10-19 15:00:19 +08:00
|
|
|
|
}
|
2024-08-21 17:45:27 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// jenkins检查AOT裁剪代码
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="version"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2024-12-30 13:27:51 +08:00
|
|
|
|
public static bool CheckAotOutDate(string workSpace, string version)
|
2024-08-21 17:45:27 +08:00
|
|
|
|
{
|
|
|
|
|
|
Debug.Log($"开始检查aot版本:{version}");
|
2024-12-30 13:27:51 +08:00
|
|
|
|
string stripedDllPath = GetAotDllStorePath(workSpace, version);
|
2024-08-21 17:45:27 +08:00
|
|
|
|
// 先编译dll
|
2025-09-04 14:41:40 +08:00
|
|
|
|
// CompileDllCommand.CompileDllActiveBuildTarget();
|
|
|
|
|
|
PrebuildCommandExt.CompileAndObfuscateDll(); // 编译混淆dll
|
2024-08-21 19:06:36 +08:00
|
|
|
|
// 再检查编译出来的dll是否满足以前的Aotdll
|
2025-07-11 15:45:30 +08:00
|
|
|
|
MissingMetadataChecker checker = new(stripedDllPath, SettingsUtil.HotUpdateAssemblyNamesIncludePreserved);
|
2024-08-21 17:45:27 +08:00
|
|
|
|
string hotUpdateDir = SettingsUtil.GetHotUpdateDllsOutputDirByTarget(EditorUserBuildSettings.activeBuildTarget);
|
|
|
|
|
|
foreach (string dll in SettingsUtil.HotUpdateAssemblyFilesExcludePreserved)
|
|
|
|
|
|
{
|
|
|
|
|
|
string dllPath = $"{hotUpdateDir}/{dll}";
|
|
|
|
|
|
bool notAnyMissing = checker.Check(dllPath);
|
|
|
|
|
|
if (!notAnyMissing)
|
2025-07-11 13:11:38 +08:00
|
|
|
|
throw new Exception($"AOT缺失Dll({dllPath}),请重新打AOT包");
|
2024-08-21 17:45:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取缓存的AOT Dll路径
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="version"></param>
|
2024-12-30 13:27:51 +08:00
|
|
|
|
public static string GetAotDllStorePath(string workSpace, string version)
|
2024-08-21 17:45:27 +08:00
|
|
|
|
{
|
2025-01-10 14:36:17 +08:00
|
|
|
|
return Application.dataPath + $"/../Yoo_Build_Cache/{workSpace}/{version}/CacheAOTDll";
|
2024-08-21 17:45:27 +08:00
|
|
|
|
}
|
2025-05-13 15:27:38 +08:00
|
|
|
|
|
|
|
|
|
|
public static string GetBundleVersionCode()
|
|
|
|
|
|
{
|
|
|
|
|
|
#if UNITY_IOS
|
|
|
|
|
|
return PlayerSettings.iOS.buildNumber;
|
|
|
|
|
|
#elif UNITY_ANDROID
|
|
|
|
|
|
return PlayerSettings.Android.bundleVersionCode.ToString();
|
|
|
|
|
|
#else
|
|
|
|
|
|
return "";
|
|
|
|
|
|
#endif
|
|
|
|
|
|
}
|
2025-05-22 15:49:25 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 上传登录key
|
|
|
|
|
|
/// </summary>
|
2025-10-22 13:53:44 +08:00
|
|
|
|
public static void PostLoginKey(string version)
|
2025-05-22 15:49:25 +08:00
|
|
|
|
{
|
2026-01-13 13:20:29 +08:00
|
|
|
|
string loginKey = HashUtils.MD5(version);
|
2025-05-22 15:49:25 +08:00
|
|
|
|
|
2026-03-05 18:53:46 +08:00
|
|
|
|
// 服务端签名原文包含 platform="",按字母升序排列
|
2025-05-22 15:49:25 +08:00
|
|
|
|
Dictionary<string, string> headData = PostHeader.PostHeaderInfo(new Dictionary<string, string>
|
2025-05-22 19:00:34 +08:00
|
|
|
|
{
|
2025-10-22 13:53:44 +08:00
|
|
|
|
{ "plaintext", version },
|
2026-03-05 18:53:46 +08:00
|
|
|
|
{ "platform", "" },
|
2025-05-22 19:00:34 +08:00
|
|
|
|
{ "tag", loginKey },
|
|
|
|
|
|
{ "timestamp", DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString() }
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
LoginKeyData loginKeyData = new()
|
|
|
|
|
|
{
|
2025-10-22 13:53:44 +08:00
|
|
|
|
plaintext = version,
|
2025-05-22 19:00:34 +08:00
|
|
|
|
tag = loginKey,
|
|
|
|
|
|
};
|
2025-05-22 15:49:25 +08:00
|
|
|
|
|
2025-05-22 17:00:48 +08:00
|
|
|
|
try
|
|
|
|
|
|
{
|
2025-06-11 16:12:05 +08:00
|
|
|
|
if (PackDataInst.Inst.localInfo.isDev)
|
2025-06-12 14:53:22 +08:00
|
|
|
|
{
|
2025-08-22 13:15:44 +08:00
|
|
|
|
if (PackDataInst.Inst.localInfo.isOversea)
|
|
|
|
|
|
HttpHelper.PostAsync($"{Oversea_Release_PostUrl}version", loginKeyData, headData).Forget(); // 暂时海外dev也使用Release
|
|
|
|
|
|
else
|
|
|
|
|
|
HttpHelper.PostAsync($"{Dev_PostUrl}version", loginKeyData, headData).Forget();
|
2025-06-12 14:53:22 +08:00
|
|
|
|
}
|
2025-06-11 16:12:05 +08:00
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-08-22 13:15:44 +08:00
|
|
|
|
if (PackDataInst.Inst.localInfo.isOversea)
|
|
|
|
|
|
HttpHelper.PostAsync($"{Oversea_Release_PostUrl}version", loginKeyData, headData).Forget();
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
HttpHelper.PostAsync($"{Pre_PostUrl}version", loginKeyData, headData).Forget();
|
|
|
|
|
|
HttpHelper.PostAsync($"{Release_PostUrl}version", loginKeyData, headData).Forget();
|
|
|
|
|
|
}
|
2025-06-11 16:12:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
2025-05-22 17:00:48 +08:00
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"[PostLoginKey Exception]:{e.Message} \r\n {e.StackTrace}");
|
|
|
|
|
|
throw;
|
|
|
|
|
|
}
|
2025-05-22 15:49:25 +08:00
|
|
|
|
}
|
2025-05-22 16:52:45 +08:00
|
|
|
|
|
2025-06-12 19:21:16 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 自动发布debug loginKey
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static void PostDebugSendKey()
|
|
|
|
|
|
{
|
2026-03-05 18:53:46 +08:00
|
|
|
|
string version = PackDataInst.Inst.localInfo.version;
|
|
|
|
|
|
string tag = HashUtils.MD5(version);
|
|
|
|
|
|
|
|
|
|
|
|
// 服务端签名原文包含 platform="0",按字母升序排列
|
2025-06-12 19:21:16 +08:00
|
|
|
|
Dictionary<string, string> dicHeadData = PostHeader.PostHeaderInfo(new Dictionary<string, string>
|
|
|
|
|
|
{
|
2026-03-05 18:53:46 +08:00
|
|
|
|
{ "plaintext", version },
|
|
|
|
|
|
{ "platform", "0" },
|
|
|
|
|
|
{ "tag", tag },
|
2025-06-12 19:21:16 +08:00
|
|
|
|
{ "timestamp", DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString() }
|
|
|
|
|
|
});
|
2025-06-23 12:57:24 +08:00
|
|
|
|
|
2026-03-05 18:53:46 +08:00
|
|
|
|
SendVersionBody body = new()
|
|
|
|
|
|
{
|
|
|
|
|
|
plaintext = version,
|
|
|
|
|
|
tag = tag,
|
|
|
|
|
|
platform = "0"
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-03-19 17:56:51 +08:00
|
|
|
|
string url = $"{Dev_PostUrl}sendVersion";
|
|
|
|
|
|
Debug.Log($"[PostDebugSendKey] URL={url}, version={version}, tag(MD5)={tag}");
|
|
|
|
|
|
HttpHelper.PostAsync(url, body, dicHeadData).Forget();
|
2025-06-12 19:21:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-05 18:53:46 +08:00
|
|
|
|
#if UNITY_EDITOR
|
|
|
|
|
|
[UnityEditor.MenuItem("Test/Build/测试 Version (version=1.0.0)")]
|
|
|
|
|
|
public static void TestPostDebugSendKey()
|
|
|
|
|
|
{
|
|
|
|
|
|
const string testVersion = "1.0.0";
|
|
|
|
|
|
string loginKey = HashUtils.MD5(testVersion);
|
|
|
|
|
|
string timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();
|
|
|
|
|
|
|
|
|
|
|
|
// 服务端签名算法:MD5(排序参数字符串) + httpKey 再做 SHA256(64位)
|
|
|
|
|
|
// 即 PostHeader.PostHeaderInfo 内部已实现的流程,参数需包含 platform=""
|
|
|
|
|
|
Dictionary<string, string> signParams = new Dictionary<string, string>
|
|
|
|
|
|
{
|
|
|
|
|
|
{ "plaintext", testVersion },
|
|
|
|
|
|
{ "platform", "" },
|
|
|
|
|
|
{ "tag", loginKey },
|
|
|
|
|
|
{ "timestamp", timestamp }
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
var sortedKeys = signParams.Keys.OrderBy(k => k).ToList();
|
|
|
|
|
|
string sortParamsStr = string.Join("&", sortedKeys.Select(k => $"{k}={signParams[k]}"));
|
|
|
|
|
|
Debug.Log($"[TestPostLoginKey] 签名原文: {sortParamsStr}");
|
|
|
|
|
|
|
|
|
|
|
|
// 使用 PostHeaderInfo 生成 64 位 signature(MD5 + httpKey + SHA256)
|
|
|
|
|
|
Dictionary<string, string> headData = PostHeader.PostHeaderInfo(signParams);
|
|
|
|
|
|
Debug.Log($"[TestPostLoginKey] signature: {headData["signature"]}");
|
|
|
|
|
|
|
|
|
|
|
|
LoginKeyData loginKeyData = new()
|
|
|
|
|
|
{
|
|
|
|
|
|
plaintext = testVersion,
|
|
|
|
|
|
tag = loginKey,
|
|
|
|
|
|
};
|
|
|
|
|
|
string bodyJson = JsonUtility.ToJson(loginKeyData);
|
|
|
|
|
|
Debug.Log($"[TestPostLoginKey] 请求 Body: {bodyJson}");
|
|
|
|
|
|
|
|
|
|
|
|
string testUrl = $"{Dev_PostUrl}version";
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Log($"[TestPostLoginKey] URL: {testUrl}");
|
|
|
|
|
|
HttpHelper.PostAsync(testUrl, loginKeyData, headData).Forget();
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"[TestPostLoginKey Exception]:{e.Message} \r\n {e.StackTrace}");
|
|
|
|
|
|
throw;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[UnityEditor.MenuItem("Test/Build/测试 SendVersion (version=1.0.0)")]
|
|
|
|
|
|
public static void TestPostSendVersion()
|
|
|
|
|
|
{
|
|
|
|
|
|
const string testVersion = "1.0.0";
|
|
|
|
|
|
string loginKey = HashUtils.MD5(testVersion);
|
|
|
|
|
|
string timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();
|
|
|
|
|
|
|
|
|
|
|
|
// sendVersion 签名参数包含 platform="0"(服务端用 strconv.Atoi 解析)
|
|
|
|
|
|
Dictionary<string, string> signParams = new Dictionary<string, string>
|
|
|
|
|
|
{
|
|
|
|
|
|
{ "plaintext", testVersion },
|
|
|
|
|
|
{ "platform", "0" },
|
|
|
|
|
|
{ "tag", loginKey },
|
|
|
|
|
|
{ "timestamp", timestamp }
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
var sortedKeys = signParams.Keys.OrderBy(k => k).ToList();
|
|
|
|
|
|
string sortParamsStr = string.Join("&", sortedKeys.Select(k => $"{k}={signParams[k]}"));
|
|
|
|
|
|
Debug.Log($"[TestPostSendVersion] 签名原文: {sortParamsStr}");
|
|
|
|
|
|
|
|
|
|
|
|
Dictionary<string, string> headData = PostHeader.PostHeaderInfo(signParams);
|
|
|
|
|
|
Debug.Log($"[TestPostSendVersion] signature: {headData["signature"]}");
|
|
|
|
|
|
|
|
|
|
|
|
SendVersionBody body = new()
|
|
|
|
|
|
{
|
|
|
|
|
|
plaintext = testVersion,
|
|
|
|
|
|
tag = loginKey,
|
|
|
|
|
|
platform = "0"
|
|
|
|
|
|
};
|
|
|
|
|
|
string bodyJson = JsonUtility.ToJson(body);
|
|
|
|
|
|
Debug.Log($"[TestPostSendVersion] 请求 Body: {bodyJson}");
|
|
|
|
|
|
|
|
|
|
|
|
string testUrl = $"{Dev_PostUrl}sendVersion";
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Log($"[TestPostSendVersion] URL: {testUrl}");
|
|
|
|
|
|
HttpHelper.PostAsync(testUrl, body, headData).Forget();
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"[TestPostSendVersion Exception]:{e.Message} \r\n {e.StackTrace}");
|
|
|
|
|
|
throw;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-03-19 18:48:56 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 从指定渠道目录读取 ChannelSetting.yaml,返回 ChannelConfig
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private static ChannelConfig LoadChannelConfig(string channelName)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 路径:ProjectNLD/../Tool/Channels/{channelName}/ChannelSetting.yaml
|
|
|
|
|
|
string projectRoot = Directory.GetParent(Application.dataPath)?.Parent?.FullName;
|
|
|
|
|
|
string yamlPath = Path.Combine(projectRoot, "Tool", "Channels", channelName, "ChannelSetting.yaml");
|
|
|
|
|
|
Debug.Log($"[LoadChannelConfig] dataPath={Application.dataPath}");
|
|
|
|
|
|
Debug.Log($"[LoadChannelConfig] projectRoot={projectRoot}");
|
|
|
|
|
|
Debug.Log($"[LoadChannelConfig] yamlPath={yamlPath}");
|
|
|
|
|
|
if (!File.Exists(yamlPath))
|
|
|
|
|
|
throw new FileNotFoundException($"[LoadChannelConfig] 找不到渠道配置文件: {yamlPath}");
|
|
|
|
|
|
|
|
|
|
|
|
var deserializer = new DeserializerBuilder().IgnoreUnmatchedProperties().Build();
|
|
|
|
|
|
string yamlContent = File.ReadAllText(yamlPath);
|
|
|
|
|
|
var config = deserializer.Deserialize<ChannelConfig>(yamlContent);
|
|
|
|
|
|
Debug.Log($"[LoadChannelConfig] 已加载渠道={channelName}, AppAccessKey={config.AppAccessKey}, Version={config.Version}");
|
|
|
|
|
|
return config;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[UnityEditor.MenuItem("Test/Build/测试 SendVersion (MarketTest_Official)")]
|
|
|
|
|
|
public static void TestPostSendVersion_MarketTestOfficial()
|
|
|
|
|
|
{
|
|
|
|
|
|
var config = LoadChannelConfig("MarketTest_Official");
|
|
|
|
|
|
string testVersion = config.Version;
|
|
|
|
|
|
string accessKey = config.AppAccessKey;
|
|
|
|
|
|
string secretKey = config.AppKey;
|
|
|
|
|
|
|
|
|
|
|
|
string tag = HashUtils.MD5(testVersion);
|
|
|
|
|
|
string timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();
|
|
|
|
|
|
|
|
|
|
|
|
Dictionary<string, string> signParams = new Dictionary<string, string>
|
|
|
|
|
|
{
|
|
|
|
|
|
{ "plaintext", testVersion },
|
|
|
|
|
|
{ "platform", "0" },
|
|
|
|
|
|
{ "tag", tag },
|
|
|
|
|
|
{ "timestamp", timestamp }
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
var sortedKeys = signParams.Keys.OrderBy(k => k).ToList();
|
|
|
|
|
|
string signRaw = string.Join("&", sortedKeys.Select(k => $"{k}={signParams[k]}"));
|
|
|
|
|
|
Debug.Log($"[TestSendVersion_Official] version={testVersion}, tag(MD5)={tag}");
|
|
|
|
|
|
Debug.Log($"[TestSendVersion_Official] AppAccessKey={accessKey}, AppKey={secretKey}");
|
|
|
|
|
|
Debug.Log($"[TestSendVersion_Official] 签名原文: {signRaw}");
|
|
|
|
|
|
|
|
|
|
|
|
Dictionary<string, string> headData = PostHeader.PostHeaderInfo(signParams, secretKey, accessKey);
|
|
|
|
|
|
Debug.Log($"[TestSendVersion_Official] signature: {headData["signature"]}");
|
|
|
|
|
|
|
|
|
|
|
|
SendVersionBody body = new()
|
|
|
|
|
|
{
|
|
|
|
|
|
plaintext = testVersion,
|
|
|
|
|
|
tag = tag,
|
|
|
|
|
|
platform = "0"
|
|
|
|
|
|
};
|
|
|
|
|
|
Debug.Log($"[TestSendVersion_Official] 请求 Body: {JsonUtility.ToJson(body)}");
|
|
|
|
|
|
|
|
|
|
|
|
string url = $"{Dev_PostUrl}sendVersion";
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Log($"[TestSendVersion_Official] URL: {url}");
|
|
|
|
|
|
HttpHelper.PostAsync(url, body, headData).Forget();
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"[TestSendVersion_Official Exception]:{e.Message} \r\n {e.StackTrace}");
|
|
|
|
|
|
throw;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[UnityEditor.MenuItem("Test/Build/测试 Version (MarketTest_Official)")]
|
|
|
|
|
|
public static void TestPostVersion_MarketTestOfficial()
|
|
|
|
|
|
{
|
|
|
|
|
|
var config = LoadChannelConfig("MarketTest_Official");
|
|
|
|
|
|
string testVersion = config.Version;
|
|
|
|
|
|
string accessKey = config.AppAccessKey;
|
|
|
|
|
|
string secretKey = config.AppKey;
|
|
|
|
|
|
|
|
|
|
|
|
string tag = HashUtils.MD5(testVersion);
|
|
|
|
|
|
string timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();
|
|
|
|
|
|
|
|
|
|
|
|
// /version 接口:签名参数 platform="" (与 /sendVersion 的 "0" 不同)
|
|
|
|
|
|
Dictionary<string, string> signParams = new Dictionary<string, string>
|
|
|
|
|
|
{
|
|
|
|
|
|
{ "plaintext", testVersion },
|
|
|
|
|
|
{ "platform", "" },
|
|
|
|
|
|
{ "tag", tag },
|
|
|
|
|
|
{ "timestamp", timestamp }
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
var sortedKeys = signParams.Keys.OrderBy(k => k).ToList();
|
|
|
|
|
|
string signRaw = string.Join("&", sortedKeys.Select(k => $"{k}={signParams[k]}"));
|
|
|
|
|
|
Debug.Log($"[TestVersion_Official] version={testVersion}, tag(MD5)={tag}");
|
|
|
|
|
|
Debug.Log($"[TestVersion_Official] AppAccessKey={accessKey}, AppKey={secretKey}");
|
|
|
|
|
|
Debug.Log($"[TestVersion_Official] 签名原文: {signRaw}");
|
|
|
|
|
|
|
|
|
|
|
|
Dictionary<string, string> headData = PostHeader.PostHeaderInfo(signParams, secretKey, accessKey);
|
|
|
|
|
|
Debug.Log($"[TestVersion_Official] signature: {headData["signature"]}");
|
|
|
|
|
|
|
|
|
|
|
|
// /version Body 不含 platform 字段
|
|
|
|
|
|
LoginKeyData body = new()
|
|
|
|
|
|
{
|
|
|
|
|
|
plaintext = testVersion,
|
|
|
|
|
|
tag = tag,
|
|
|
|
|
|
};
|
|
|
|
|
|
Debug.Log($"[TestVersion_Official] 请求 Body: {JsonUtility.ToJson(body)}");
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
string url = $"{Dev_PostUrl}version";
|
|
|
|
|
|
Debug.Log($"[TestVersion_Official] URL: {url}");
|
|
|
|
|
|
HttpHelper.PostAsync(url, body, headData).Forget();
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"[TestVersion_Official Exception]:{e.Message} \r\n {e.StackTrace}");
|
|
|
|
|
|
throw;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-03-05 18:53:46 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
[System.Serializable]
|
2025-05-22 19:00:34 +08:00
|
|
|
|
private class LoginKeyData
|
|
|
|
|
|
{
|
2025-06-04 15:58:31 +08:00
|
|
|
|
public string plaintext;
|
2025-05-22 19:00:34 +08:00
|
|
|
|
public string tag;
|
2025-06-23 12:57:24 +08:00
|
|
|
|
public string platform;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-05 18:53:46 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// /sendVersion 接口 Body
|
|
|
|
|
|
/// platform 服务端内部用 strconv.Atoi 解析,必须为可转整数的字符串(空字符串会报错)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[System.Serializable]
|
|
|
|
|
|
private class SendVersionBody
|
|
|
|
|
|
{
|
|
|
|
|
|
public string plaintext;
|
|
|
|
|
|
public string tag;
|
|
|
|
|
|
public string platform = "0"; // 服务端需要可转整数的字符串,"0" 表示未指定平台
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-22 19:00:34 +08:00
|
|
|
|
private class LoginKeyResData
|
|
|
|
|
|
{
|
|
|
|
|
|
public int code;
|
|
|
|
|
|
public string message;
|
|
|
|
|
|
public object data;
|
|
|
|
|
|
}
|
2025-06-23 13:44:52 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private class ChannelConfig
|
|
|
|
|
|
{
|
|
|
|
|
|
public List<string> Define_list { get; set; }
|
2025-08-22 13:15:44 +08:00
|
|
|
|
|
2025-06-23 13:44:52 +08:00
|
|
|
|
public string PackageName { get; set; }
|
2025-06-27 12:33:37 +08:00
|
|
|
|
|
2025-08-22 13:15:44 +08:00
|
|
|
|
public bool IsOversea { get; set; }
|
|
|
|
|
|
|
2025-06-27 12:33:37 +08:00
|
|
|
|
public int BuildCode { get; set; }
|
2025-06-23 14:23:38 +08:00
|
|
|
|
|
|
|
|
|
|
public string ConfigAccessKeyId { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
public string ConfigAccessKeySecret { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
public string ConfigBucketName { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
public string ConfigURL { get; set; }
|
2025-06-23 14:31:20 +08:00
|
|
|
|
|
|
|
|
|
|
public string AppAccessKey { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
public string AppKey { get; set; }
|
2026-03-19 18:48:56 +08:00
|
|
|
|
|
|
|
|
|
|
public string Version { get; set; }
|
2025-06-23 14:23:38 +08:00
|
|
|
|
|
2026-03-05 13:27:06 +08:00
|
|
|
|
public string PhxhBiAccessKeyId { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
public string PhxhBiScretKey { get; set; }
|
|
|
|
|
|
|
2026-03-05 15:22:58 +08:00
|
|
|
|
public string WxPayAppId { get; set; }
|
|
|
|
|
|
|
2025-06-23 13:44:52 +08:00
|
|
|
|
public CrashSightConfig CrashSight_Android { get; set; }
|
|
|
|
|
|
public CrashSightConfig CrashSight_iOS { get; set; }
|
2025-10-29 15:17:55 +08:00
|
|
|
|
public TalkingDataConfig TalkingData { get; set; }
|
2026-03-19 12:44:23 +08:00
|
|
|
|
public ThinkingDataConfig ThinkingData { get; set; }
|
2025-06-23 13:44:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private class CrashSightConfig
|
|
|
|
|
|
{
|
|
|
|
|
|
[YamlMember(Alias = "id")] public string Id { get; set; }
|
|
|
|
|
|
[YamlMember(Alias = "key")] public string Key { get; set; }
|
|
|
|
|
|
}
|
2025-06-23 14:23:38 +08:00
|
|
|
|
|
2025-10-29 15:17:55 +08:00
|
|
|
|
private class TalkingDataConfig
|
|
|
|
|
|
{
|
|
|
|
|
|
[YamlMember(Alias = "appid")] public string appId { get; set; }
|
|
|
|
|
|
[YamlMember(Alias = "channel")] public string channel { get; set; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-19 12:44:23 +08:00
|
|
|
|
private class ThinkingDataConfig
|
|
|
|
|
|
{
|
|
|
|
|
|
[YamlMember(Alias = "appid")] public string appId { get; set; }
|
|
|
|
|
|
[YamlMember(Alias = "serverurl")] public string serverUrl { get; set; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-23 13:44:52 +08:00
|
|
|
|
private const string ChannelSettingYaml = "/../ChannelSetting.yaml";
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 从YAML文件初始化渠道配置
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private static void InitChannelConfigFromYaml()
|
|
|
|
|
|
{
|
|
|
|
|
|
List<string> appendDefineList = new();
|
|
|
|
|
|
|
|
|
|
|
|
// 判断是否为开发模式
|
|
|
|
|
|
if (EditorUserBuildSettings.development)
|
|
|
|
|
|
{
|
|
|
|
|
|
appendDefineList.Add(DEBUG);
|
|
|
|
|
|
Debug.Log("追加宏定义:" + DEBUG);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string yamlPath = Application.dataPath + ChannelSettingYaml;
|
|
|
|
|
|
if (File.Exists(yamlPath))
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 忽略 YAML 中多余的字段
|
|
|
|
|
|
var deserializer = new DeserializerBuilder()
|
|
|
|
|
|
.IgnoreUnmatchedProperties()
|
|
|
|
|
|
.Build();
|
|
|
|
|
|
|
|
|
|
|
|
string yamlContent = File.ReadAllText(yamlPath);
|
|
|
|
|
|
var config = deserializer.Deserialize<ChannelConfig>(yamlContent);
|
|
|
|
|
|
|
|
|
|
|
|
// 处理宏定义
|
|
|
|
|
|
if (config.Define_list != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (string define in config.Define_list)
|
|
|
|
|
|
{
|
|
|
|
|
|
string cleanDefine = define.Trim();
|
|
|
|
|
|
if (!string.IsNullOrEmpty(cleanDefine))
|
|
|
|
|
|
{
|
|
|
|
|
|
appendDefineList.Add(cleanDefine);
|
|
|
|
|
|
Debug.Log("追加宏定义:" + cleanDefine);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理包名
|
|
|
|
|
|
if (!string.IsNullOrEmpty(config.PackageName))
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Log("设置新包名:" + config.PackageName);
|
|
|
|
|
|
if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.Android)
|
|
|
|
|
|
{
|
|
|
|
|
|
PlayerSettings.applicationIdentifier = config.PackageName;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-22 13:15:44 +08:00
|
|
|
|
YooAssetBuildBase.isOversea = config.IsOversea;
|
|
|
|
|
|
|
2025-06-27 12:33:37 +08:00
|
|
|
|
// 处理BuildCode
|
2026-03-10 14:57:28 +08:00
|
|
|
|
// 若命令行已通过 -buildCode 传入(由 version_code_manager.py 自动递增),优先使用命令行值,不用 YAML 覆盖
|
|
|
|
|
|
bool hasCmdBuildCode = System.Array.Exists(
|
|
|
|
|
|
Environment.GetCommandLineArgs(), a => a == "-buildCode");
|
|
|
|
|
|
if (hasCmdBuildCode)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Log($"[BuildCode] 命令行已传入 -buildCode,跳过 YAML 中 BuildCode={config.BuildCode} 的覆盖");
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (config.BuildCode != 0)
|
2025-06-27 12:33:37 +08:00
|
|
|
|
{
|
|
|
|
|
|
Debug.Log("设置BuildCode:" + config.BuildCode);
|
|
|
|
|
|
#if UNITY_IOS
|
|
|
|
|
|
PlayerSettings.iOS.buildNumber = config.BuildCode.ToString();
|
|
|
|
|
|
#elif UNITY_ANDROID
|
|
|
|
|
|
PlayerSettings.Android.bundleVersionCode = config.BuildCode;
|
|
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-23 14:23:38 +08:00
|
|
|
|
// 处理AppConfig上传id
|
|
|
|
|
|
if (config.ConfigAccessKeyId != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
YooAssetBuildBase.appConfigAccessKeyId = config.ConfigAccessKeyId;
|
|
|
|
|
|
Debug.Log($"设置AppConfig上传id:{YooAssetBuildBase.appConfigAccessKeyId}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理AppConfig上传key
|
|
|
|
|
|
if (config.ConfigAccessKeySecret != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
YooAssetBuildBase.appConfigAccessKeySecret = config.ConfigAccessKeySecret;
|
|
|
|
|
|
Debug.Log($"设置AppConfig上传key:{YooAssetBuildBase.appConfigAccessKeySecret}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理AppConfig上传桶名
|
|
|
|
|
|
if (config.ConfigBucketName != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
YooAssetBuildBase.appConfigBucketName = config.ConfigBucketName;
|
|
|
|
|
|
Debug.Log($"设置AppConfig上传桶名:{YooAssetBuildBase.appConfigBucketName}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理AppConfig上传url
|
|
|
|
|
|
if (config.ConfigURL != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
YooAssetBuildBase.appConfigURL = config.ConfigURL;
|
|
|
|
|
|
Debug.Log($"设置AppConfig上传url:{YooAssetBuildBase.appConfigURL}");
|
|
|
|
|
|
}
|
2025-06-23 14:31:20 +08:00
|
|
|
|
|
|
|
|
|
|
// 处理http请求AccessKey
|
|
|
|
|
|
if (config.AppAccessKey != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
YooAssetBuildBase.httpAccessKey = config.AppAccessKey;
|
|
|
|
|
|
Debug.Log($"设置http请求id:{YooAssetBuildBase.httpAccessKey}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理http请求AppKey
|
|
|
|
|
|
if (config.AppKey != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
YooAssetBuildBase.httpKey = config.AppKey;
|
|
|
|
|
|
Debug.Log($"设置http请求id:{YooAssetBuildBase.httpKey}");
|
|
|
|
|
|
}
|
2025-06-23 13:44:52 +08:00
|
|
|
|
|
2026-03-05 13:27:06 +08:00
|
|
|
|
// 处理BI AccessKeyId
|
|
|
|
|
|
if (config.PhxhBiAccessKeyId != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
YooAssetBuildBase.phxhBiAccessKeyId = config.PhxhBiAccessKeyId;
|
|
|
|
|
|
Debug.Log($"设置BI AccessKeyId:{YooAssetBuildBase.phxhBiAccessKeyId}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理BI SecretKey
|
|
|
|
|
|
if (config.PhxhBiScretKey != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
YooAssetBuildBase.phxhBiScretKey = config.PhxhBiScretKey;
|
|
|
|
|
|
Debug.Log($"设置BI SecretKey:{YooAssetBuildBase.phxhBiScretKey}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-05 15:22:58 +08:00
|
|
|
|
// 处理微信支付 AppID
|
|
|
|
|
|
if (config.WxPayAppId != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
YooAssetBuildBase.wxPayAppId = config.WxPayAppId;
|
|
|
|
|
|
Debug.Log($"设置微信支付 AppID:{YooAssetBuildBase.wxPayAppId}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-23 13:44:52 +08:00
|
|
|
|
// 处理CrashSight_Android配置
|
|
|
|
|
|
if (config.CrashSight_Android != null &&
|
|
|
|
|
|
EditorUserBuildSettings.activeBuildTarget == BuildTarget.Android)
|
|
|
|
|
|
{
|
|
|
|
|
|
var crashSightData = new PhxhSDK.Data.CrashSightData
|
|
|
|
|
|
{
|
|
|
|
|
|
id = config.CrashSight_Android.Id,
|
|
|
|
|
|
key = config.CrashSight_Android.Key
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
var json = JsonUtility.ToJson(crashSightData);
|
2026-03-18 19:05:23 +08:00
|
|
|
|
WriteEncryptedJsonResource("CrashSightData", json);
|
2025-06-23 13:44:52 +08:00
|
|
|
|
Debug.Log("CrashSight配置已保存:" + crashSightData.id + "|" + crashSightData.key);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-29 15:17:55 +08:00
|
|
|
|
// 处理CrashSight_iOS配置
|
2025-06-23 13:44:52 +08:00
|
|
|
|
if (config.CrashSight_iOS != null &&
|
|
|
|
|
|
EditorUserBuildSettings.activeBuildTarget == BuildTarget.iOS)
|
|
|
|
|
|
{
|
|
|
|
|
|
var crashSightData = new PhxhSDK.Data.CrashSightData
|
|
|
|
|
|
{
|
|
|
|
|
|
id = config.CrashSight_iOS.Id,
|
|
|
|
|
|
key = config.CrashSight_iOS.Key
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
var json = JsonUtility.ToJson(crashSightData);
|
2026-03-18 19:05:23 +08:00
|
|
|
|
WriteEncryptedJsonResource("CrashSightData", json);
|
2025-06-23 13:44:52 +08:00
|
|
|
|
Debug.Log("CrashSight配置已保存:" + crashSightData.id + "|" + crashSightData.key);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-29 15:17:55 +08:00
|
|
|
|
if (config.TalkingData != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var talkingDataInitTool = new TalkingDataInitTool
|
|
|
|
|
|
{
|
|
|
|
|
|
appID = config.TalkingData.appId,
|
|
|
|
|
|
channel = config.TalkingData.channel
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
var json = JsonUtility.ToJson(talkingDataInitTool);
|
2026-03-18 19:05:23 +08:00
|
|
|
|
WriteEncryptedJsonResource("TalkingDataInitConfig", json);
|
2025-10-29 15:17:55 +08:00
|
|
|
|
Debug.Log("TalkingData配置已保存:" + talkingDataInitTool.appID + "|" + talkingDataInitTool.channel);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-19 12:44:23 +08:00
|
|
|
|
// 处理数数科技(ThinkingData)配置
|
|
|
|
|
|
if (config.ThinkingData != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
YooAssetBuildBase.thinkingDataAppId = config.ThinkingData.appId;
|
|
|
|
|
|
YooAssetBuildBase.thinkingDataServerUrl = config.ThinkingData.serverUrl;
|
|
|
|
|
|
Debug.Log($"设置数数科技 AppID:{YooAssetBuildBase.thinkingDataAppId}");
|
|
|
|
|
|
Debug.Log($"设置数数科技 ServerUrl:{YooAssetBuildBase.thinkingDataServerUrl}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-23 13:44:52 +08:00
|
|
|
|
// 更新宏定义
|
|
|
|
|
|
var currentTargetGroup = BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget);
|
|
|
|
|
|
var oldDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(currentTargetGroup);
|
|
|
|
|
|
_oldDefines = oldDefines;
|
|
|
|
|
|
|
|
|
|
|
|
if (appendDefineList.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
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));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 关闭Unity闪屏
|
|
|
|
|
|
PlayerSettings.SplashScreen.showUnityLogo = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"解析YAML配置文件失败: {e.Message}\n{e.StackTrace}");
|
|
|
|
|
|
throw;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"找不到渠道配置文件: {yamlPath}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-03-18 19:05:23 +08:00
|
|
|
|
}
|