using System; using System.Collections; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; using UnityEngine; #if UNITY_STANDALONE_WIN enum DumpCommandType { enumDump_Begin = 0, enumDump_BackgroundExecutionFlag = enumDump_Begin, // 后台上传宕机信息(不显示DumpReport界面) enumDump_ForceUpload, // Dump是否强制上报(忽略玩家在DumpReport界面上的选择) enumDump_LogDirectory, // 设置log文件路径 enumDump_CollectFile, // 设置需收集的文件名 enumDump_LogDirectory_UTF8, // 设置log文件路径(传入参数为UTF8,Unity/UE 使用此参数) enumDump_CollectFile_UTF8, // 设置需收集的文件名(传入参数为UTF8,Unity/UE 使用此参数) enumDump_SetURL, // 设置上传url (internal_cn|internal_us|external|test) => (国内|海外|外部项目|内部测试) enumDump_SetBeta, // 设置 beta enumDump_SetUserIdentifier, // 设置 UserIdentifier enumDump_SetUserIdentifier_UTF8, enumDump_AddExtraData, // 添加额外数据 enumDump_AddExtraData_UTF8, // 添加额外数据(传入参数为UTF8,Unity/UE 使用此参数) enumDump_leaveBreadcrumbType, // 设置面包屑传入字符串的格式 enumDump_GM_TEST, // GM测试指令 enumDump_Count } public class DumpForPC : MonoBehaviour { private static IntPtr StringToCharPtr(string s) { return Marshal.StringToHGlobalUni(s); } private static string YourAppVersion = "NA"; [DllImport("Crasheye64")] private static extern bool InitDumperCrasheye(string appkey, string version, string channId); [DllImport("Crasheye64")] private static extern void UnInitDumper(); [DllImport("Crasheye64")] private static extern bool SetConfig(int nDumpCommandType, IntPtr pArg); public static void SetForceUpload(bool isForceUpload) { IntPtr pBool = Marshal.AllocHGlobal(1); Marshal.WriteByte(pBool, Convert.ToByte(isForceUpload)); SetConfig((int)DumpCommandType.enumDump_ForceUpload, pBool); Marshal.FreeHGlobal(pBool); } [DllImport("Crasheye64")] private static extern bool SetConfig(int nDumpCommandType, IntPtr[] pArg); [DllImport("Crasheye64")] public static extern bool SendScriptException(string errorTitle, string stackTrace, string language); public static bool SetBackgroundUpload(bool isBackgroundUpload) { IntPtr pBool = Marshal.AllocHGlobal(1); Marshal.WriteByte(pBool, Convert.ToByte(isBackgroundUpload)); bool result = SetConfig((int)DumpCommandType.enumDump_BackgroundExecutionFlag, pBool); Marshal.FreeHGlobal(pBool); return result; } public delegate void FnOnCrashCallback(bool bCaptureSucceed, IntPtr cpszCrashReportFile); [DllImport("Crasheye64")] public static extern bool SetOnMiniDumpCreateCallBack(FnOnCrashCallback pCallback); [DllImport("Crasheye64", CharSet = CharSet.Unicode)] public static extern bool PushLogTrace([MarshalAs(UnmanagedType.LPStr)] string cpszMessage); [DllImport("Crasheye64", CharSet = CharSet.Unicode)] public static extern bool leaveBreadcrumb([MarshalAs(UnmanagedType.LPStr)] string cpszMessage); //AddExtraData专用参数 private static IntPtr[] extraData = new IntPtr[2]; /// /// Windows的初始化 /// /// 平台申请的当前应用 /// 应用的渠道号 public static void Init(string appKeyForPC,string channIdForPC) { try { bool res = InitDumperCrasheye(appKeyForPC, YourAppVersion, channIdForPC); } catch (Exception e) { Debug.LogError(e.Message); } } /// /// 反初始化 CrasheyeSdk /// 在程序正常退出时调用 /// public static void UnInit() { try { UnInitDumper(); } catch (Exception e) { Debug.LogError(e.Message); } } /// /// 设置上报路径. /// internal_cn => 国内自研项目 /// internal_us => 海外自研项目 /// external => 外部项目 /// 若不设置, 默认是 external /// 若要设置, 建议在 Init 之前调用. /// /// internal_cn/internal_us/external 三选一 public static void SetURL(string url) { if (String.IsNullOrEmpty(url)) { Debug.LogError("set url is null or empty!"); return; } var szLogDir = url.Replace("/", "\\"); IntPtr pLogDir = Marshal.StringToHGlobalAnsi(szLogDir); SetConfig((int)DumpCommandType.enumDump_SetURL, pLogDir); Marshal.FreeHGlobal(pLogDir); } /// /// 标记当前版本为调试版本. /// 若要设置, 建议在 Init 之前调用. /// public static void SetBeta() { try { IntPtr pLogDir = default; SetConfig((int)DumpCommandType.enumDump_SetBeta, pLogDir); } catch (Exception e) { Debug.LogError(e.Message); } } /// /// 设置用户id. /// /// 项目内部的用户id public static void SetUserIdentifier(string userIdentifier) { if (string.IsNullOrEmpty(userIdentifier)) { Debug.LogError("user identifier is null or empty!"); return; } try { var szUserIdentifier = userIdentifier.Replace("/", "\\"); IntPtr pUserIdentifier = Marshal.StringToHGlobalAnsi(szUserIdentifier); SetConfig((int)DumpCommandType.enumDump_SetUserIdentifier, pUserIdentifier); Marshal.FreeHGlobal(pUserIdentifier); } catch (Exception e) { Debug.LogError(e.Message); } } /// /// 设置用户id. /// /// 项目内部的用户id public static void SetUserIdentifier_UTF8(string userIdentifier) { if (string.IsNullOrEmpty(userIdentifier)) { Debug.LogError("user identifier is null or empty!"); return; } try { var szUserIdentifier = userIdentifier.Replace("/", "\\"); IntPtr pUserIdentifier = Marshal.StringToHGlobalAnsi(szUserIdentifier); SetConfig((int)DumpCommandType.enumDump_SetUserIdentifier_UTF8, pUserIdentifier); Marshal.FreeHGlobal(pUserIdentifier); } catch (Exception e) { Debug.LogError(e.Message); } } /// /// 添加自定义数据,额外上报信息. /// 以键值对的形式添加额外信息, 添加的信息会被包含着崩溃报告中随报告一同上报. /// /// Key /// Value public static void AddExtraData(string szKey,string szValue) { if (string.IsNullOrEmpty(szKey) || string.IsNullOrEmpty(szValue)) { Debug.LogError("AddExtraData szKey or szVanlue is null"); return; } try { extraData[0] = Marshal.StringToHGlobalAnsi(szKey); extraData[1] = Marshal.StringToHGlobalAnsi(szValue); SetConfig((int)DumpCommandType.enumDump_AddExtraData, extraData); Marshal.FreeHGlobal(extraData[0]); Marshal.FreeHGlobal(extraData[1]); } catch (Exception e) { Debug.LogError(e.Message); } } /// /// 添加自定义数据,额外上报信息. /// 以键值对的形式添加额外信息, 添加的信息会被包含着崩溃报告中随报告一同上报. /// /// Key /// Value public static void AddExtraDataUTF8(string szKey, string szValue) { if (string.IsNullOrEmpty(szKey) || string.IsNullOrEmpty(szValue)) { Debug.LogError("AddExtraData szKey or szVanlue is null"); return; } try { extraData[0] = Marshal.StringToHGlobalAnsi(szKey); extraData[1] = Marshal.StringToHGlobalAnsi(szValue); SetConfig((int)DumpCommandType.enumDump_AddExtraData_UTF8, extraData); Marshal.FreeHGlobal(extraData[0]); Marshal.FreeHGlobal(extraData[1]); } catch (Exception e) { Debug.LogError(e.Message); } } /// /// 添加额外上报日志(文件). /// 添加的文件会被包含着崩溃报告中随报告一同上报. /// /// 需要额外收集的文件 public static void AddCustomLog(string collectFile) { if (string.IsNullOrEmpty(collectFile)) { Debug.LogError("AddCustomLog collectFile is null or empty"); return; } try { var szCollectFile = collectFile.Replace("/", "\\"); Debug.Log(szCollectFile); IntPtr pCollectFile = Marshal.StringToHGlobalAnsi(szCollectFile); SetConfig((int)DumpCommandType.enumDump_CollectFile_UTF8, pCollectFile); Marshal.FreeHGlobal(pCollectFile); } catch (Exception e) { Debug.LogError(e.Message); } } /// /// 添加额外上报日志(目录). /// 添加的目录会被包含着崩溃报告中随报告一同上报. /// /// 需要额外收集的文件目录 public static void AddCustomLogDirectory(string CollectLogDirectory) { if (string.IsNullOrEmpty(CollectLogDirectory)) { Debug.LogError("AddCustomLog CollectLogDirectory is null or empty"); return; } try { var szCollectLogDirectory = CollectLogDirectory.Replace("/", "\\"); Debug.Log(szCollectLogDirectory); IntPtr pCollectLogDirectory = Marshal.StringToHGlobalAnsi(szCollectLogDirectory); SetConfig((int)DumpCommandType.enumDump_LogDirectory_UTF8, pCollectLogDirectory); Marshal.FreeHGlobal(pCollectLogDirectory); } catch (Exception e) { Debug.LogError(e.Message); } } /// /// 设置版本号信息 /// /// public static void SetAppVersion(string yourAppVersion) { if (yourAppVersion == null) { return; } YourAppVersion = yourAppVersion; } public static void SetBreadCrumbType(Int32 breadCrumbType) { IntPtr bCT = Marshal.AllocHGlobal(sizeof(Int32)); Marshal.WriteInt32(bCT, breadCrumbType); SetConfig((int)DumpCommandType.enumDump_leaveBreadcrumbType, bCT); Marshal.FreeHGlobal(bCT); } public static void OnHandleUnresolvedException(object sender, UnhandledExceptionEventArgs args) { Debug.Log(args.ExceptionObject.GetType()); if (args != null && args.ExceptionObject != null && typeof(Exception).IsInstanceOfType(args.ExceptionObject)) { Debug.Log("OnHandleUnresolvedException Ture"); Exception ex = (Exception)args.ExceptionObject; Debug.Log("C# error Source:" + ex.StackTrace); Debug.Log("C# error StackTrace:" + ex.StackTrace); LibSendScriptException(ex.Source, ex.StackTrace); } else { Debug.Log("OnHandleUnresolvedException False"); } } public static void LibSendScriptException(string error, string stack) { Debug.Log("LibSendScriptException"); bool res = SendScriptException(error, stack, "C#"); Debug.Log(res); } public static void OnHandleLogCallback(string logString, string stackTrace, LogType type) { Debug.Log("OnHandleLogCallback: type: " + type + "logString: " + logString); if (LogType.Assert == type || LogType.Exception == type) { LibSendScriptException(logString, stackTrace); } } } #endif