最初是用来在手机端直接显示Log到屏幕上,后来看到满屏幕Log实在有点恶心,所以就通过Udp,把手机端上的log,直接发送到电脑端上的接收器。同时还可以进入多个手机设备同时进行LOG调试。
首先创建一个脚本OutLog.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System;
using System.Text;
using System.Collections;
using System.Net;
using System.Net.Sockets;
public class OutLog : MonoBehaviour
{
static List<string> mLines = new List<string>();
static List<string> mWriteTxt = new List<string>();
private string outpath;
//屏幕打印最多Log数量
public int _screenLogMaxCount = 8;
public bool _isInputLogOnScreen = false;
public Color _color = Color.red;
public string ip = "127.0.0.1";
public int point = 60000;
private UdpClient udpClient;
private IPEndPoint iPEndPoint;
void Awake() {
iPEndPoint = new IPEndPoint(IPAddress.Parse(ip), point);
udpClient = new UdpClient();
//Application.persistentDataPath Unity中只有这个路径是既可以读也可以写的。
outpath = Application.persistentDataPath + "/outLog.txt";
Debug.Log("path:" + outpath);
//每次启动客户端删除之前保存的Log
if (System.IO.File.Exists(outpath)) {
File.Delete(outpath);
}
//在这里做一个Log的监听
Application.RegisterLogCallback(HandleLog);
}
void 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.Log || type == LogType.Error || type == LogType.Exception) {
Log(logString);
//Log(stackTrace);
}
try {
byte[] bytes;
//bytes = Encoding.UTF8.GetBytes(type.ToString() + "n " + logString + "n" + stackTrace);
bytes = Encoding.UTF8.GetBytes(logString + "n" + stackTrace);
udpClient.Send(bytes, bytes.Length, iPEndPoint);
} catch (System.Exception) {
}
}
//输出在手机屏幕上
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 > _screenLogMaxCount) {
mLines.RemoveAt(0);
}
mLines.Add(text);
}
}
void OnGUI() {
if (_isInputLogOnScreen) {
GUI.color = _color;
int count = 0;
for (int i = mLines.Count - 1; i >= 0 && count < _screenLogMaxCount; --i) {
count++;
GUILayout.Label(mLines[i]);
}
}
}
}
再将OutLog.cs绑定在手机端任意GameObject上

Screen Log Mac Count :屏幕同时显示的最多Log数
Is Input Log On Screen:是否在屏幕显示Log
Color:屏幕显示Log颜色
IP :接收端的IP地址
Point : 接收端的端口号
效果如下:

