环境
发布正式包时,Unity的原生Log肯定是要屏蔽的。最常用的做法就是自己封装一下,实现一个debug。不过这样的话,双击跳转就会去到Debug类里面去。为了方便查bug,实现一下日志跳转。
实现
看了一下网上的资料,思路应该就是通过类型实例化Console界面,得到Log具体数据。然后解析跳转。网上的实现步骤稍微复杂了一点。这里给出不到一百行代码,轻松实现功能。这个代码需要放到Editor目录下。
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text.RegularExpressions;
using UnityEditor;
public class LogEditor
{
private static LogEditor m_Instance;
public static LogEditor GetInstacne()
{
if (m_Instance == null)
{
m_Instance = new LogEditor();
} return m_Instance;
}
private const string DEBUGERFILEPATH = "Assets/Debuger/Debuger.cs";//替换成你自己的封装类地址
private int m_DebugerFileInstanceId;
private Type m_ConsoleWindowType = null;
private FieldInfo m_ActiveTextInfo;
private FieldInfo m_ConsoleWindowFileInfo;
private LogEditor()
{
UnityEngine. Object debuggerFile = AssetDatabase.LoadAssetAtPath(DEBUGERFILEPATH,typeof(UnityEngine.Object));
m_DebugerFileInstanceId = debuggerFile.GetInstanceID();
m_ConsoleWindowType = Type.GetType("UnityEditor.ConsoleWindow,UnityEditor");
m_ActiveTextInfo = m_ConsoleWindowType.GetField("m_ActiveText", BindingFlags.Instance | BindingFlags.NonPublic);
m_ConsoleWindowFileInfo = m_ConsoleWindowType.GetField("ms_ConsoleWindow", BindingFlags.Static | BindingFlags.NonPublic);
}
[UnityEditor.Callbacks.OnOpenAssetAttribute(-1)]
private static bool OnOpenAsset(int instanceID, int line)
{
if (instanceID == LogEditor.GetInstacne().m_DebugerFileInstanceId)
{
return LogEditor.GetInstacne().FindCode();
}
return false;
}
public bool FindCode()
{
var windowInstance = m_ConsoleWindowFileInfo.GetValue(null);
var activeText = m_ActiveTextInfo.GetValue(windowInstance);
string[] contentStrings = activeText.ToString().Split('\n');
List<string> filePath = new List<string>();
for (int index = 0; index < contentStrings.Length; index++)
{
if (contentStrings[index].Contains("at"))
{
filePath.Add(contentStrings[index]);
}
} bool success = PingAndOpen(filePath[1]);
return success;
}
public bool PingAndOpen(string fileContext)
{
string regexRule = @"at ([\w\W]*):(\d+)\)";
Match match = Regex.Match(fileContext, regexRule);
if (match.Groups.Count > 1)
{
string path = match.Groups[1].Value;
string line = match.Groups[2].Value;
UnityEngine.Object codeObject = AssetDatabase.LoadAssetAtPath(path, typeof(UnityEngine.Object));
if (codeObject == null)
{
return false;
}
EditorGUIUtility.PingObject(codeObject);
AssetDatabase.OpenAsset(codeObject, int.Parse(line));
return true;
}
return false;
}
}
技术点
如果只是要实现功能,看上面代码就足够了。接下来讲几个点说明为什么要这样做。重点在于ConsoleWindow的源码。
1."UnityEditor.ConsoleWindow"是Console界面的类。需要查看的话,装个ReSharper到VS,或者装一个ILSpy去反编译。这样就都能看到源码了。
2.“m_ActiveText”是当前被选中的Log的详细信息。就是我们平时查看堆栈数据的那段内容。
3.AssetDatabase.OpenAsset(codeObject, int.Parse(line));第二个参数是行数。这个函数会重新触发OnOpenAssetAttribute回调。这就是为什么需要判断Degger类的实例id,是这个才进去重定位。不判断这个也可用其他来判断。反正要小心死循环。
参考文档:
1.http://www.cppblog.com/heath/archive/2016/06/21/213777.html
2.https://blog.csdn.net/qq_26999509/article/details/78516237
3.http://dsqiu.iteye.com/blog/2263664