ios监控

作者: crazyfox | 来源:发表于2021-06-23 10:31 被阅读0次

    一.日志监控

    I.自己写API调用

    II.定义宏替换

     #define NSLog(frmt,...) LogAPI(frmt,##__VA_ARGS__)
     (##__VA_ARGS__可变参数宏,##去掉只有一个参数时的,号)
    

    III.使用官方提供的框架

    ASL apple system log (已弃用)ios(8.0,10.0)
    NSLog:
    Logs an error message to the Apple System Log facility.

    IIII.fishhook

    fishhook可以将我们Mach-O的库的符号表重新绑定
    hook掉NSLog函数,这边采用这种方式

    static void (* orig_nslog)(NSString *format, ...);
    void redirect_nslog(NSString *format, ...) {
        // 可以在这里先进行自己的处理
        // 继续执行原 NSLog
        orig_nslog(@"%@",[format stringByAppendingString:@"被HOOK了"]);
        va_list va;
        va_start(va, format);
        NSLogv(format, va);
        va_end(va);
    }
    - (void)openLogRecord
    {
        struct rebinding nsLog;
        nsLog.name = "NSLog";
        nsLog.replacement = redirect_nslog;
        nsLog.replaced = (void *)&orig_nslog;
        struct rebinding rebinds[1] = {nsLog};
        rebind_symbols(rebinds, 1);
    }
    

    二.网络监控

    I.NSURLProtocol

    @class NSURLProtocol
    @abstract NSURLProtocol is an abstract class which provides the
    basic structure for performing protocol-specific loading of URL
    data. Concrete subclasses handle the specifics associated with one
    or more protocols or URL schemes.

    抽象类,需要实现一个子类

    + (BOOL)canInitWithRequest:(NSURLRequest *)request
    {
        if ([NSURLProtocol propertyForKey:request.URL.absoluteString.md5String inRequest:request]) {
            return NO;
        }
        
        NSString *url = request.URL.absoluteString;
        
        // 如果url以https开头,则进行拦截处理,否则不处理
        if ([url hasPrefix:@"https"] ||[url hasPrefix:@"http"]) {
            return YES;
        }
        return NO;
    
    }
    
    
    /**
     * 如果需要对请求进行重定向,添加指定头部等操作,可以在该方法中进行
     */
    + (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
        NSMutableURLRequest *req = [request mutableCopy];
        [NSURLProtocol setProperty:@(YES) forKey:request.URL.absoluteString.md5String inRequest:req];
        return req;
    }
    

    II.WKURLSchemeHandler

    调用wkwebview的方法setURLSchemeHandler:forURLScheme:

        WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
        if (@available(iOS 11.0, *)) {
            URLSchemeHandler *handler = [URLSchemeHandler new];
            [configuration setURLSchemeHandler:handler forURLScheme:@"https"];
            [configuration setURLSchemeHandler:handler forURLScheme:@"http"];
        } else {
            // Fallback on earlier versions
        }
    
    

    声明http,https需要拦截
    直接拦截会导致崩溃,需要方法交换一下

    + (void)load {
      static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
        Method handlesURLScheme = class_getClassMethod(self, @selector(handlesURLScheme:));
        Method ssshandlesURLScheme = class_getClassMethod(self, @selector(ssshandlesURLScheme:));
        method_exchangeImplementations(handlesURLScheme, sshandlesURLScheme);
      });
    }
    
    + (BOOL)ssshandlesURLScheme:(NSString *)urlScheme {
        if(DailyRecordManager.shared.type&DailyRecordAll ||
           DailyRecordManager.shared.type&DailyRecordRequest
           ){
            //返回NO,否则可能会中断言, 'http' is a URL scheme that WKWebView handles natively
          if ([urlScheme isEqualToString:@"http"] || [urlScheme isEqualToString:@"https"]) {
            return NO;
          } else {
            return [self ssshandlesURLScheme:urlScheme];
          }
        }else{
            return [self ssshandlesURLScheme:urlScheme];
        }
    
    }
    

    //对于NSURLSession发起的网络请求,我们发现通过shared得到的session发起的网络请求都能够监听到,但是通过方法sessionWithConfiguration:delegate:delegateQueue:得到的session,我们是不能监听到的,原因就出在NSURLSessionConfiguration上,我们进到NSURLSessionConfiguration里面看一下,他有一个属性 @property(nullable, copy)NSArray<Class>*protocolClasses;复制代码
    //我们能够看出,这是一个NSURLProtocol数组,上面我们提到了,我们监控网络是通过注册NSURLProtocol来进行网络监控的,但是通过sessionWithConfiguration:delegate:delegateQueue:得到的session,他的configuration中已经有一个NSURLProtocol,所以他不会走我们的protocol来,怎么解决这个问题呢? 其实很简单,我们将NSURLSessionConfiguration的属性protocolClasses的get方法hook掉,通过返回我们自己的protocol,这样,我们就能够监控到通过sessionWithConfiguration:delegate:delegateQueue:得到的session的网络请求
    //https://juejin.cn/post/6844903473671077895

    因为第三方sdk有可能对wkwebview有封装
    所以直接hook掉wkwebview的configuration

    + (void)load {
      static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
          Method setConfiguration = class_getInstanceMethod(self, @selector(configuration));
        Method setSSSConfiguration = class_getInstanceMethod(self, @selector(SSSConfiguration));
        method_exchangeImplementations(setConfiguration, setSSSConfiguration);
          Method con = class_getInstanceMethod(self, @selector(initWithFrame:configuration:));
          Method ssscon = class_getInstanceMethod(self, @selector(sssinitWithFrame:configuration:));
        method_exchangeImplementations(setConfiguration, setSSSConfiguration);
          method_exchangeImplementations(con, ssscon);
    
      });
    }
    
    

    III.查看NSURLSession的请求连接开始时间结束时间重定向次数等具体信息,iOS10之后可以使用代理方法,iOS10之前可以使用libcurl

    -(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
    https://www.jianshu.com/p/32935af04593
    https://www.jianshu.com/p/f146f8fdadbf

    IIII.拦截console.log

    使用js注入的方式

            [configuration.userContentController addScriptMessageHandler:self name:@"logger"];//js打印事件
              NSString *printContent = @"console.log = function(message){window.webkit.messageHandlers['logger'].postMessage(message)};";
              WKUserScript *userScript = [[WKUserScript alloc] initWithSource:printContent injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
              [configuration.userContentController addUserScript:userScript];
    

    https://www.jianshu.com/p/840e049741bc

    https://juejin.cn/post/6844903552385564679#comment

    三.崩溃监控

    NSSetUncaughtExceptionHandler();//设置崩溃时走的函数
    NSGetUncaughtExceptionHandler();//获取崩溃处理函数
    

    ios崩溃分类:

    1.未捕获异常分类
    2.底层信号崩溃

    未捕获异常处理:

    static NSUncaughtExceptionHandler *oldUncaughtExceptionHandler = nil;
    
    void uncaughtExceptionHandler(NSException *exception) {
        //记录日志等操作 旧崩溃函数处理
        // Internal error reporting
    }
    
    oldUncaughtExceptionHandler  =  NSGetUncaughtExceptionHandler();
        NSGetUncaughtExceptionHandler(&uncaughtExceptionHandler);//获取崩溃处理函数
    

    底层信号崩溃

    void SignalExceptionHandler(int signal){
        NSLog(@"signal: %d", signal);
        [DailyRecordManager.shared logType:(DailyRecordCrash) message:@(signal)];
    
    }
    
    - (void)crashSingleHandler{
        signal(SIGABRT, SignalExceptionHandler);
        signal(SIGILL, SignalExceptionHandler);
        signal(SIGSEGV, SignalExceptionHandler);
        signal(SIGFPE, SignalExceptionHandler);
        signal(SIGBUS, SignalExceptionHandler);
    
    }
    
    

    [https://blog.csdn.net/u012390519/article/details/51682951]
    (https://blog.csdn.net/u012390519/article/details/51682951)
    https://segmentfault.com/a/1190000039111381

    相关文章

      网友评论

        本文标题:ios监控

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