美文网首页
使用dSYM分析App崩溃日志

使用dSYM分析App崩溃日志

作者: 高思阳 | 来源:发表于2019-06-19 16:24 被阅读0次

    前言

    我们在开发App过程中,因为连接到控制台,所以遇到问题会很容易找到问题代码。但是对于线上的App出现Crash的时候,我们不可能通过这种方式,也不现实,所以我们只能通过收集Crash信息,来解决Bug。而这种收集Crash信息并且分析定位到具体代码的第三方SDK很多。但是今天我们来自己实现一下。

    收集 Crash 信息

    Apple提供了NSException类来帮助我们收集异常信息。

    NSException is used to implement exception handling and contains information about an exception — Apple Documentation.

    点击这里来查看官方文档具体内容。

    我们的确可以通过NSException来收集信息,但是,我们怎么把这个信息保存下来,并且上传到我们后台服务器,收集起来呢。这就需要用到另一个函数:NSUncaughtExceptionHandler

    Sets the top-level error-handling function where you can perform last-minute logging before the program terminates.http://www.90168.org/

    意思就是我们可以在App异常退出的之前有一分钟的时间来处理异常信息,利用这段时间,我们可以把Crash信息写入本地,也可以上传到服务器,但是考虑到网络阻塞原因,我们可能在这一分钟不能操作完毕,所以我们把上传放到下一次App启动时执行。

    具体的代码如下:

    - (void)lyCarshLog {     [self uploadExceptionLog];     NSSetUncaughtExceptionHandler(&catchExceptionLog); } - (void)uploadExceptionLog {      if (log != nil) {         // 在这里上传 Crash 信息,上传完毕后要记得清空。      } } void catchExceptionLog(NSException *exception) {     // 获取 Crash 信息     NSArray *symbols = [exception callStackSymbols];     NSString *reason = [exception reason];     NSString *name = [exception name];     NSDictionary *userInfo = [exception userInfo];     //...          /*另外,我们可能需要一些别的信息,比如说发生 Crash 的设备的系统版本,设备型号,App的版本号*/     struct utsname systemInfo; // 需要导入`sys/utsname.h`头文件。     uname(&systemInfo);     NSString *deviceString = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];     NSDictionary *appInfo = [[NSBundle mainBundle] infoDictionary];     NSString *appVersion = [appInfo objectForKey:@"CFBundleShortVersionString"];     NSString *result = [NSString stringWithFormat:@"CarshReason = %@ \n name = %@ \n userInfo = %@ \n log = %@ \n systemVersion = %f \n deviceInfo = %@ \n appVersion = %@ ",reason,name,userInfo,symbols,[UIDevice currentDevice].systemVersion.floatValue,deviceString,appVersion];     // 把 result 写入本地。 }</pre>
    

    Crash信息至此已经收集完毕,等待下次App启动的时候,我们把本地的Crash信息上传到服务器就OK了。

    处理 Crash 信息 - 符号化(Fully Symbolicated)

    Tips: 堆栈跟踪是自下而上展示的,也就是最先调用的方法在最下面。

    其中:

    1. Binary name 表明代码所在App或者Framework的位置。比如:line 0 是在CoreFoundation中,line 3 在CrashDemo中…
    2. Address 方法的内存地址。
    3. Class name 当前的类名。
    4. Method name 当前调用的方法名。
    5. Offset 相对加载地址/基地址(load address)的偏移量。

    我们得到这个半符号化(Partially Symbolicated)的日志对我们分析Crash原因的帮助很有限,因为我们可能只能知道__NSArrayI objectAtIndex:调用出现了问题,但是不能定位到具体代码。所以我们要把它完全符号化(Fully Symbolicated)。

    dSYM

    我们需要借助dSYM来帮助我们完成符号化,对于dSYM文件的获取,我们可以通过多种方法,我这里只说一种:

    先打开XcodeWindows->Organize->找到对应的app包,然后右键->Show in finder,找到appName. xcarchive->显示包内容->把dSYMs拷贝出来(或者就在里面操作)

    atos

    The atos command converts numeric addresses to their symbolic equivalents

    我们使用atos命令来完成符号化,具体命令如下:

    $ atos -arch <Binary Architecture> -o <Path to dSYM file>/Contents/Resources/DWARF/<binary image name> -l <load address> <address to symbolicate>
    

    其中:

    1. Binary Architecture: arm64armv6armv7 armv7s 根据自己的情况来写。
    2. Path to dSYM file: dSYM文件的路径。
    3. binary image name: 你工程的名字。
    4. load address: 基地址,如果我们的崩溃日志中没有这个信息(比如上面的Crash信息中就没有包含),就需要我们手动去计算这个load address:laod address = address to symbolicate - offset,比如:0x0000000102838119转化为十进制为4337139993,再减去偏移量265,为4337139728,在转化为十六进制0x0000000102838010
    5. address to symbolicate:当前方法的内存地址。

    所以,上图为例:

    $ cd CrashDemo/dSYMs $ atos -arch arm64 -o CrashDemo.app.dSYM/Contents/Resources/DWARF/CrashDemo -l  0x0000000102838010 0x0000000102838119</pre>
    

    这时命令就会输出已经符号化过的信息: -[ViewController viewDidLoad] (in CrashDemo) (ViewController.m:45)

    其中45就是问题代码在ViewController.m中的具体位置。

    其实符号化的过程有多种方式,你可以参考Apple文档,对于其中UUID,只是为了我们找到App对应版本的dSYM文件,所以如果你能确定两者的对应,不需要我们再去获取。而且,使用上面方法,我们可以找到每一个版本对应的dSYM文件(假如你没有删除的话)。 [图片上传失败...(image-dcd188-1560932492972)]

    最后

    愉快的改Bug吧😳

    链接: 使用dSYM分析App崩溃日志

    相关文章

      网友评论

          本文标题:使用dSYM分析App崩溃日志

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