diff --git a/Assets/CHANGELOG.md b/Assets/CHANGELOG.md index 8c6a4e5..7c1937c 100644 --- a/Assets/CHANGELOG.md +++ b/Assets/CHANGELOG.md @@ -1,3 +1,11 @@ +# [1.4.15] + +### 修复 + +* Release 默认仍关闭 `com.anythink.sdk:debugger-ui`,但不再把 `com.verbto.tools:util` 当作 DebugUI 附属库排除。 +* `TopOn 配置` 页签新增独立的 `verbto util` 强制坐标配置,默认强制声明 `com.verbto.tools:util:1.1.3`;后续 Taku 修复后可取消勾选,交给宿主项目自动解析。 +* Android Gradle 后处理在强制 util 时改写旧的 `com.verbto.tools:util:*` 声明,并只清理非目标版本的本地 util 产物。 + # [1.4.14] ### 修复 diff --git a/Assets/Topon_Adapter/Editor/ToponAndroidDebuggerDependencyPostProcessor.cs b/Assets/Topon_Adapter/Editor/ToponAndroidDebuggerDependencyPostProcessor.cs index 04f102d..df48d07 100644 --- a/Assets/Topon_Adapter/Editor/ToponAndroidDebuggerDependencyPostProcessor.cs +++ b/Assets/Topon_Adapter/Editor/ToponAndroidDebuggerDependencyPostProcessor.cs @@ -13,10 +13,13 @@ namespace Topon_Adapter.Editor { private const string Tag = "[TopOn Build]"; private const string DebuggerDependency = "com.anythink.sdk:debugger-ui:+"; - private const string VerbtoDependency = "com.verbto.tools:util:1.1.3"; + private const string DebuggerDependencyMarker = "com.anythink.sdk:debugger-ui"; + private const string VerbtoDependencyMarker = "com.verbto.tools:util"; private const string DebuggerRepositoryUrl = "https://jfrog.anythinktech.com/artifactory/debugger"; private const string DepsStart = "// TopOn Debugger UI Dependencies Start"; private const string DepsEnd = "// TopOn Debugger UI Dependencies End"; + private const string VerbtoDepsStart = "// TopOn Verbto Util Dependency Start"; + private const string VerbtoDepsEnd = "// TopOn Verbto Util Dependency End"; private const string ReposStart = "// TopOn Debugger UI Repository Start"; private const string ReposEnd = "// TopOn Debugger UI Repository End"; @@ -49,19 +52,25 @@ namespace Topon_Adapter.Editor Path.Combine(gradleRoot, "launcher", "build.gradle"), Path.Combine(gradleRoot, "build.gradle") }; + var forceVerbtoUtilVersion = settings.forceVerbtoUtilVersion; + var verbtoDependency = ToponBuildSettingsStore.GetVerbtoUtilDependency(settings); foreach (var gradleFile in gradleFiles) { - StripDebuggerFromGradleFile(gradleFile); + StripManagedDependenciesFromGradleFile(gradleFile, forceVerbtoUtilVersion); } - StripDebuggerFromGradleFile(Path.Combine(gradleRoot, "settings.gradle")); + StripManagedDependenciesFromGradleFile(Path.Combine(gradleRoot, "settings.gradle"), forceVerbtoUtilVersion); - if (settings.enableDebuggerUI) + if (settings.enableDebuggerUI || forceVerbtoUtilVersion) { InjectRepository(Path.Combine(gradleRoot, "settings.gradle")); InjectRepository(Path.Combine(gradleRoot, "build.gradle")); - InjectDependencies(Path.Combine(path, "build.gradle"), settings.forceVerbtoUtilVersion); + } + + if (settings.enableDebuggerUI) + { + InjectDebuggerDependency(Path.Combine(path, "build.gradle")); Debug.Log($"{Tag} DebugUI dependency enabled for this build."); } else @@ -73,6 +82,17 @@ namespace Topon_Adapter.Editor Debug.Log($"{Tag} DebugUI dependency disabled for this build."); } + + if (forceVerbtoUtilVersion) + { + InjectVerbtoUtilDependency(Path.Combine(path, "build.gradle"), verbtoDependency); + RemoveGeneratedStaleVerbtoUtilArtifacts(gradleRoot, verbtoDependency); + Debug.Log($"{Tag} Verbto util dependency forced to {verbtoDependency}."); + } + else + { + Debug.Log($"{Tag} Verbto util dependency is not modified by TopOn build settings."); + } } private static string GetGradleRoot(string unityLibraryPath) @@ -84,7 +104,7 @@ namespace Topon_Adapter.Editor #endif } - private static void StripDebuggerFromGradleFile(string filePath) + private static void StripManagedDependenciesFromGradleFile(string filePath, bool forceVerbtoUtilVersion) { if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath)) { @@ -94,9 +114,13 @@ namespace Topon_Adapter.Editor var content = File.ReadAllText(filePath); var original = content; content = RemoveMarkedBlock(content, DepsStart, DepsEnd); + content = RemoveMarkedBlock(content, VerbtoDepsStart, VerbtoDepsEnd); content = RemoveMarkedBlock(content, ReposStart, ReposEnd); - content = RemoveDebuggerRepositoryBlocks(content); - content = RemoveLinesContaining(content, "com.anythink.sdk:debugger-ui", "com.verbto.tools:util"); + content = RemoveLinesContaining(content, DebuggerDependencyMarker); + if (forceVerbtoUtilVersion) + { + content = RemoveLinesContaining(content, VerbtoDependencyMarker); + } if (!string.Equals(original, content, StringComparison.Ordinal)) { @@ -104,7 +128,17 @@ namespace Topon_Adapter.Editor } } - private static void InjectDependencies(string buildGradlePath, bool forceVerbtoUtilVersion) + private static void InjectDebuggerDependency(string buildGradlePath) + { + InjectDependencyBlock(buildGradlePath, DepsStart, DepsEnd, DebuggerDependency); + } + + private static void InjectVerbtoUtilDependency(string buildGradlePath, string dependency) + { + InjectDependencyBlock(buildGradlePath, VerbtoDepsStart, VerbtoDepsEnd, dependency); + } + + private static void InjectDependencyBlock(string buildGradlePath, string startMarker, string endMarker, string dependency) { if (!File.Exists(buildGradlePath)) { @@ -112,16 +146,17 @@ namespace Topon_Adapter.Editor return; } - var content = File.ReadAllText(buildGradlePath); - var block = new StringBuilder(); - block.AppendLine(DepsStart); - block.AppendLine($" implementation '{DebuggerDependency}'"); - if (forceVerbtoUtilVersion) + if (string.IsNullOrWhiteSpace(dependency)) { - block.AppendLine($" implementation '{VerbtoDependency}'"); + Debug.LogWarning($"{Tag} dependency is empty, skip injecting {startMarker}."); + return; } - block.AppendLine($" {DepsEnd}"); + var content = File.ReadAllText(buildGradlePath); + var block = new StringBuilder(); + block.AppendLine(startMarker); + block.AppendLine($" implementation '{dependency.Trim()}'"); + block.AppendLine($" {endMarker}"); var pattern = new Regex(@"(dependencies\s*\{)"); if (!pattern.IsMatch(content)) @@ -142,6 +177,11 @@ namespace Topon_Adapter.Editor } var content = File.ReadAllText(gradlePath); + if (content.Contains(DebuggerRepositoryUrl)) + { + return; + } + var block = $"{ReposStart}\n maven {{ url '{DebuggerRepositoryUrl}' }}\n {ReposEnd}"; Regex pattern; if (Path.GetFileName(gradlePath).Equals("settings.gradle", StringComparison.OrdinalIgnoreCase)) @@ -196,26 +236,47 @@ namespace Topon_Adapter.Editor } } + private static void RemoveGeneratedStaleVerbtoUtilArtifacts(string gradleRoot, string expectedDependency) + { + if (string.IsNullOrWhiteSpace(gradleRoot) || !Directory.Exists(gradleRoot)) + { + return; + } + + var root = Path.GetFullPath(gradleRoot).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + foreach (var path in Directory.GetFiles(root, "*", SearchOption.AllDirectories)) + { + var fileName = Path.GetFileName(path); + if (!ToponBuildSettingsStore.IsVerbtoUtilArtifactFileName(fileName) || + ToponBuildSettingsStore.IsExpectedVerbtoUtilArtifactFileName(fileName, expectedDependency)) + { + continue; + } + + var fullPath = Path.GetFullPath(path); + if (!fullPath.StartsWith(root, StringComparison.OrdinalIgnoreCase)) + { + continue; + } + + try + { + File.Delete(fullPath); + Debug.Log($"{Tag} Removed stale verbto util artifact: {fullPath}"); + } + catch (Exception exception) + { + Debug.LogWarning($"{Tag} Failed to remove stale verbto util artifact: {exception.Message}"); + } + } + } + private static string RemoveMarkedBlock(string content, string startMarker, string endMarker) { var pattern = new Regex($@"\s*{Regex.Escape(startMarker)}[\s\S]*?{Regex.Escape(endMarker)}\s*"); return pattern.Replace(content, "\n"); } - private static string RemoveDebuggerRepositoryBlocks(string content) - { - var escapedUrl = Regex.Escape(DebuggerRepositoryUrl); - content = Regex.Replace( - content, - $@"\r?\n\s*maven\s*\{{\s*url\s*['""]{escapedUrl}['""][^\r\n]*\s*\}}", - string.Empty); - content = Regex.Replace( - content, - $@"\r?\n\s*maven\s*\{{\s*\r?\n\s*url\s*['""]{escapedUrl}['""][^\r\n]*\r?\n\s*\}}", - string.Empty); - return content; - } - private static string RemoveLinesContaining(string content, params string[] markers) { var lines = content.Replace("\r\n", "\n").Replace('\r', '\n').Split('\n'); diff --git a/Assets/Topon_Adapter/Editor/ToponBuildSettingsStore.cs b/Assets/Topon_Adapter/Editor/ToponBuildSettingsStore.cs index b06fec3..66b9efb 100644 --- a/Assets/Topon_Adapter/Editor/ToponBuildSettingsStore.cs +++ b/Assets/Topon_Adapter/Editor/ToponBuildSettingsStore.cs @@ -11,17 +11,19 @@ namespace Topon_Adapter.Editor { public bool enableDebuggerUI = false; public bool forceVerbtoUtilVersion = true; + public string verbtoUtilDependency = ToponBuildSettingsStore.DefaultVerbtoUtilDependency; public bool stripResolvedDebuggerArtifacts = true; } internal static class ToponBuildSettingsStore { + public const string DefaultVerbtoUtilDependency = "com.verbto.tools:util:1.1.3"; + private const string ActiveBuildSessionKey = "Commercialization.Topon.ActiveBuildSettings"; private const string SettingsFileSuffix = "_topon_build_settings.json"; private const string BuildConfigsFolder = "BuildConfigs"; private const string DebuggerPackageMarker = "com.anythink.sdk:debugger-ui"; private const string VerbtoPackageMarker = "com.verbto.tools:util"; - private const string DebuggerRepositoryMarker = "jfrog.anythinktech.com/artifactory/debugger"; [Serializable] private sealed class ActiveBuildSettings @@ -35,6 +37,16 @@ namespace Topon_Adapter.Editor return new ToponBuildSettings(); } + public static string GetVerbtoUtilDependency(ToponBuildSettings settings) + { + if (settings == null || string.IsNullOrWhiteSpace(settings.verbtoUtilDependency)) + { + return DefaultVerbtoUtilDependency; + } + + return settings.verbtoUtilDependency.Trim(); + } + public static ToponBuildSettings LoadForProfileName(string profileName, string repositoryRoot) { var settings = CreateDefault(); @@ -47,6 +59,7 @@ namespace Topon_Adapter.Editor try { JsonUtility.FromJsonOverwrite(File.ReadAllText(path), settings); + Normalize(settings); } catch (Exception exception) { @@ -62,6 +75,10 @@ namespace Topon_Adapter.Editor { settings = CreateDefault(); } + else + { + Normalize(settings); + } var path = GetSettingsPath(profileName, repositoryRoot); if (string.IsNullOrEmpty(path)) @@ -111,6 +128,7 @@ namespace Topon_Adapter.Editor { return CreateDefault(); } + Normalize(activeSettings.settings); var activatedAt = new DateTime(activeSettings.utcTicks, DateTimeKind.Utc); if (DateTime.UtcNow - activatedAt > TimeSpan.FromHours(6)) @@ -143,9 +161,35 @@ namespace Topon_Adapter.Editor } var content = File.ReadAllText(path); - if (content.Contains(DebuggerPackageMarker) || - content.Contains(VerbtoPackageMarker) || - content.Contains(DebuggerRepositoryMarker)) + if (content.Contains(DebuggerPackageMarker)) + { + return true; + } + } + + return false; + } + + public static bool HasUnforcedVerbtoUtilOutput(string repositoryRoot, string expectedDependency) + { + expectedDependency = NormalizeDependency(expectedDependency); + foreach (var path in GetResolverOutputPaths(repositoryRoot)) + { + if (!File.Exists(path)) + { + continue; + } + + var content = File.ReadAllText(path); + if (content.Contains(VerbtoPackageMarker) && !content.Contains(expectedDependency)) + { + return true; + } + } + + foreach (var path in FindResolvedVerbtoUtilArtifacts(repositoryRoot)) + { + if (!IsExpectedVerbtoUtilArtifactFileName(Path.GetFileName(path), expectedDependency)) { return true; } @@ -180,6 +224,32 @@ namespace Topon_Adapter.Editor return result; } + public static IReadOnlyList FindResolvedVerbtoUtilArtifacts(string repositoryRoot) + { + var result = new List(); + var root = ResolveRepositoryRoot(repositoryRoot); + if (string.IsNullOrEmpty(root)) + { + return result; + } + + var androidPluginPath = Path.Combine(root, "Assets", "Plugins", "Android"); + if (!Directory.Exists(androidPluginPath)) + { + return result; + } + + foreach (var path in Directory.GetFiles(androidPluginPath, "*", SearchOption.AllDirectories)) + { + if (IsVerbtoUtilArtifactFileName(Path.GetFileName(path))) + { + result.Add(path); + } + } + + return result; + } + internal static bool IsDebuggerArtifactFileName(string fileName) { if (string.IsNullOrEmpty(fileName)) @@ -187,8 +257,33 @@ namespace Topon_Adapter.Editor return false; } - return fileName.StartsWith("com.anythink.sdk.debugger-ui-", StringComparison.OrdinalIgnoreCase) || - fileName.StartsWith("com.verbto.tools.util-", StringComparison.OrdinalIgnoreCase); + return fileName.StartsWith("com.anythink.sdk.debugger-ui-", StringComparison.OrdinalIgnoreCase); + } + + internal static bool IsVerbtoUtilArtifactFileName(string fileName) + { + if (string.IsNullOrEmpty(fileName)) + { + return false; + } + + return fileName.StartsWith("com.verbto.tools.util-", StringComparison.OrdinalIgnoreCase); + } + + internal static bool IsExpectedVerbtoUtilArtifactFileName(string fileName, string expectedDependency) + { + if (!IsVerbtoUtilArtifactFileName(fileName)) + { + return false; + } + + var version = GetVersionFromDependency(expectedDependency); + if (string.IsNullOrEmpty(version)) + { + return false; + } + + return fileName.StartsWith($"com.verbto.tools.util-{version}", StringComparison.OrdinalIgnoreCase); } private static ToponBuildSettings Clone(ToponBuildSettings settings) @@ -202,10 +297,38 @@ namespace Topon_Adapter.Editor { enableDebuggerUI = settings.enableDebuggerUI, forceVerbtoUtilVersion = settings.forceVerbtoUtilVersion, + verbtoUtilDependency = GetVerbtoUtilDependency(settings), stripResolvedDebuggerArtifacts = settings.stripResolvedDebuggerArtifacts }; } + private static void Normalize(ToponBuildSettings settings) + { + if (settings == null) + { + return; + } + + settings.verbtoUtilDependency = NormalizeDependency(settings.verbtoUtilDependency); + } + + private static string NormalizeDependency(string dependency) + { + if (string.IsNullOrWhiteSpace(dependency)) + { + return DefaultVerbtoUtilDependency; + } + + return dependency.Trim(); + } + + private static string GetVersionFromDependency(string dependency) + { + dependency = NormalizeDependency(dependency); + var parts = dependency.Split(':'); + return parts.Length >= 3 ? parts[parts.Length - 1] : string.Empty; + } + private static IEnumerable GetResolverOutputPaths(string repositoryRoot) { var root = ResolveRepositoryRoot(repositoryRoot); diff --git a/Assets/Topon_Adapter/Editor/ToponBuildWindowExtension.cs b/Assets/Topon_Adapter/Editor/ToponBuildWindowExtension.cs index 5d9d715..9ef385d 100644 --- a/Assets/Topon_Adapter/Editor/ToponBuildWindowExtension.cs +++ b/Assets/Topon_Adapter/Editor/ToponBuildWindowExtension.cs @@ -31,7 +31,7 @@ namespace Topon_Adapter.Editor EditorGUILayout.LabelField("TopOn Android 调试工具", EditorStyles.boldLabel); EditorGUILayout.HelpBox( - "正式 release 默认关闭 DebugUI。关闭后构建后处理会剔除 debugger-ui 及其诊断库,避免 anr_data.db 降级崩溃。", + "正式 release 默认关闭 DebugUI。verbto util 独立控制,默认强制指定到 1.1.3,避免回落到存在数据库降级风险的旧版本。", MessageType.Info); EditorGUI.BeginChangeCheck(); @@ -39,15 +39,19 @@ namespace Topon_Adapter.Editor new GUIContent("启用 DebugUI 依赖", "仅用于开发/测试包;正式 release 应保持关闭。"), settings.enableDebuggerUI); - using (new EditorGUI.DisabledScope(!settings.enableDebuggerUI)) + settings.forceVerbtoUtilVersion = EditorGUILayout.Toggle( + new GUIContent("强制指定 verbto util", "无论 DebugUI 是否启用,都声明下方的 com.verbto.tools:util 坐标;取消勾选后交给 Taku/宿主项目自动处理。"), + settings.forceVerbtoUtilVersion); + + using (new EditorGUI.DisabledScope(!settings.forceVerbtoUtilVersion)) { - settings.forceVerbtoUtilVersion = EditorGUILayout.Toggle( - new GUIContent("强制 util 1.1.3", "启用 DebugUI 时同时声明 com.verbto.tools:util:1.1.3,避免回落到 1.0.6。"), - settings.forceVerbtoUtilVersion); + settings.verbtoUtilDependency = EditorGUILayout.TextField( + new GUIContent("util 坐标", "默认 com.verbto.tools:util:1.1.3;Taku 修复后可取消强制指定。"), + ToponBuildSettingsStore.GetVerbtoUtilDependency(settings)); } settings.stripResolvedDebuggerArtifacts = EditorGUILayout.Toggle( - new GUIContent("禁用时剔除旧产物", "关闭 DebugUI 时,从生成的 Gradle 工程中删除旧 Resolver 带入的 debugger-ui/util AAR。"), + new GUIContent("禁用时剔除 DebugUI 旧产物", "关闭 DebugUI 时,从生成的 Gradle 工程中删除旧 Resolver 带入的 debugger-ui AAR;不会把 verbto util 当作 DebugUI 一起剔除。"), settings.stripResolvedDebuggerArtifacts); if (EditorGUI.EndChangeCheck()) @@ -65,6 +69,15 @@ namespace Topon_Adapter.Editor EditorGUILayout.HelpBox("当前配置不会打包 TopOn DebugUI。", MessageType.None); } + if (settings.forceVerbtoUtilVersion) + { + EditorGUILayout.HelpBox($"当前会强制声明 {ToponBuildSettingsStore.GetVerbtoUtilDependency(settings)}。", MessageType.None); + } + else + { + EditorGUILayout.HelpBox("当前不会干预 verbto util 版本,由 Taku/宿主项目依赖解析决定。", MessageType.Info); + } + DrawResolverStatus(context); } @@ -90,7 +103,7 @@ namespace Topon_Adapter.Editor } else { - report.AddMessage("TopOn DebugUI 已关闭,构建产物会剔除 debugger-ui/util 诊断库。"); + report.AddMessage("TopOn DebugUI 已关闭,构建产物不会打包 debugger-ui。"); } if (!settings.enableDebuggerUI && ToponBuildSettingsStore.HasStaleDebuggerResolverOutput(context.repositoryRoot)) @@ -98,6 +111,20 @@ namespace Topon_Adapter.Editor report.AddWarning("检测到旧 Resolver 输出仍包含 TopOn DebugUI;本次构建会在生成 Gradle 后剔除,建议后续重新 Resolve。"); } + if (settings.forceVerbtoUtilVersion) + { + var dependency = ToponBuildSettingsStore.GetVerbtoUtilDependency(settings); + report.AddMessage($"TopOn 将强制声明 {dependency}。"); + if (ToponBuildSettingsStore.HasUnforcedVerbtoUtilOutput(context.repositoryRoot, dependency)) + { + report.AddWarning($"检测到旧 Resolver 输出或本地 AAR 可能不是 {dependency};本次构建会在生成 Gradle 后改写为强制版本。"); + } + } + else + { + report.AddMessage("TopOn 不干预 verbto util 版本。"); + } + return report; } @@ -108,13 +135,26 @@ namespace Topon_Adapter.Editor private static void DrawResolverStatus(BuildWindowExtensionContext context) { - var hasStaleOutput = ToponBuildSettingsStore.HasStaleDebuggerResolverOutput(context.repositoryRoot); - var artifacts = ToponBuildSettingsStore.FindResolvedDebuggerArtifacts(context.repositoryRoot); + var profile = context?.profile; + var settings = profile == null + ? ToponBuildSettingsStore.CreateDefault() + : ToponBuildSettingsStore.LoadForProfileName(profile.profileName, context.repositoryRoot); + var dependency = ToponBuildSettingsStore.GetVerbtoUtilDependency(settings); + var hasStaleDebuggerOutput = ToponBuildSettingsStore.HasStaleDebuggerResolverOutput(context.repositoryRoot); + var hasUnforcedUtilOutput = ToponBuildSettingsStore.HasUnforcedVerbtoUtilOutput(context.repositoryRoot, dependency); + var debuggerArtifacts = ToponBuildSettingsStore.FindResolvedDebuggerArtifacts(context.repositoryRoot); + var utilArtifacts = ToponBuildSettingsStore.FindResolvedVerbtoUtilArtifacts(context.repositoryRoot); EditorGUILayout.Space(6); EditorGUILayout.LabelField("本地依赖状态", EditorStyles.boldLabel); - EditorGUILayout.LabelField("旧 Resolver 输出", hasStaleOutput ? "检测到 debugger-ui/util" : "未检测到"); - EditorGUILayout.LabelField("已解析 AAR/JAR", artifacts.Count == 0 ? "未检测到" : $"{artifacts.Count} 个"); + EditorGUILayout.LabelField("旧 DebugUI 输出", hasStaleDebuggerOutput ? "检测到 debugger-ui" : "未检测到"); + EditorGUILayout.LabelField("DebugUI AAR/JAR", debuggerArtifacts.Count == 0 ? "未检测到" : $"{debuggerArtifacts.Count} 个"); + EditorGUILayout.LabelField("verbto util 强制", settings.forceVerbtoUtilVersion ? dependency : "自动/不干预"); + EditorGUILayout.LabelField("verbto util 本地产物", utilArtifacts.Count == 0 ? "未检测到" : $"{utilArtifacts.Count} 个"); + if (settings.forceVerbtoUtilVersion && hasUnforcedUtilOutput) + { + EditorGUILayout.HelpBox("检测到本地/Resolver 中存在非强制版本的 verbto util;Android Gradle 工程生成后会改写依赖,并清理旧版本本地产物。", MessageType.Warning); + } } } } diff --git a/Assets/package.json b/Assets/package.json index 5d6362d..d56241e 100644 --- a/Assets/package.json +++ b/Assets/package.json @@ -2,7 +2,7 @@ "name": "com.commercialization.topon", "displayName": "Commercialization.topon", "description": "基于topon的广告sdk封装,依赖基础商业化模块", - "version": "1.4.14", + "version": "1.4.15", "unity": "2021.1", "license": "MIT", "repository": { diff --git a/README.md b/README.md index 7521c10..5d7b06f 100644 --- a/README.md +++ b/README.md @@ -237,7 +237,8 @@ - `topon.debug=true` 现在只打开 SDK 调试日志。 - 官方 DebugUI 默认不再自动弹出,如需使用,手动调用或在样例面板点击 `Open DebugUI`。 - Android 正式包默认不再解析或打包 `com.anythink.sdk:debugger-ui`。 -- 如果测试包确实需要官方 DebugUI,请在 `Build/Modular Build System` 的 `TopOn 配置` 页签中开启 `启用 DebugUI 依赖`。关闭时,构建后处理会从生成的 Gradle 工程剔除 `debugger-ui` 以及 `com.verbto.tools:util`。 +- `TopOn 配置` 页签默认强制声明 `com.verbto.tools:util:1.1.3`,无论 DebugUI 是否启用都会生效;Taku 修复后可取消 `强制指定 verbto util`,改为由宿主项目自动解析。 +- 如果测试包确实需要官方 DebugUI,请在 `Build/Modular Build System` 的 `TopOn 配置` 页签中开启 `启用 DebugUI 依赖`。关闭时,构建后处理只剔除 `debugger-ui`,不会把 `com.verbto.tools:util` 当作 DebugUI 一起排除。 - `topon.exclude_bundle_ids` - 用于全局排除指定广告主 bundle id