From 08ea53580d8df9908fc1ab2bc6284fcf1fc12437 Mon Sep 17 00:00:00 2001 From: CORE-FOLDCCCore <1813547935@qq.com> Date: Sun, 14 Jun 2026 18:18:05 +0800 Subject: [PATCH] feat: move bugly build settings into crashreport --- CHANGELOG.md | 13 + Editor/BuglyAndroidSymbolUtility.cs | 651 +++++++++++++++++++++++ Editor/BuglyAndroidSymbolUtility.cs.meta | 11 + Editor/CrashPostProcessBuildIOS.cs | 22 +- Editor/CrashReportBuildExtension.cs | 481 +++++++++++++++++ Editor/CrashReportBuildExtension.cs.meta | 11 + Editor/CrashReportBuildSettings.cs | 130 +++++ Editor/CrashReportBuildSettings.cs.meta | 11 + package.json | 3 +- 9 files changed, 1325 insertions(+), 8 deletions(-) create mode 100644 Editor/BuglyAndroidSymbolUtility.cs create mode 100644 Editor/BuglyAndroidSymbolUtility.cs.meta create mode 100644 Editor/CrashReportBuildExtension.cs create mode 100644 Editor/CrashReportBuildExtension.cs.meta create mode 100644 Editor/CrashReportBuildSettings.cs create mode 100644 Editor/CrashReportBuildSettings.cs.meta diff --git a/CHANGELOG.md b/CHANGELOG.md index 77bfac5..16f7a98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,3 +25,16 @@ ### 修复 * 修复 `CHANGELOG.md.meta` 与 `package.json.meta` 和 Commercialization 包重复导致的 UPM GUID 冲突告警。 + +# [1.0.4] + +### 新增 + +* 新增 Crash/Bugly 构建面板扩展,由 CrashReport 包自身维护 Bugly 构建配置。 +* 支持按构建 profile 保存 Android 符号表归档/上传配置。 +* 支持按构建 profile 配置 iOS Bugly Pod 注入版本和构建后 `pod install`。 + +### 调整 + +* iOS Bugly Pod 后处理改为读取 CrashReport 构建配置,不再固定写入单一版本。 +* 声明对 `com.foldcc.cc-framework.common` 的构建面板 API 依赖。 diff --git a/Editor/BuglyAndroidSymbolUtility.cs b/Editor/BuglyAndroidSymbolUtility.cs new file mode 100644 index 0000000..a8a871a --- /dev/null +++ b/Editor/BuglyAndroidSymbolUtility.cs @@ -0,0 +1,651 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.IO.Compression; +using System.Reflection; +using System.Security.Cryptography; +using System.Text; +using UnityEditor; +using UnityEngine; +using Debug = UnityEngine.Debug; + +namespace CCFramework.CrashReport.Editor +{ + public static class BuglyAndroidSymbolUtility + { + public delegate void LogHandler(string message, LogType type = LogType.Log); + + public const string BuglyDownloadUrl = "https://bugly.tds.tencent.com/docs/assets/files/bugly_symbol_oversea_v3.4.23-a449c7a62d7792de76fca1af623584f5.zip"; + public const string BuglyToolGuideUrl = "https://bugly.tds.tencent.com/docs/tutorial/symbol/tool/"; + + private const string SymbolFolderSuffix = "_bugly_symbols"; + private const string SymbolPackageSuffix = "_bugly_symbols.zip"; + private const string UploadStagingDirectory = "Library/BuglySymbolUpload"; + + public static void ApplyAndroidSymbolSettings(BuildProfile profile, CrashReportBuglyProfileSettings settings, LogHandler log) + { + if (!IsAndroidProfile(profile) || settings == null || !settings.enableAndroidSymbolArchive) + { + return; + } + + EditorUserBuildSettings.androidCreateSymbols = AndroidCreateSymbols.Debugging; + WriteLog(log, "已启用 Android Debugging 符号表生成,构建后会产出 native-debug-symbols.zip。"); + } + + public static BuglySymbolArchiveResult ArchiveAfterBuild( + BuildProfile profile, + CrashReportBuglyProfileSettings settings, + string buildOutputPath, + LogHandler log) + { + BuglySymbolArchiveResult result = new BuglySymbolArchiveResult(); + if (!IsAndroidProfile(profile) || settings == null || !settings.enableAndroidSymbolArchive) + { + result.message = "当前不是 Android 构建或未启用 Bugly 符号表归档。"; + WriteLog(log, result.message); + return result; + } + + string resolvedBuildOutputPath = ResolveFullPath(buildOutputPath); + string buildDirectory = Path.GetDirectoryName(resolvedBuildOutputPath); + string buildName = Path.GetFileNameWithoutExtension(resolvedBuildOutputPath); + string archiveDirectory = Path.Combine(buildDirectory, buildName + SymbolFolderSuffix); + Directory.CreateDirectory(archiveDirectory); + + string nativeSymbolPath = FindNativeDebugSymbols(profile); + string mappingPath = FindMappingFile(profile, resolvedBuildOutputPath); + + if (!string.IsNullOrWhiteSpace(nativeSymbolPath)) + { + result.nativeSymbolPath = Path.Combine(archiveDirectory, buildName + "_native-debug-symbols.zip"); + File.Copy(nativeSymbolPath, result.nativeSymbolPath, true); + WriteLog(log, $"已归档 Bugly SO 符号表:{result.nativeSymbolPath}"); + } + else + { + WriteLog(log, "未找到 native-debug-symbols.zip,Native Crash 可能无法还原。", LogType.Warning); + } + + if (!string.IsNullOrWhiteSpace(mappingPath)) + { + result.mappingPath = Path.Combine(archiveDirectory, buildName + "_mapping.txt"); + File.Copy(mappingPath, result.mappingPath, true); + WriteLog(log, $"已归档 Bugly mapping 文件:{result.mappingPath}"); + } + + result.archiveDirectory = archiveDirectory; + result.manifestPath = WriteManifest(profile, resolvedBuildOutputPath, archiveDirectory, result); + result.packagePath = CreatePackage(archiveDirectory, Path.Combine(buildDirectory, buildName + SymbolPackageSuffix)); + result.hasSymbols = File.Exists(result.nativeSymbolPath) || File.Exists(result.mappingPath); + result.message = result.hasSymbols ? "Bugly 符号表归档完成。" : "Bugly 符号表归档完成,但没有找到可上传的符号表文件。"; + WriteLog(log, $"Bugly 符号表包:{result.packagePath}"); + return result; + } + + public static BuglySymbolUploadResult UploadPreparedSymbols( + BuildProfile profile, + CrashReportBuglyProfileSettings settings, + BuglySymbolArchiveResult archive, + LogHandler log) + { + if (profile == null || settings == null) + { + return FailUpload("构建配置为空,无法上传 Bugly 符号表。", log); + } + + if (archive == null || !archive.hasSymbols) + { + return FailUpload("没有可上传的 Bugly 符号表文件。", log); + } + + string javaPath = string.IsNullOrWhiteSpace(settings.buglyJavaPath) ? "java" : settings.buglyJavaPath.Trim(); + string toolPath = ResolveSymbolToolPath(settings); + if (string.IsNullOrWhiteSpace(settings.buglyAppId)) + { + return FailUpload("Bugly App ID 为空。", log); + } + + if (string.IsNullOrWhiteSpace(settings.buglyAppKey)) + { + return FailUpload("Bugly App Key 为空。", log); + } + + if (string.IsNullOrWhiteSpace(toolPath) || !File.Exists(toolPath)) + { + return FailUpload($"Bugly 符号表工具不存在:{toolPath}", log); + } + + BuglySymbolArchiveResult uploadArchive = PrepareUploadInputs(profile, archive, log); + List arguments = new List + { + "-jar", + Quote(toolPath), + "-appid", + Quote(settings.buglyAppId.Trim()), + "-appkey", + Quote(settings.buglyAppKey.Trim()), + "-version", + Quote(profile.version), + "-buildNo", + Quote(profile.buildNumber.ToString()), + "-platform", + "Android" + }; + + if (PathExists(uploadArchive.nativeSymbolPath)) + { + arguments.Add("-inputSymbol"); + arguments.Add(Quote(uploadArchive.nativeSymbolPath)); + } + + if (File.Exists(uploadArchive.mappingPath)) + { + arguments.Add("-inputMapping"); + arguments.Add(Quote(uploadArchive.mappingPath)); + } + + string argumentText = string.Join(" ", arguments); + WriteLog(log, $"开始上传 Bugly 符号表:{javaPath} {MaskUploadArguments(argumentText)}"); + + ProcessStartInfo startInfo = new ProcessStartInfo + { + FileName = javaPath, + Arguments = argumentText, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + StandardOutputEncoding = GetBuglyToolOutputEncoding(), + StandardErrorEncoding = GetBuglyToolOutputEncoding() + }; + + try + { + using (Process process = Process.Start(startInfo)) + { + string output = process.StandardOutput.ReadToEnd(); + string error = process.StandardError.ReadToEnd(); + process.WaitForExit(); + + BuglySymbolUploadResult result = new BuglySymbolUploadResult + { + success = process.ExitCode == 0 && IsBuglyUploadOutputSuccessful(output, error), + exitCode = process.ExitCode, + output = output, + error = error, + command = javaPath + " " + MaskUploadArguments(argumentText) + }; + result.logPath = WriteUploadLog(archive.archiveDirectory, result); + + if (result.success) + { + WriteLog(log, $"Bugly 符号表上传完成,日志:{result.logPath}"); + } + else + { + WriteLog(log, $"Bugly 符号表上传失败,ExitCode={result.exitCode},日志:{result.logPath}", LogType.Error); + } + + return result; + } + } + catch (Exception e) + { + return FailUpload($"执行 Bugly 符号表上传失败:{e.Message}", log); + } + } + + public static string BuildUploadCommandTemplate(BuildProfile profile, CrashReportBuglyProfileSettings settings, bool maskSecret) + { + if (profile == null || settings == null) + { + return string.Empty; + } + + string buildOutputPath = ResolveFullPath(BuildPipelineCore.GetExpectedBuildOutputPath(profile)); + string buildDirectory = Path.GetDirectoryName(buildOutputPath); + string buildName = Path.GetFileNameWithoutExtension(buildOutputPath); + string archiveDirectory = Path.Combine(buildDirectory, buildName + SymbolFolderSuffix); + string appKey = string.IsNullOrWhiteSpace(settings.buglyAppKey) ? "" : settings.buglyAppKey.Trim(); + if (maskSecret && !string.IsNullOrWhiteSpace(settings.buglyAppKey)) + { + appKey = "******"; + } + + return (string.IsNullOrWhiteSpace(settings.buglyJavaPath) ? "java" : settings.buglyJavaPath.Trim()) + + " -jar " + Quote(ResolveSymbolToolPath(settings)) + + " -appid " + Quote(string.IsNullOrWhiteSpace(settings.buglyAppId) ? "" : settings.buglyAppId.Trim()) + + " -appkey " + Quote(appKey) + + " -version " + Quote(profile.version) + + " -buildNo " + Quote(profile.buildNumber.ToString()) + + " -platform Android" + + " -inputSymbol " + Quote(Path.Combine(archiveDirectory, buildName + "_native-debug-symbols.zip")) + + " -inputMapping " + Quote(Path.Combine(archiveDirectory, buildName + "_mapping.txt")); + } + + public static string ResolveSymbolToolPath(CrashReportBuglyProfileSettings settings) + { + if (settings != null && !string.IsNullOrWhiteSpace(settings.buglySymbolToolPath)) + { + string configuredPath = ResolveFullPath(settings.buglySymbolToolPath); + if (File.Exists(configuredPath)) + { + return configuredPath; + } + } + + string bundledRoot = Path.Combine(GetProjectRoot(), "Tools", "BuglySymbolTool"); + if (!Directory.Exists(bundledRoot)) + { + return string.Empty; + } + + string newestPath = string.Empty; + DateTime newestWriteTime = DateTime.MinValue; + foreach (string jarPath in Directory.GetFiles(bundledRoot, "*.jar", SearchOption.AllDirectories)) + { + DateTime writeTime = File.GetLastWriteTimeUtc(jarPath); + if (writeTime > newestWriteTime) + { + newestPath = jarPath; + newestWriteTime = writeTime; + } + } + + return newestPath; + } + + public static string ToProfilePath(string path) + { + if (string.IsNullOrWhiteSpace(path)) + { + return string.Empty; + } + + string fullPath = ResolveFullPath(path); + string projectRoot = GetProjectRoot().TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + string rootPrefix = projectRoot + Path.DirectorySeparatorChar; + if (fullPath.StartsWith(rootPrefix, StringComparison.OrdinalIgnoreCase)) + { + return fullPath.Substring(rootPrefix.Length).Replace(Path.DirectorySeparatorChar, '/'); + } + + return path; + } + + private static bool IsAndroidProfile(BuildProfile profile) + { + if (profile == null) + { + return false; + } + + Type profileType = profile.GetType(); + string targetPlatform = GetStringField(profileType, profile, "targetPlatform"); + string buildTargetGroup = GetStringField(profileType, profile, "buildTargetGroup"); + string buildTarget = GetStringField(profileType, profile, "buildTarget"); + bool hasExplicitPlatformValue = + !string.IsNullOrWhiteSpace(targetPlatform) || + !string.IsNullOrWhiteSpace(buildTargetGroup) || + !string.IsNullOrWhiteSpace(buildTarget); + return IsPlatformValue(targetPlatform, "Android") || + IsPlatformValue(buildTargetGroup, "Android") || + IsPlatformValue(buildTarget, "Android") || + (!hasExplicitPlatformValue && EditorUserBuildSettings.activeBuildTarget == BuildTarget.Android); + } + + private static string GetStringField(Type ownerType, object instance, string fieldName) + { + FieldInfo field = ownerType.GetField(fieldName, BindingFlags.Public | BindingFlags.Instance); + return field?.GetValue(instance) as string ?? string.Empty; + } + + private static bool IsPlatformValue(string value, string expectedValue) + { + return !string.IsNullOrWhiteSpace(value) && + string.Equals(value, expectedValue, StringComparison.OrdinalIgnoreCase); + } + + private static string FindNativeDebugSymbols(BuildProfile profile) + { + string buildType = profile != null && profile.isDevelopment ? "debug" : "release"; + string preferredPath = Path.Combine( + GetProjectRoot(), + "Library", + "Bee", + "Android", + "Prj", + "IL2CPP", + "Gradle", + "launcher", + "build", + "outputs", + "native-debug-symbols", + buildType, + "native-debug-symbols.zip"); + + return File.Exists(preferredPath) + ? preferredPath + : FindNewestFile(Path.Combine(GetProjectRoot(), "Library", "Bee", "Android"), "native-debug-symbols.zip"); + } + + private static string FindMappingFile(BuildProfile profile, string buildOutputPath) + { + string buildDirectory = Path.GetDirectoryName(buildOutputPath); + string newestOutputMapping = FindNewestFile(buildDirectory, "*mapping*.txt"); + if (!string.IsNullOrEmpty(newestOutputMapping)) + { + return newestOutputMapping; + } + + string buildType = profile != null && profile.isDevelopment ? "debug" : "release"; + string preferredRoot = Path.Combine( + GetProjectRoot(), + "Library", + "Bee", + "Android", + "Prj", + "IL2CPP", + "Gradle", + "launcher", + "build", + "outputs", + "mapping", + buildType); + + string preferredMapping = FindNewestFile(preferredRoot, "mapping.txt"); + return !string.IsNullOrEmpty(preferredMapping) + ? preferredMapping + : FindNewestFile(Path.Combine(GetProjectRoot(), "Library", "Bee", "Android"), "mapping.txt"); + } + + private static string FindNewestFile(string root, string fileName) + { + if (string.IsNullOrEmpty(root) || !Directory.Exists(root)) + { + return string.Empty; + } + + string newestPath = string.Empty; + DateTime newestWriteTime = DateTime.MinValue; + foreach (string file in Directory.GetFiles(root, fileName, SearchOption.AllDirectories)) + { + DateTime writeTime = File.GetLastWriteTimeUtc(file); + if (writeTime > newestWriteTime) + { + newestPath = file; + newestWriteTime = writeTime; + } + } + + return newestPath; + } + + private static string WriteManifest(BuildProfile profile, string buildOutputPath, string archiveDirectory, BuglySymbolArchiveResult result) + { + BuglySymbolManifest manifest = new BuglySymbolManifest + { + productName = profile.productName, + bundleIdentifier = profile.bundleIdentifier, + version = profile.version, + buildNumber = profile.buildNumber, + buildOutputPath = buildOutputPath, + buildOutputSha256 = File.Exists(buildOutputPath) ? GetSHA256Hash(buildOutputPath) : string.Empty, + nativeSymbolPath = result.nativeSymbolPath, + nativeSymbolSha256 = File.Exists(result.nativeSymbolPath) ? GetSHA256Hash(result.nativeSymbolPath) : string.Empty, + mappingPath = result.mappingPath, + mappingSha256 = File.Exists(result.mappingPath) ? GetSHA256Hash(result.mappingPath) : string.Empty, + createdAt = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + }; + + string manifestPath = Path.Combine(archiveDirectory, "bugly-symbol-manifest.json"); + File.WriteAllText(manifestPath, JsonUtility.ToJson(manifest, true), Encoding.UTF8); + return manifestPath; + } + + private static string CreatePackage(string archiveDirectory, string packagePath) + { + if (File.Exists(packagePath)) + { + File.Delete(packagePath); + } + + ZipFile.CreateFromDirectory( + archiveDirectory, + packagePath, + System.IO.Compression.CompressionLevel.Optimal, + false); + return packagePath; + } + + private static BuglySymbolArchiveResult PrepareUploadInputs(BuildProfile profile, BuglySymbolArchiveResult archive, LogHandler log) + { + string stagingRoot = Path.Combine(GetProjectRoot(), UploadStagingDirectory.Replace("/", Path.DirectorySeparatorChar.ToString())); + string stagingDirectory = Path.Combine(stagingRoot, BuildSafeStagingName(profile) + "_" + DateTime.Now.ToString("yyyyMMddHHmmss")); + Directory.CreateDirectory(stagingDirectory); + + BuglySymbolArchiveResult uploadArchive = new BuglySymbolArchiveResult + { + hasSymbols = archive.hasSymbols, + archiveDirectory = archive.archiveDirectory, + packagePath = archive.packagePath, + manifestPath = archive.manifestPath, + message = archive.message + }; + + if (File.Exists(archive.nativeSymbolPath)) + { + string symbolDirectory = Path.Combine(stagingDirectory, "symbols"); + Directory.CreateDirectory(symbolDirectory); + ZipFile.ExtractToDirectory(archive.nativeSymbolPath, symbolDirectory); + uploadArchive.nativeSymbolPath = symbolDirectory; + WriteLog(log, $"已解压 Bugly SO 符号表到英文临时目录:{symbolDirectory}"); + } + + if (File.Exists(archive.mappingPath)) + { + uploadArchive.mappingPath = Path.Combine(stagingDirectory, "mapping.txt"); + File.Copy(archive.mappingPath, uploadArchive.mappingPath, true); + } + + return uploadArchive; + } + + private static string BuildSafeStagingName(BuildProfile profile) + { + string rawName = profile == null ? "bugly" : profile.profileName + "_" + profile.version + "_" + profile.buildNumber; + StringBuilder builder = new StringBuilder(rawName.Length); + foreach (char ch in rawName) + { + builder.Append(char.IsLetterOrDigit(ch) || ch == '_' || ch == '-' || ch == '.' ? ch : '_'); + } + + return builder.ToString(); + } + + private static string WriteUploadLog(string archiveDirectory, BuglySymbolUploadResult result) + { + string logDirectory = Directory.Exists(archiveDirectory) ? archiveDirectory : GetProjectRoot(); + string logPath = Path.Combine(logDirectory, "bugly-symbol-upload.log"); + File.WriteAllText( + logPath, + $"Time: {DateTime.Now:yyyy-MM-dd HH:mm:ss}\nCommand: {result.command}\nExitCode: {result.exitCode}\n--- Output ---\n{result.output}\n--- Error ---\n{result.error}", + Encoding.UTF8); + return logPath; + } + + private static BuglySymbolUploadResult FailUpload(string message, LogHandler log) + { + WriteLog(log, message, LogType.Error); + return new BuglySymbolUploadResult + { + success = false, + exitCode = -1, + error = message + }; + } + + private static bool PathExists(string path) + { + return File.Exists(path) || Directory.Exists(path); + } + + private static Encoding GetBuglyToolOutputEncoding() + { + try + { + return Encoding.GetEncoding("GB18030"); + } + catch + { + return Encoding.Default; + } + } + + private static bool IsBuglyUploadOutputSuccessful(string output, string error) + { + string combinedText = (output ?? string.Empty) + "\n" + (error ?? string.Empty); + return combinedText.IndexOf("plugin execute result status: failure", StringComparison.OrdinalIgnoreCase) < 0 && + combinedText.IndexOf("event_res:failure", StringComparison.OrdinalIgnoreCase) < 0 && + combinedText.IndexOf("##[error]", StringComparison.OrdinalIgnoreCase) < 0 && + combinedText.IndexOf("errorMsg is", StringComparison.OrdinalIgnoreCase) < 0; + } + + private static string ResolveFullPath(string path) + { + if (string.IsNullOrWhiteSpace(path)) + { + return string.Empty; + } + + string normalizedPath = path.Replace("{inproject}: ", string.Empty); + return Path.IsPathRooted(normalizedPath) + ? Path.GetFullPath(normalizedPath) + : Path.GetFullPath(Path.Combine(GetProjectRoot(), normalizedPath)); + } + + private static string GetProjectRoot() + { + return Directory.GetParent(Application.dataPath).FullName; + } + + private static string Quote(string value) + { + return string.IsNullOrEmpty(value) ? "\"\"" : "\"" + value.Replace("\"", "\\\"") + "\""; + } + + private static string MaskUploadArguments(string arguments) + { + return MaskArgumentValue(arguments, "-appkey"); + } + + private static string MaskArgumentValue(string arguments, string key) + { + int keyIndex = arguments.IndexOf(key, StringComparison.OrdinalIgnoreCase); + if (keyIndex < 0) + { + return arguments; + } + + int valueStart = keyIndex + key.Length; + while (valueStart < arguments.Length && char.IsWhiteSpace(arguments[valueStart])) + { + valueStart++; + } + + if (valueStart >= arguments.Length) + { + return arguments; + } + + int tokenEnd = valueStart; + if (arguments[valueStart] == '"') + { + tokenEnd = arguments.IndexOf('"', valueStart + 1); + return tokenEnd > valueStart + ? arguments.Substring(0, valueStart + 1) + "******" + arguments.Substring(tokenEnd) + : arguments; + } + + while (tokenEnd < arguments.Length && !char.IsWhiteSpace(arguments[tokenEnd])) + { + tokenEnd++; + } + + return arguments.Substring(0, valueStart) + "******" + arguments.Substring(tokenEnd); + } + + private static string GetSHA256Hash(string filePath) + { + using (SHA256 sha256 = SHA256.Create()) + using (FileStream stream = File.OpenRead(filePath)) + { + return BitConverter.ToString(sha256.ComputeHash(stream)).Replace("-", "").ToLowerInvariant(); + } + } + + private static void WriteLog(LogHandler log, string message, LogType type = LogType.Log) + { + if (log != null) + { + log(message, type); + return; + } + + switch (type) + { + case LogType.Error: + case LogType.Exception: + Debug.LogError(message); + break; + case LogType.Warning: + Debug.LogWarning(message); + break; + default: + Debug.Log(message); + break; + } + } + } + + [Serializable] + public class BuglySymbolArchiveResult + { + public bool hasSymbols; + public string archiveDirectory; + public string packagePath; + public string nativeSymbolPath; + public string mappingPath; + public string manifestPath; + public string message; + } + + [Serializable] + public class BuglySymbolUploadResult + { + public bool success; + public int exitCode; + public string command; + public string output; + public string error; + public string logPath; + } + + [Serializable] + public class BuglySymbolManifest + { + public string productName; + public string bundleIdentifier; + public string version; + public int buildNumber; + public string buildOutputPath; + public string buildOutputSha256; + public string nativeSymbolPath; + public string nativeSymbolSha256; + public string mappingPath; + public string mappingSha256; + public string createdAt; + } +} diff --git a/Editor/BuglyAndroidSymbolUtility.cs.meta b/Editor/BuglyAndroidSymbolUtility.cs.meta new file mode 100644 index 0000000..057c15c --- /dev/null +++ b/Editor/BuglyAndroidSymbolUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ecfd0727debd42f7bde54f6b3d1f5f74 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/CrashPostProcessBuildIOS.cs b/Editor/CrashPostProcessBuildIOS.cs index 0f42421..a03bec2 100644 --- a/Editor/CrashPostProcessBuildIOS.cs +++ b/Editor/CrashPostProcessBuildIOS.cs @@ -2,6 +2,7 @@ using System; using System.IO; +using CCFramework.CrashReport.Editor; using UnityEditor; using UnityEditor.Callbacks; using UnityEngine; @@ -10,7 +11,6 @@ namespace Editor { public static class CrashPostProcessBuildIOS { - private const string PodLine = " pod 'Bugly', '~> 2.6'"; private const string UnityFrameworkTarget = "target 'UnityFramework' do"; [PostProcessBuild(980)] @@ -21,13 +21,21 @@ namespace Editor return; } - EnsureBuglyPod(pathToBuiltProject); + CrashReportBuglyProfileSettings settings = CrashReportBuildSettingsStore.GetLastBuildProfileSettings(); + if (settings == null || !settings.enableIOSPod) + { + return; + } + + EnsureBuglyPod(pathToBuiltProject, settings.iosPodVersion); } - private static void EnsureBuglyPod(string pathToBuiltProject) + public static void EnsureBuglyPod(string pathToBuiltProject, string podVersion) { string podfilePath = Path.Combine(pathToBuiltProject, "Podfile"); string content = File.Exists(podfilePath) ? File.ReadAllText(podfilePath) : string.Empty; + string normalizedVersion = string.IsNullOrWhiteSpace(podVersion) ? "~> 2.6" : podVersion.Trim(); + string podLine = $" pod 'Bugly', '{normalizedVersion}'"; if (content.Contains("pod 'Bugly'") || content.Contains("pod \"Bugly\"")) { @@ -40,12 +48,12 @@ namespace Editor "platform :ios, '9.0'" + Environment.NewLine + Environment.NewLine + UnityFrameworkTarget + Environment.NewLine + - PodLine + Environment.NewLine + + podLine + Environment.NewLine + "end" + Environment.NewLine); } else if (content.Contains(UnityFrameworkTarget)) { - content = content.Replace(UnityFrameworkTarget, UnityFrameworkTarget + Environment.NewLine + PodLine); + content = content.Replace(UnityFrameworkTarget, UnityFrameworkTarget + Environment.NewLine + podLine); File.WriteAllText(podfilePath, content); } else @@ -53,11 +61,11 @@ namespace Editor File.AppendAllText(podfilePath, Environment.NewLine + UnityFrameworkTarget + Environment.NewLine + - PodLine + Environment.NewLine + + podLine + Environment.NewLine + "end" + Environment.NewLine); } - Debug.Log("CrashReport iOS 已写入 Bugly CocoaPods 依赖,请在 Xcode 构建前执行 pod install。"); + Debug.Log($"CrashReport iOS 已写入 Bugly CocoaPods 依赖({normalizedVersion}),请在 Xcode 构建前执行 pod install。"); } } } diff --git a/Editor/CrashReportBuildExtension.cs b/Editor/CrashReportBuildExtension.cs new file mode 100644 index 0000000..917fb4a --- /dev/null +++ b/Editor/CrashReportBuildExtension.cs @@ -0,0 +1,481 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using Runtime; +using UnityEditor; +using UnityEngine; +using Debug = UnityEngine.Debug; + +namespace CCFramework.CrashReport.Editor +{ + [InitializeOnLoad] + public static class CrashReportBuildExtensionBootstrap + { + static CrashReportBuildExtensionBootstrap() + { + BuildWindowExtensionRegistry.Register(new CrashReportBuildExtension()); + } + } + + public sealed class CrashReportBuildExtension : IBuildWindowExtension + { + public string Id => "ccframework.crashreport.bugly"; + public string DisplayName => "Crash/Bugly"; + public int Order => 50; + + public bool IsEnabled(BuildWindowExtensionContext context) + { + BuildProfile profile = context?.profile; + return profile != null && (IsAndroidProfile(profile) || IsIOSProfile(profile)); + } + + public void DrawSection(BuildWindowExtensionContext context) + { + BuildProfile profile = context?.profile; + if (profile == null) + { + EditorGUILayout.HelpBox("当前没有构建配置。", MessageType.Info); + return; + } + + CrashReportBuildSettings settings = CrashReportBuildSettingsStore.Load(); + CrashReportBuglyProfileSettings profileSettings = + CrashReportBuildSettingsStore.GetProfileSettings(settings, profile.profileName); + bool migrated = TryMigrateLegacyProfileSettings(profile, profileSettings); + CrashReportBuildSettingsStore.Normalize(profileSettings); + if (migrated) + { + CrashReportBuildSettingsStore.Save(settings); + } + + EditorGUI.BeginChangeCheck(); + DrawRuntimeCrashConfig(); + EditorGUILayout.Space(8); + + if (IsAndroidProfile(profile)) + { + DrawAndroidSection(profile, profileSettings); + } + else if (IsIOSProfile(profile)) + { + DrawIOSSection(profileSettings); + } + + if (EditorGUI.EndChangeCheck()) + { + CrashReportBuildSettingsStore.Normalize(profileSettings); + CrashReportBuildSettingsStore.Save(settings); + AssetDatabase.SaveAssets(); + } + } + + public BuildWindowExtensionReport Preflight(BuildWindowExtensionContext context) + { + BuildProfile profile = context?.profile; + if (profile == null) + { + return BuildWindowExtensionReport.Pass(); + } + + CrashReportBuildSettings settings = CrashReportBuildSettingsStore.Load(); + settings.lastBuildProfileName = profile.profileName; + CrashReportBuglyProfileSettings profileSettings = + CrashReportBuildSettingsStore.GetProfileSettings(settings, profile.profileName); + TryMigrateLegacyProfileSettings(profile, profileSettings); + CrashReportBuildSettingsStore.Normalize(profileSettings); + CrashReportBuildSettingsStore.Save(settings); + + if (IsAndroidProfile(profile)) + { + BuglyAndroidSymbolUtility.ApplyAndroidSymbolSettings(profile, profileSettings, WriteLog); + return profileSettings.enableAndroidSymbolArchive + ? BuildWindowExtensionReport.Pass().AddMessage("Bugly Android 符号表生成已启用。") + : BuildWindowExtensionReport.Pass(); + } + + if (IsIOSProfile(profile) && profileSettings.enableIOSPod) + { + return BuildWindowExtensionReport.Pass().AddMessage("Bugly iOS Pod 注入已启用。"); + } + + return BuildWindowExtensionReport.Pass(); + } + + public BuildWindowExtensionReport PostBuild(BuildWindowExtensionContext context) + { + BuildProfile profile = context?.profile; + if (profile == null || !context.lastBuildSuccess) + { + return BuildWindowExtensionReport.Pass(); + } + + CrashReportBuildSettings settings = CrashReportBuildSettingsStore.Load(); + CrashReportBuglyProfileSettings profileSettings = + CrashReportBuildSettingsStore.GetProfileSettings(settings, profile.profileName); + CrashReportBuildSettingsStore.Normalize(profileSettings); + + if (IsAndroidProfile(profile)) + { + return PostBuildAndroid(profile, profileSettings, context.lastBuildOutputPath); + } + + if (IsIOSProfile(profile)) + { + return PostBuildIOS(profileSettings, context.lastBuildOutputPath); + } + + return BuildWindowExtensionReport.Pass(); + } + + private static void DrawRuntimeCrashConfig() + { + EditorGUILayout.LabelField("运行时上报配置", EditorStyles.boldLabel); + SerializedObject serializedObject = GetCrashConfigSerializedObject(); + if (serializedObject == null) + { + EditorGUILayout.HelpBox("未找到 CrashConfig.asset。", MessageType.Warning); + return; + } + + serializedObject.Update(); + EditorGUILayout.PropertyField(serializedObject.FindProperty("EnableCrashReport"), new GUIContent("启用上报")); + EditorGUILayout.PropertyField(serializedObject.FindProperty("HasDebugMode"), new GUIContent("Debug日志")); + EditorGUILayout.PropertyField(serializedObject.FindProperty("BuglyAppID"), new GUIContent("Bugly App ID")); + EditorGUILayout.PropertyField(serializedObject.FindProperty("BuglyChannel"), new GUIContent("Bugly Channel")); + serializedObject.ApplyModifiedProperties(); + } + + private static void DrawAndroidSection(BuildProfile profile, CrashReportBuglyProfileSettings settings) + { + EditorGUILayout.LabelField("Bugly Android 符号表", EditorStyles.boldLabel); + settings.enableAndroidSymbolArchive = EditorGUILayout.Toggle("构建后整理符号表", settings.enableAndroidSymbolArchive); + settings.androidAutoUploadSymbols = EditorGUILayout.Toggle("构建后自动上传", settings.androidAutoUploadSymbols); + settings.buglyAppId = EditorGUILayout.TextField("Bugly App ID", settings.buglyAppId ?? string.Empty); + settings.buglyAppKey = EditorGUILayout.PasswordField("Bugly App Key", settings.buglyAppKey ?? string.Empty); + settings.buglySymbolToolPath = EditorGUILayout.TextField("符号表工具 Jar", settings.buglySymbolToolPath ?? string.Empty); + settings.buglyJavaPath = EditorGUILayout.TextField("Java 命令", string.IsNullOrWhiteSpace(settings.buglyJavaPath) ? "java" : settings.buglyJavaPath); + + string resolvedToolPath = BuglyAndroidSymbolUtility.ResolveSymbolToolPath(settings); + EditorGUILayout.LabelField("实际工具路径", string.IsNullOrEmpty(resolvedToolPath) ? "未找到" : resolvedToolPath); + + using (new EditorGUILayout.HorizontalScope()) + { + if (GUILayout.Button("下载 Zip", GUILayout.Width(100))) + { + Application.OpenURL(BuglyAndroidSymbolUtility.BuglyDownloadUrl); + } + + if (GUILayout.Button("打开说明", GUILayout.Width(100))) + { + Application.OpenURL(BuglyAndroidSymbolUtility.BuglyToolGuideUrl); + } + + if (GUILayout.Button("选择 Jar", GUILayout.Width(100))) + { + SelectBuglySymbolTool(settings); + GUI.changed = true; + } + } + + using (new EditorGUILayout.HorizontalScope()) + { + GUILayout.FlexibleSpace(); + if (GUILayout.Button("复制命令", GUILayout.Width(100))) + { + EditorGUIUtility.systemCopyBuffer = + BuglyAndroidSymbolUtility.BuildUploadCommandTemplate(profile, settings, false); + Debug.Log("Bugly 符号表上传命令已复制到剪贴板。"); + } + } + + EditorGUILayout.LabelField("上传命令模板"); + EditorGUILayout.TextArea(BuglyAndroidSymbolUtility.BuildUploadCommandTemplate(profile, settings, true), GUILayout.Height(76)); + } + + private static void DrawIOSSection(CrashReportBuglyProfileSettings settings) + { + EditorGUILayout.LabelField("Bugly iOS CocoaPods", EditorStyles.boldLabel); + settings.enableIOSPod = EditorGUILayout.Toggle("注入 Bugly Pod", settings.enableIOSPod); + settings.iosPodVersion = EditorGUILayout.TextField("Pod 版本", string.IsNullOrWhiteSpace(settings.iosPodVersion) ? "~> 2.6" : settings.iosPodVersion); + settings.iosRunPodInstall = EditorGUILayout.Toggle("构建后执行 pod install", settings.iosRunPodInstall); + settings.podExecutablePath = EditorGUILayout.TextField("Pod 命令", string.IsNullOrWhiteSpace(settings.podExecutablePath) ? "pod" : settings.podExecutablePath); + EditorGUILayout.HelpBox("iOS 原生桥由 CrashReport 包提供;证书签名由基础构建页的 iOS 设置写入 Xcode 工程。", MessageType.Info); + } + + private static BuildWindowExtensionReport PostBuildAndroid( + BuildProfile profile, + CrashReportBuglyProfileSettings settings, + string buildOutputPath) + { + if (settings == null || !settings.enableAndroidSymbolArchive) + { + return BuildWindowExtensionReport.Pass(); + } + + if (string.IsNullOrWhiteSpace(buildOutputPath)) + { + buildOutputPath = BuildPipelineCore.GetExpectedBuildOutputPath(profile); + } + + BuglySymbolArchiveResult archive = + BuglyAndroidSymbolUtility.ArchiveAfterBuild(profile, settings, buildOutputPath, WriteLog); + if (settings.androidAutoUploadSymbols) + { + BuglySymbolUploadResult upload = + BuglyAndroidSymbolUtility.UploadPreparedSymbols(profile, settings, archive, WriteLog); + return upload != null && upload.success + ? BuildWindowExtensionReport.Pass().AddMessage("Bugly 符号表已归档并上传。") + : BuildWindowExtensionReport.Pass().AddWarning("Bugly 符号表已归档,但上传未成功,请查看日志。"); + } + + return BuildWindowExtensionReport.Pass().AddMessage("Bugly 符号表已归档。"); + } + + private static BuildWindowExtensionReport PostBuildIOS(CrashReportBuglyProfileSettings settings, string xcodeProjectPath) + { + if (settings == null || !settings.enableIOSPod || !settings.iosRunPodInstall) + { + return BuildWindowExtensionReport.Pass(); + } + + if (string.IsNullOrWhiteSpace(xcodeProjectPath) || !Directory.Exists(xcodeProjectPath)) + { + return BuildWindowExtensionReport.Pass().AddWarning("未找到 iOS Xcode 工程目录,已跳过 pod install。"); + } + + return RunPodInstall(settings, xcodeProjectPath) + ? BuildWindowExtensionReport.Pass().AddMessage("pod install 执行完成。") + : BuildWindowExtensionReport.Pass().AddWarning("pod install 未成功,请查看 Unity Console 日志。"); + } + + private static bool RunPodInstall(CrashReportBuglyProfileSettings settings, string xcodeProjectPath) + { + string podCommand = string.IsNullOrWhiteSpace(settings.podExecutablePath) ? "pod" : settings.podExecutablePath; + ProcessStartInfo startInfo = new ProcessStartInfo + { + FileName = podCommand, + Arguments = "install", + WorkingDirectory = xcodeProjectPath, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true + }; + + try + { + using (Process process = Process.Start(startInfo)) + { + string output = process.StandardOutput.ReadToEnd(); + string error = process.StandardError.ReadToEnd(); + process.WaitForExit(); + if (!string.IsNullOrWhiteSpace(output)) + { + Debug.Log(output); + } + + if (!string.IsNullOrWhiteSpace(error)) + { + Debug.LogWarning(error); + } + + return process.ExitCode == 0; + } + } + catch (Exception e) + { + Debug.LogWarning($"[CrashReport] 执行 pod install 失败:{e.Message}"); + return false; + } + } + + private static SerializedObject GetCrashConfigSerializedObject() + { + const string path = "Assets/Resources"; + const string assetPath = "Assets/Resources/CrashConfig.asset"; + CrashConfig config = AssetDatabase.LoadAssetAtPath(assetPath); + if (config == null) + { + if (!Directory.Exists(path)) + { + Directory.CreateDirectory(path); + } + + config = ScriptableObject.CreateInstance(); + AssetDatabase.CreateAsset(config, assetPath); + AssetDatabase.Refresh(); + } + + return config == null ? null : new SerializedObject(config); + } + + private static bool TryMigrateLegacyProfileSettings( + BuildProfile profile, + CrashReportBuglyProfileSettings settings) + { + if (profile == null || settings == null) + { + return false; + } + + bool changed = false; + + if (!settings.enableAndroidSymbolArchive && profile.enableBuglySymbolArchive) + { + settings.enableAndroidSymbolArchive = true; + changed = true; + } + + if (!settings.androidAutoUploadSymbols && profile.buglyAutoUploadSymbols) + { + settings.androidAutoUploadSymbols = true; + changed = true; + } + + if (string.IsNullOrWhiteSpace(settings.buglyAppId) && + !string.IsNullOrWhiteSpace(profile.buglyAppId)) + { + settings.buglyAppId = profile.buglyAppId; + changed = true; + } + + if (string.IsNullOrWhiteSpace(settings.buglyAppKey) && + !string.IsNullOrWhiteSpace(profile.buglyAppKey)) + { + settings.buglyAppKey = profile.buglyAppKey; + changed = true; + } + + if (IsDefaultSymbolToolPath(settings.buglySymbolToolPath) && + !string.IsNullOrWhiteSpace(profile.buglySymbolToolPath)) + { + settings.buglySymbolToolPath = profile.buglySymbolToolPath; + changed = true; + } + + if (string.Equals(settings.buglyJavaPath, "java", StringComparison.Ordinal) && + !string.IsNullOrWhiteSpace(profile.buglyJavaPath) && + !string.Equals(profile.buglyJavaPath, "java", StringComparison.Ordinal)) + { + settings.buglyJavaPath = profile.buglyJavaPath; + changed = true; + } + + return changed; + } + + private static bool IsDefaultSymbolToolPath(string value) + { + return string.IsNullOrWhiteSpace(value) || + string.Equals(value, "Tools/BuglySymbolTool/buglyqq-upload-symbol.jar", StringComparison.OrdinalIgnoreCase); + } + + private static bool IsAndroidProfile(BuildProfile profile) + { + return string.Equals(ResolveProfilePlatformName(profile), "Android", StringComparison.OrdinalIgnoreCase); + } + + private static bool IsIOSProfile(BuildProfile profile) + { + string platformName = ResolveProfilePlatformName(profile); + return string.Equals(platformName, "iOS", StringComparison.OrdinalIgnoreCase) || + string.Equals(platformName, "iPhone", StringComparison.OrdinalIgnoreCase); + } + + private static string ResolveProfilePlatformName(BuildProfile profile) + { + if (profile == null) + { + return string.Empty; + } + + Type profileType = profile.GetType(); + string targetPlatform = GetStringField(profileType, profile, "targetPlatform"); + string buildTargetGroup = GetStringField(profileType, profile, "buildTargetGroup"); + string buildTarget = GetStringField(profileType, profile, "buildTarget"); + bool hasExplicitPlatformValue = + !string.IsNullOrWhiteSpace(targetPlatform) || + !string.IsNullOrWhiteSpace(buildTargetGroup) || + !string.IsNullOrWhiteSpace(buildTarget); + + if (IsPlatformValue(targetPlatform, "iOS", "iPhone") || + IsPlatformValue(buildTargetGroup, "iOS") || + IsPlatformValue(buildTarget, "iOS", "iPhone")) + { + return "iOS"; + } + + if (IsPlatformValue(targetPlatform, "Android") || + IsPlatformValue(buildTargetGroup, "Android") || + IsPlatformValue(buildTarget, "Android")) + { + return "Android"; + } + + if (hasExplicitPlatformValue) + { + return string.Empty; + } + + if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.iOS) + { + return "iOS"; + } + + return EditorUserBuildSettings.activeBuildTarget == BuildTarget.Android ? "Android" : string.Empty; + } + + private static string GetStringField(Type ownerType, object instance, string fieldName) + { + FieldInfo field = ownerType.GetField(fieldName, BindingFlags.Public | BindingFlags.Instance); + return field?.GetValue(instance) as string ?? string.Empty; + } + + private static bool IsPlatformValue(string value, params string[] expectedValues) + { + if (string.IsNullOrWhiteSpace(value)) + { + return false; + } + + foreach (string expectedValue in expectedValues) + { + if (string.Equals(value, expectedValue, StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + + return false; + } + + private static void SelectBuglySymbolTool(CrashReportBuglyProfileSettings settings) + { + string selectedPath = EditorUtility.OpenFilePanel("选择 Bugly 符号表工具", Application.dataPath, "jar"); + if (string.IsNullOrEmpty(selectedPath)) + { + return; + } + + settings.buglySymbolToolPath = BuglyAndroidSymbolUtility.ToProfilePath(selectedPath); + } + + private static void WriteLog(string message, LogType type = LogType.Log) + { + switch (type) + { + case LogType.Error: + case LogType.Exception: + Debug.LogError(message); + break; + case LogType.Warning: + Debug.LogWarning(message); + break; + default: + Debug.Log(message); + break; + } + } + } +} diff --git a/Editor/CrashReportBuildExtension.cs.meta b/Editor/CrashReportBuildExtension.cs.meta new file mode 100644 index 0000000..081ade9 --- /dev/null +++ b/Editor/CrashReportBuildExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2b8fdf55210d41f6906198c6f5e3901b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/CrashReportBuildSettings.cs b/Editor/CrashReportBuildSettings.cs new file mode 100644 index 0000000..cdcf2c3 --- /dev/null +++ b/Editor/CrashReportBuildSettings.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.IO; +using UnityEngine; + +namespace CCFramework.CrashReport.Editor +{ + [Serializable] + public sealed class CrashReportBuildSettings + { + public string lastBuildProfileName = string.Empty; + public List profiles = new List(); + } + + [Serializable] + public sealed class CrashReportBuglyProfileSettings + { + public string profileName = "default"; + public bool enableAndroidSymbolArchive = true; + public bool androidAutoUploadSymbols = false; + public string buglyAppId = string.Empty; + public string buglyAppKey = string.Empty; + public string buglySymbolToolPath = "Tools/BuglySymbolTool/buglyqq-upload-symbol.jar"; + public string buglyJavaPath = "java"; + public bool enableIOSPod = true; + public string iosPodVersion = "~> 2.6"; + public bool iosRunPodInstall = false; + public string podExecutablePath = "pod"; + } + + public static class CrashReportBuildSettingsStore + { + private const string SettingsDirectory = "ProjectSettings/CrashReport"; + private const string SettingsFileName = "crashreport-build-settings.json"; + + public static string SettingsPath => Path.Combine(SettingsDirectory, SettingsFileName); + + public static CrashReportBuildSettings Load() + { + if (!File.Exists(SettingsPath)) + { + return new CrashReportBuildSettings(); + } + + try + { + string json = File.ReadAllText(SettingsPath); + CrashReportBuildSettings settings = JsonUtility.FromJson(json); + return settings ?? new CrashReportBuildSettings(); + } + catch (Exception e) + { + Debug.LogWarning($"[CrashReport] 构建配置读取失败,将使用默认配置:{e.Message}"); + return new CrashReportBuildSettings(); + } + } + + public static void Save(CrashReportBuildSettings settings) + { + if (!Directory.Exists(SettingsDirectory)) + { + Directory.CreateDirectory(SettingsDirectory); + } + + File.WriteAllText(SettingsPath, JsonUtility.ToJson(settings ?? new CrashReportBuildSettings(), true)); + } + + public static CrashReportBuglyProfileSettings GetProfileSettings(CrashReportBuildSettings settings, string profileName) + { + settings = settings ?? new CrashReportBuildSettings(); + string key = string.IsNullOrWhiteSpace(profileName) ? "default" : profileName; + + foreach (CrashReportBuglyProfileSettings profileSettings in settings.profiles) + { + if (profileSettings != null && string.Equals(profileSettings.profileName, key, StringComparison.Ordinal)) + { + Normalize(profileSettings); + return profileSettings; + } + } + + CrashReportBuglyProfileSettings created = new CrashReportBuglyProfileSettings + { + profileName = key + }; + Normalize(created); + settings.profiles.Add(created); + return created; + } + + public static CrashReportBuglyProfileSettings GetLastBuildProfileSettings() + { + CrashReportBuildSettings settings = Load(); + return GetProfileSettings(settings, settings.lastBuildProfileName); + } + + public static void Normalize(CrashReportBuglyProfileSettings settings) + { + if (settings == null) + { + return; + } + + if (string.IsNullOrWhiteSpace(settings.profileName)) + { + settings.profileName = "default"; + } + + if (string.IsNullOrWhiteSpace(settings.buglyJavaPath)) + { + settings.buglyJavaPath = "java"; + } + + if (string.IsNullOrWhiteSpace(settings.buglySymbolToolPath)) + { + settings.buglySymbolToolPath = "Tools/BuglySymbolTool/buglyqq-upload-symbol.jar"; + } + + if (string.IsNullOrWhiteSpace(settings.iosPodVersion)) + { + settings.iosPodVersion = "~> 2.6"; + } + + if (string.IsNullOrWhiteSpace(settings.podExecutablePath)) + { + settings.podExecutablePath = "pod"; + } + } + } +} diff --git a/Editor/CrashReportBuildSettings.cs.meta b/Editor/CrashReportBuildSettings.cs.meta new file mode 100644 index 0000000..68fdf91 --- /dev/null +++ b/Editor/CrashReportBuildSettings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bcb8cf0a589747d490149a0769a07a42 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package.json b/package.json index 5a23439..b25a7c1 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "com.foldcc.cc-framework.crashreport", "displayName": "CC-Framework.CrashReport", "description": "Crash检测, 异常上报", - "version": "1.0.3", + "version": "1.0.4", "unity": "2022.3", "license": "MIT", "repository": { @@ -16,6 +16,7 @@ }, "dependencies": { + "com.foldcc.cc-framework.common": "1.0.5" }, "keywords": [ "Framework"