然后网上百度一下网络调试工具,就可以找到一些UDP的调试工具了。
或者自己写一个也可以。
以下是我用Unity写的UDP的服务器,用于接收Log信息:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
public class UdpServer : MonoBehaviour
{
public int _point = 60000;
Thread _thread = null;
private Socket newsock;//定义一个socket变量
IPEndPoint ip;//定义一个IP地址和端口号
int recv;//定义一个接受值的变量
byte[] data;//定义一个二进制的数组用来获取客户端发过来的数据包
List<string> _dataList;
void Start() {
Loom.Initialize();
_dataList = new List<string>();
_labelStyle = new GUIStyle();
Screen.SetResolution(960, 640, false);
//得到本机IP,设置TCP端口号
ip = new IPEndPoint(IPAddress.Any, _point);//设置自身的IP和端口号,在这里IPAddress.Any是自动获取本机IP
newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);//实例化socket对象设置寻址方案为internetwork(IP版本的4存放),设置Soket的类型,为Dgram(支持数据报形式的数据),设置协议的类型,为UDP
newsock.SendTimeout = 5000;
newsock.ReceiveTimeout = 5000;
//绑定网络地址
newsock.Bind(ip);//绑定IP
Debug.Log("This is a Server,host name is " + Dns.GetHostName());//输出本地的名字
Debug.Log("Waiting for a client");
//BeginReceives();
_thread = new Thread(BeginListening);//定义一个子线程
_thread.Start();//子线程开始
}
void BeginListening() {
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);//实例化一个网络端点,设置为IPAddress.Any为自动获取跟我通讯的IP,0代表所有的地址都可以
EndPoint Remote = (EndPoint)(sender);//实例化一个地址结束点来标识网络路径
// Debug.Log(Encoding.ASCII.GetString(data, 0, recv));//输出二进制转换为string类型用来测试
while (true) {
if (newsock.Available == 0) {
System.Threading.Thread.Sleep(200);
continue;
}
int bufferSize = newsock.Available;
if(bufferSize > 3000){
bufferSize *= 3;
}
//Debug.Log("buff size " + bufferSize);
data = new byte[25000];
recv = newsock.ReceiveFrom(data, ref Remote);//将数据包接收到的数据放入缓存点,并存储终节点
//Debug.Log(Encoding.ASCII.GetString(data, 0, recv));
string str = "IP:" + Remote.ToString() + " 时间:" + DateTime.Now.ToLongTimeString().ToString() + "n" + Encoding.Default.GetString(data, 0, recv);
Loom.QueueOnMainThread(() => {
_dataList.Add(str);
});
// newsock.SendTo(Encoding.ASCII.GetBytes(mydata),mydata.Length,SocketFlags.None,Remote);
}
}
void SendMessage(string message) {
byte[] data = new byte[1024];
Debug.Log("This is a client,host name is" + Dns.GetHostName());
//IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);//实例化一个网络端点,设置为IPAddress.Any为自动获取跟我通讯的IP,0代表所有的地址都可以
EndPoint Remote = (EndPoint)(ip);//实例化一个地址结束点来标识网络路径
Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//string welcome = "你好";
//data = Encoding.ASCII.GetBytes(welcome);
ip = new IPEndPoint(IPAddress.Parse("192.168.1.120"), 12346);
// server.SendTo(data, data.Length, SocketFlags.None, ip);
// data = new byte[1024];
server.SendTo(Encoding.ASCII.GetBytes(message), ip);
// data = new byte[1024];
Debug.Log("Stopping Client.");
server.Close();
}
Vector2 startScrollPos = Vector2.zero;
float buttonHight = 30.0f;
GUIStyle _labelStyle;
void OnGUI() {
GUILayout.BeginHorizontal();
GUILayout.Label("端口号", GUILayout.Width(40), GUILayout.Height(buttonHight));
_point = int.Parse(GUILayout.TextField(_point.ToString(), GUILayout.Width(60), GUILayout.Height(buttonHight)));
if (GUILayout.Button("监听", GUILayout.Height(buttonHight))) {
StopListening();
//得到本机IP,设置TCP端口号
ip = new IPEndPoint(IPAddress.Any, _point);//设置自身的IP和端口号,在这里IPAddress.Any是自动获取本机IP
newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);//实例化socket对象设置寻址方案为internetwork(IP版本的4存放),设置Soket的类型,为Dgram(支持数据报形式的数据),设置协议的类型,为UDP
//绑定网络地址
newsock.Bind(ip);//绑定IP
Debug.Log("This is a Server,host name is " + Dns.GetHostName());//输出本地的名字
Debug.Log("Waiting for a client");
//BeginReceives();
_thread = new Thread(BeginListening);
_thread.Start();
}
if (GUILayout.Button("停止", GUILayout.Height(buttonHight))) {
StopListening();
}
if (GUILayout.Button("清理", GUILayout.Height(buttonHight))) {
_dataList.Clear();
}
if (GUILayout.Button("Count " + _dataList.Count, GUILayout.Height(buttonHight), GUILayout.Width(140))) {
}
GUILayout.EndHorizontal();
GUILayout.Space(10);
startScrollPos = GUILayout.BeginScrollView(startScrollPos, GUILayout.Width(Screen.width), GUILayout.Height(Screen.height - 2 * buttonHight));
//labelStyle.fontSize = 20;
for (int i = _dataList.Count; i > 0; i--) {
//Color lableColor =
string str = _dataList[i - 1];
if (str == "" || str == null || str.Length < 1)
continue;
if (str.Contains("Debug:LogError(Object)")) {
_labelStyle.normal.textColor = Color.red;
} else if (str.Contains("Debug:LogWarning(Object)")) {
_labelStyle.normal.textColor = Color.yellow;
} else {
_labelStyle.normal.textColor = Color.white;
}
GUILayout.Label(str, _labelStyle);
}
//foreach (string data in _dataList) {
// GUILayout.Label(data);
//}
GUILayout.EndScrollView();
}
void OnApplicationQuit() {
StopListening();
}
void StopListening() {
_dataList.Clear();
if (_thread != null) {
_thread.Abort();
}
if (newsock != null)
newsock.Close();
}
}
效果图如下:
