背景
开发过程中,为了便于调试,会输出很多打印日志,而只有当电脑连着真机进行调试的时候,Xcode控制台才会有日志输出。这也就意味着如果未处于调试状态时,是看不到Xcode控制台的日志输出的,那么如果还想看到日志输出,那么这个功能就尤为重要了。
实现方案的调研与思考
iOS 开发语言有Objective-C和Swift,经销商项目中均有使用。Objective-C中的打印方法为NSLog,Swift中打印方法为print。这就意味着如果要实现此功能,就需要处理两个方法。
NSLog
FOUNDATION_EXPORT void NSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2) NS_NO_TAIL_CALL;
有成熟的第三方库CocoaLumberjack。但是 需要使用他们公开的API,这于我们来说侵入性太大,完全没有必要。
2、通过fishhook库hook NSLog方法重定向NSLog函数
fishhook是Facebook提供的一个动态修改链接Mach-O文件的工具,能够hook C函数。
NSLog最后重定向的句柄是STDERR,NSLog输出的日志内容,最终都通过STDERR句柄来记录,而dup2函数式专门进行文件重定向的;可以使用dup2重定向STDERR句柄,将内容重定向指定的位置。但是重定向之后,控制台无法正常输出
func print(_ items: Any..., separator: String = " ", terminator: String = "n")
Swift语言具备重载特性,我们可以在项目中重载该print方法。这样在项目中调用print方法后,会直接调用已重载后的print方法。但需保证Swift的print方法重载类在项目目录下,不能在组件下。
代码实现
Objective-C中NSLog的方法重定向(选用优化后的fishhook方案)
//函数指针,用来保存原始的函数的地址
static void(*old_nslog)(NSString *format, ...);
//新的NSLog
void myNSLog(NSString *format, ...){
va_list vl;
va_start(vl, format);
NSString* str = [[NSString alloc] initWithFormat:format arguments:vl];
va_end(vl);
[[DoraemonNSLogManager sharedInstance] addNSLog:str];
//再调用原来的nslog
//old_nslog(str);
old_nslog(@"%@",str);
}
@implementation DoraemonNSLogManager
+ (instancetype)sharedInstance {
static id instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
});
return instance;
}
// 开启日志监听
- (void)startNSLogMonitor{
doraemon_rebind_symbols((struct doraemon_rebinding[1]){"NSLog", (void *)myNSLog, (void **)&old_nslog},1);
}
// 关闭日志监听
- (void)stopNSLogMonitor{
doraemon_rebind_symbols((struct doraemon_rebinding[1]){"NSLog", (void *)old_nslog, NULL},1);
}
// 日志写入缓存
- (void)addNSLog:(NSString *)log{
DoraemonNSLogModel *model = [[DoraemonNSLogModel alloc] init];
model.content = log;
model.timeInterval = [[NSDate date] timeIntervalSince1970];
if (!_dataArray) {
_dataArray = [[NSMutableArray alloc] init];
}
[_dataArray addObject:model];
}
核心代码如下:
// 重载print方法
public func print(_ items: Any..., separator: String = " ", terminator: String = "n") {
#if DEBUG
// 调用原系统的打印方法 保持控制台的正常输出
Swift.print(items, separator: separator, terminator: terminator)
// 添加swift日志打印
let isOn = DoraemonCacheManager.sharedInstance().nsLogSwitch()
guard isOn else { return }
let str = items.map { "($0)" }.joined(separator: separator)
// 日志写入缓存
DoraemonNSLogManager.sharedInstance().addNSLog(str)
#endif
}
捕获这两个方法后,即可将输出的日志,写入到缓存中,然后再呈现到UI页面上,即可实现在设备上实时查看日志的功能。
如何使用
原文地址:https://blog.csdn.net/qq_25303213/article/details/128701425
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_19257.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!