我正在考虑做一些Unity3D脚本的东西,我想设置全局异常处理系统.这不是在游戏的发布版本中运行,其目的是捕获用户脚本中的异常以及编辑器脚本中的异常,并确保将其转发到数据库进行分析(也可以向相关的开发人员发送电子邮件,以便他们可以解决他们的嘶嘶声).
在一个香草C#应用程序,我将有一个try-catch在Main方法.在WPF中我会挂钩一个或多个unhandled exception events.在Unity …?
到目前为止,我能够想到的最好的是这样的:
using UnityEngine; using System.Collections; public abstract class BehavIoUrBase : MonoBehavIoUr { // Use this for initialization void Start () { } // Update is called once per frame void Update () { try { performUpdate(); print("hello"); } catch (System.Exception e) { print(e.ToString()); } } public abstract void performUpdate(); }
在其他脚本中,我派生BehavIoUrBase而不是MonoBehavior,并执行performUpdate()而不是Update().我没有为Editor clases实现并行版本,但我认为我必须在这里做同样的事情.
不过,我不喜欢这个策略,因为我必须把它运送到我们从社区获取的任何脚本(我必须在团队中执行).编辑器脚本没有单个入口与MonoBehavior相当,所以我认为我必须实现异常安全版本的向导,编辑器等等.
我已经看到关于使用Application.RegisterLogCallback捕获日志消息(而不是例外)的建议,但这让我不舒服,因为我需要解析调试日志字符串,而不是访问实际的异常和堆栈跟踪.
那么什么是正确的事情呢?
解决方法
我在这里找到了RegisterLogCallback的一个工作实现:
http://answers.unity3d.com/questions/47659/callback-for-unhandled-exceptions.html
在我自己的实现中,我使用它来调用自己的MessageBox.Show而不是写入日志文件.我刚从每个场景调用SetupExceptionHandling.
static bool isExceptionHandlingSetup; public static void SetupExceptionHandling() { if (!isExceptionHandlingSetup) { isExceptionHandlingSetup = true; Application.RegisterLogCallback(HandleException); } } static void HandleException(string condition,string stackTrace,LogType type) { if (type == LogType.Exception) { MessageBox.Show(condition + "\n" + stackTrace); } }
我现在也有错误处理程序通过这个例程发送给我,所以我总是知道我的应用程序崩溃,尽可能多的细节.
internal static void ReportCrash(string message,string stack) { //Debug.Log("Report Crash"); var errorMessage = new StringBuilder(); errorMessage.AppendLine("FreeCell Quest " + Application.platform); errorMessage.AppendLine(); errorMessage.AppendLine(message); errorMessage.AppendLine(stack); //if (exception.InnerException != null) { // errorMessage.Append("\n\n ***INNER EXCEPTION*** \n"); // errorMessage.Append(exception.InnerException.ToString()); //} errorMessage.AppendFormat ( "{0} {1} {2} {3}\n{4},{5},{6},{7}x {8}\n{9}x{10} {11}dpi FullScreen {12},{13},{14} vmem: {15} Fill: {16} Max Texture: {17}\n\nScene {18},Unity Version {19},Ads Disabled {18}",SystemInfo.deviceModel,SystemInfo.deviceName,SystemInfo.deviceType,SystemInfo.deviceUniqueIdentifier,SystemInfo.operatingSystem,Localization.language,SystemInfo.systemMemorySize,SystemInfo.processorCount,SystemInfo.processorType,Screen.currentResolution.width,Screen.currentResolution.height,Screen.dpi,Screen.fullScreen,SystemInfo.graphicsDeviceName,SystemInfo.graphicsDeviceVendor,SystemInfo.graphicsMemorySize,SystemInfo.graphicsPixelFillrate,SystemInfo.maxTextureSize,Application.loadedLevelName,Application.unityVersion,GameSettings.AdsDisabled ); //if (Main.Player != null) { // errorMessage.Append("\n\n ***PLAYER*** \n"); // errorMessage.Append(XamlServices.Save(Main.Player)); //} try { using (var client = new WebClient()) { var arguments = new NameValueCollection(); //if (loginResult != null) // arguments.Add("SessionId",loginResult.SessionId.ToString()); arguments.Add("report",errorMessage.ToString()); var result = Encoding.ASCII.GetString(client.UploadValues(serviceAddress + "/ReportCrash",arguments)); //Debug.Log(result); } } catch (WebException e) { Debug.Log("Report Crash: " + e.ToString()); } }