美文网首页iOS精華
重定义你的XCode Console

重定义你的XCode Console

作者: Arbalest_313 | 来源:发表于2017-01-20 18:09 被阅读54次

"iOS10 XCode8 Console Color Log 重定向Log"
author: yuan

前言


自从Xcode8之后, 再也不能像以前一样愉快的使用插件了。之前赖以生存Console插件XcodeColors 也随之失效。我们再一次回到了原生只有黑白信息的Console上面。虽然可以用一些Formatting的Log来弥补,但依旧不是很直观。

每一次当测试机同事的手机器上有什么BUG需要查看日志的时候,可能还需要使用中间层代理来破解HTTPS查看请求,或者直接来找开发在Xcode里面查看Log。 过程还需要打包,查找,定位信息,繁琐无比。

作为一个攻城狮,完全不能忍。于是乎,一个远程查看Log与自定义的展现形式的Console的需求孕育而生:

首先第一点,就是要抓取到所有的Log的同时还需要无任何的侵入性。 不可能因为这个需求把项目里面之前的各种Log重新写一遍。

其次第二点,就是我们的Console的展现要我们可以自己根据自己的需求来定义Console。并且可以远程查看。

先看效果:

RemoteConsole


接下来就是简单的把他们组合起来创建一个RemoteConsole,

#import "RemoteConsole.h"
#import "PSWebSocketServer.h"
@interface RemoteConsole () <PSWebSocketServerDelegate>

@property (nonatomic, strong) PSWebSocketServer *server;//tiny webSocketServer
@property (nonatomic, strong, nullable)PSWebSocket * webSocket;//the webSocket

@property (nonatomic,assign) int originalStdHandle;//original file descriptor

@property (nonatomic,strong) dispatch_source_t sourt_t;//file descriptor mointor

@end

在开始与结束的时候分别重写与重置STDERR_FILENO的文件描述符

#pragma mark - PSWebSocketServerDelegate
_server = [PSWebSocketServer serverWithHost:nil port:8080];//指定端口为8080
_server.delegate = self;

- (void)serverDidStart:(PSWebSocketServer *)server {
    NSLog(@"Server did start…");
    if (_sourt_t) {
        dispatch_cancel(_sourt_t);
    }
    _sourt_t = [self startCapturingLogFrom:STDERR_FILENO];
}
- (void)serverDidStop:(PSWebSocketServer *)server {
    NSLog(@"Server did stop…");
    dispatch_cancel(_sourt_t);
}

抓取Log与重置Log

- (dispatch_source_t)startCapturingLogFrom:(int)fd  {
    int origianlFD = fd;
    _originalStdHandle = dup(fd);//save the original for reset proporse
    int fildes[2];
    pipe(fildes);  // [0] is read end of pipe while [1] is write end
    dup2(fildes[1], fd);  // Duplicate write end of pipe "onto" fd (this closes fd)
    close(fildes[1]);  // Close original write end of pipe
    fd = fildes[0];  // We can now monitor the read end of the pipe
    
    NSMutableData* data = [[NSMutableData alloc] init];
    fcntl(fd, F_SETFL, O_NONBLOCK);// set the reading of this file descriptor without delay
    __weak typeof(self) wkSelf = self;
    dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
    
    int writeEnd = fildes[1];
    dispatch_source_set_cancel_handler(source, ^{
        close(writeEnd);
        if (wkSelf) {
            dup2(wkSelf.originalStdHandle, origianlFD);//reset the original file descriptor
        }
    });
    
    dispatch_source_set_event_handler(source, ^{
        @autoreleasepool {
            char buffer[1024 * 10];
            ssize_t size = read(fd, (void*)buffer, (size_t)(sizeof(buffer)));
            [data setLength:0];
            [data appendBytes:buffer length:size];
            NSString *aString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            [wkSelf.webSocket send:aString];
            printf("\n%s\n",[aString UTF8String]); //print on STDOUT_FILENO,so that logs can show on xcode console as well
        }
    });
    dispatch_resume(source);
    return source;
}

然后在适时的时候开启server即可。这样手机端就完成了,接下来就是远程的Console

XcodeConsole.html

之前我们已经获取了IP,并且建立了Socket的连接了,并且可以接受到数据。接下来就是我们要如何展示了:

//XcodeConsole.html
function writeToScreen(message) { 
      var tr = document.createElement('tr');   
      var pre = document.createElement('pre');
      var td1 = document.createElement('td');
      var text1 = document.createTextNode(message);
      pre.appendChild(text1)
      td1.appendChild(pre);
      tr.appendChild(td1);

      var lowerM = message.toLowerCase()
      if (lowerM.indexOf("code = 0") >= 0 || lowerM.indexOf("error") >= 0 ||  lowerM.indexOf("exception") >= 0) {
        tr.style.background = "#E97E60"
      } else if (lowerM.indexOf("warning") >= 0) {
        tr.style.background = "#FACC9A"
      } else if (lowerM.indexOf("-- response") >= 0) {
        tr.style.color = "#5BBB7B"
      }
      
      output.appendChild(tr);
      footerElement.scrollIntoView(false);
      updateTimestamp();

    }  

当我们的log里面包含了不同的关键字时,我们赋予字体与背景不同的颜色,然后添加到页面的output元素中

现在你就只需要把这个文件放入浏览器里面然后跟上你想要的ip参数就可以访问了/XcodeConsole.html?ip=0.0.0.0

后续


到这里一个远程的Console Log就完成了。你所需要的就是修改ip所跟随的设备地址。模拟器为0:0:0:0,真机可以去WIFI里面查看设比地址。
下一步可以把这个静态页面布置在测试服务器的内网上, 让所有人在内网都可以访问。再也不需要设置代理,或者xCode特意去查看了。

我把这个静态页面放在了http://dev.hyyy.me/iOS/Console?ip=xxx 下不过端口是在9001.需要的同学可以自行修改端口。

最后Github源码

Reference:

相关文章

网友评论

  • Homer1ynn:你好, 我看了你的文章, 模拟器测试时可以通过的, 真机的话, 查看了在同一网段, 但是总是连接不上, 不知道是什么问题呢.
    Homer1ynn:@Arbalest_313 IP是手机的, 我也查看过端口是否占用等问题, 无奈的时候, 也试了一下换电脑的IP, 都没有链接上, 看网页上的显示, 应该是一直在链接, 可是每次尝试链接的过程经过一段时间以后, 就链接失败了
    Arbalest_313:@Homer1ynn 有改ip吗
  • 千若逸:方案很好,但有一个问题没法做日志等级控制,比如Debug模式和Release需要显示不同等级的日志
    Arbalest_313:@千若逸 这个只是抓取,展示你的log,给你高度的展现形式的可订, 并没有涉及侵入到原有的任何log. :smile:

本文标题:重定义你的XCode Console

本文链接:https://www.haomeiwen.com/subject/dfpwbttx.html