有段时间没有写过文章了,不知道大伙儿还记得雨松MOMO吗? 嘿嘿。
开发项目的时候尤其在处理与服务器交互这块,如果服务端程序看不到客户端请求的Log信息,那么无法修改BUG。在Windows上Unity会自动讲Log文件写入本地,但是在IOS和Android上确没有这个功能,所以我想了个办法,把Log信息写在手机的客户端里。把如下脚本挂在任意游戏对象上即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
using UnityEngine; using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; public class OutLog : MonoBehaviour { static List<string> mLines = new List<string>(); static List<string> mWriteTxt = new List<string>(); private string outpath; void Start () { //Application.persistentDataPath Unity中只有这个路径是既可以读也可以写的。 outpath = Application.persistentDataPath + "/outLog.txt"; //每次启动客户端删除之前保存的Log if (System.IO.File.Exists (outpath)) { File.Delete (outpath); } //在这里做一个Log的监听 Application.RegisterLogCallback(HandleLog); //一个输出 Debug.Log("xuanyusong"); } void Update () { //因为写入文件的操作必须在主线程中完成,所以在Update中哦给你写入文件。 if(mWriteTxt.Count > 0) { string[] temp = mWriteTxt.ToArray(); foreach(string t in temp) { using(StreamWriter writer = new StreamWriter(outpath, true, Encoding.UTF8)) { writer.WriteLine(t); } mWriteTxt.Remove(t); } } } void HandleLog(string logString, string stackTrace, LogType type) { mWriteTxt.Add(logString); if (type == LogType.Error || type == LogType.Exception) { Log(logString); Log(stackTrace); } } //这里我把错误的信息保存起来,用来输出在手机屏幕上 static public void Log (params object[] objs) { string text = ""; for (int i = 0; i < objs.Length; ++i) { if (i == 0) { text += objs[i].ToString(); } else { text += ", " + objs[i].ToString(); } } if (Application.isPlaying) { if (mLines.Count > 20) { mLines.RemoveAt(0); } mLines.Add(text); } } void OnGUI() { GUI.color = Color.red; for (int i = 0, imax = mLines.Count; i < imax; ++i) { GUILayout.Label(mLines[i]); } } } |
如果在Mac上,可以借助同步推类似的工具来把你的Log文件取出来。
Android上取法类似。
此时如果客户端报错了怎么办?如果你是在IOS平台,强烈建议把PlayerSetting里面的Script Call Optimization设置成Slow and Safe,这样比如遇到空指针 或者 数组越界这样的错误,程序是不会直接闪退的。(Android上不用设置)这里我创造一个数组越界的错误。
1 2 3 4 |
void Start () { int []test = new int[1]; test[2] = 0; } |
那么在手机上报错以后,会自动将错误信息的堆栈打印在屏幕上。前提一定要设置Script Call Optimization设置成Slow and Safe,不然就直接闪退了。
补充,我看有朋友在下面给我留言问我安卓Android上面无法取出Log文件,今天在详细说明一下。
打包之前在Android的Player Setting里面选择WriteAccess (写入访问)
Internal Only:表示Application.persistentDataPath的路径是应用程序沙盒,(需要root不然访问不了写入的文件)
文件路径:data/data/包名/Files/OutLog.txt
External(SDCard):表示Application.persistentDataPath的路径是SDCard的路径。(不需要root就可以访问文件)
文件路径:SDCard/Android/包名/Files/OutLog.txt
后者你可以利用 腾讯 360 百度 91 各种手机助手把文件取出来。(建议使用后者)
总结 Application.persistentDataPath 会根据你的WriteAccess选项而产生对应的路径,如果你还是不知道路径我建议你输出一下它。
6月11日补充
项目中我一直用Application.RegisterLogCallback(HandleLog);方法来记录手机iOS和Android下产生的Log。结果今天测试小妹告诉我她在手机里面取出的LOG不全(LOG记录在本地后可以通过同步推一类的软件把LOG取出来)
经过仔细研究后发现原来最近我接了一个sdk,它在后台也用Application.RegisterLogCallback(HandleLog)来监听Log,我的程序是先执行我的RegisterLogCallback 然后在执行它的RegisterLogCallback所以它就把我的RegisterLogCallback覆盖了,那么我在HandleLog就监听不到了,即使有LOG产生也不会进我的方法了。。 解决的办法就是保证项目中只有一个Application.RegisterLogCallback(HandleLog)即可。
- 本文固定链接: https://www.xuanyusong.com/archives/2477
- 转载请注明: 雨松MOMO 于 雨松MOMO程序研究院 发表
为什么其他C#Script的Debug.log()的内容,没有输出在outlog.txt上?
请问 Update里的这句注释是为什么“//因为写入文件的操作必须在主线程中完成,所以在Update中哦给你写入文件。”为什么写文件要在主线程,在协成里不行吗?
APPLICATION.ISPLAYING什么意思,我的代码好像一直是FALSE
说错了,一直是TRUE,什么情况下会变成FLASE?
editor下 非运行 是false
嗯,後來知道了,但是steamvr 的代碼是在update方法下做的判斷,判斷成功會執行一大段代碼(目測只有在切出editor的時候會執行,或者某些情況下,改變了gameobject的路徑才執行1次,做editor對應更新的),執行頻率幾乎為0,沒搞清楚steamvr的這段代碼想做什麼
直接在電腦運行會 一直true,應該是真機才會false,才觸發update裡的代碼吧
成功了
怎么样获取root 权限,我现在在沙河 文件夹下面创建了一个 子目录, 访问的时候提示我没有权限不能访问。
Slow and safe 对效率影响有多大?
没啥 影响 两个项目上去了 没问题。。
momo大神,请问log 写入iphone手机的沙盒中,如何提取出来呢?
同步推
iphone屏幕上怎么不打印呢 OnGUI不能用于苹果手机吗
在手机端运行时,输出的Log文件中错误信息木有行号,,怎么破
没办法。。。
void HandleLog(string logString, string stackTrace, LogType type)
{
mWriteTxt.Add(logString);
System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(4,true);
mWriteTxt.Add(trace.ToString());
}
Editor下运行有stackTrace和行号,android下没行号但有stackTrace应该也能定位错误了,ios没测试过
那个万一没有sd卡的话?WriteAccess External ?
WriteAccess External 如果手机没SD 卡。 会写在 手机内部。。 unity会做这个判断。
不错。
谢谢。
我的手机上可以生成log,但是报错信息没有输出到屏幕上,是什么原因呢?
这种方法对闪退有用吗,比如安卓闪退的情况
关于文中最后一个问题是 Application.RegisterLogCallback只允许单个委托注册,这就意味着如果有两个独立的插件就没法分别使用了。不过也有解决的方法,可以自定义类来允许注册多个回调。using System.Collections.Generic;using UnityEngine;/// /// Application.RegisterLogCallback只允许单个委托注册/// http://feedback.unity3d.com/suggestions/change-application-dot-registerlogcallback-to-allow-multiple-callbacks/// 本来解决了多个委托hook到log的回调/// public static class LogCallbackHandler{private static readonly List callbacks;static LogCallbackHandler(){callbacks = new List();Application.RegisterLogCallback(HandleLog);}public static void RegisterLogCallback(Application.LogCallback logCallback){callbacks.Add(logCallback);}private static void HandleLog(string condition, string stackTrace, LogType type){for (var i = 0; i < callbacks.Count; i ){callbacks
(condition, stackTrace, type);}}}
关于文中最后一个问题是 Application.RegisterLogCallback只允许单个委托注册,这就意味着如果有两个独立的插件就没法分别使用了。不过也有解决的方法,可以自定义类来允许注册多个回调。using System.Collections.Generic;using UnityEngine;/// /// Application.RegisterLogCallback只允许单个委托注册/// http://feedback.unity3d.com/suggestions/change-application-dot-registerlogcallback-to-allow-multiple-callbacks/// 本来解决了多个委托hook到log的回调/// public static class LogCallbackHandler{ private static readonly List callbacks; static LogCallbackHandler() { callbacks = new List(); Application.RegisterLogCallback(HandleLog); } public static void RegisterLogCallback(Application.LogCallback logCallback) { callbacks.Add(logCallback); } private static void HandleLog(string condition, string stackTrace, LogType type) { for (var i = 0; i < callbacks.Count; i++) { callbacks
(condition, stackTrace, type); } }}
我测试了,输出日志是不会显示在Android手机上啊。都是按照
教程来的啊
你终于回来了,我就等了好久了,嘿嘿
有空经常更新啊,学习unity差不多一年,您的博客帮我解决了不少问题!~感谢
谢谢哈。。
一直收藏者MOMO你的博客。终于有更新了。看来最近很忙啊!
是啊, 嘿嘿、、
确实很久没看到新文章了,准备恢复更新了吗?