iOS Crash 流程化1:一般的 Crash 日志解析方法

  • iOS Crash 流程化:一般的 Crash 日志解析方法
    • TL;DR
    • 一、手动解析 Crash 日志
      • 1、需要的相关文件路径or获取途径
        • Crash Log获取
        • dSYM路径
        • Symbolicatecrash的文件(已提供)路径:
      • 2、UUID校验(确保文件之间彼此正确对应)
        • .crash
        • dSYM
        • .App
      • 3、.Crash文件分析过程
    • 二、通过Xcode查看设备崩溃信息
    • 三、使用 Apple 提供的 Crash 崩溃收集服务
      • 1、上报错误信息
      • 2、查看崩溃次数
      • 3、回到 Xcode 查看
        • 查看具体崩溃信息
    • 四、第三方崩溃分析工具 Bugly
      • 冲突
    • 补充:来自iOS知识小集
    • Ref

默认 Build Settings -> Build Options -> Debug Information Format 中,置为了 DWARF,如果选为DWARF则不会产生dSYM文件,必须选择DWARF with dSYM File才会生成符号表文件。

TL;DR

1、校验Crash Log uuid

grep "ShanLinExample arm" *.crash

2、校验dSYM uuid

dwarfdump --uuid ShanLinExample.App.dSYM/Contents/Resources/DWARF/ShanLinExample

3、校验App uuid

dwarfdump --uuid Payload/ShanLinExample.app/ShanLinExample

4、将 Crash Log、dSYM、App 放在同一个文件夹下,符号化

./symbolicatecrash ShanLinExample-2016-06-14-133332.crash ShanLinExample.App.dSYM > report.log

一、手动解析 Crash 日志

1、需要的相关文件路径or获取途径

Crash Log 获取
  1. 将发生了Crash的手机连接电脑,打开Xcode-菜单栏Window-Devices and Simulators
  2. 打开相应的手机View Device Logs
    image
  3. 建议按时间倒序排列,选中相应App的CrashLog,右键Export Log,以桌面CrashReport文件夹为例拷贝到~/Desktop/CrashReport
    image
dSYM路径

每一个打包版本都有个对应的 Archives 文件,路径为:

~/Library/Developer/Xcode/Archives

  1. Xcode-菜单栏Window-Archives选中相应版本Archive-show in Finder
    image
  2. 对选中.xcarchive右键显示包内容,在dSYMs文件夹下找到#AppName#.app.dSYM,拷贝到桌面CrashReport文件夹中
    image
Symbolicatecrash的文件(已提供)路径:
/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash

Xcode不同版本间Symbolicatecrash的位置可能会有差异,如DVTFoundation.framework部分文件名不一样。

若找不到可以通过命令来查找:

find /Applications/Xcode.App -name symbolicatecrash -type f

2、UUID校验(确保文件之间彼此正确对应)

Ps. ShanLinExample改为对应的AppName即可。

.crash
grep "ShanLinExample arm" *.crash

输出结果:

0x100054000 - 0x1008e3fff ShanLinExample arm64  <f960888bef2430e9b844732364819642> /var/containers/Bundle/Application/84FA640D-AC63-4848-9989-9C5D8FCA748A/ShanLinExample.app/ShanLinExample
dSYM
dwarfdump --uuid ShanLinExample.App.dSYM/Contents/Resources/DWARF/ShanLinExample

输出结果:

UUID: 271C3816-D14F-3FFE-93FA-D0A8F2912DF0 (armv7) ShanLinExample.App.dSYM/Contents/Resources/DWARF/ShanLinExample
UUID: F960888B-EF24-30E9-B844-732364819642 (arm64) ShanLinExample.App.dSYM/Contents/Resources/DWARF/ShanLinExample
.App

应用Archive生成的.ipa,将后缀改为.zip,解压生成Payload文件夹,里面有个与App同名文件,此时用命令行:

dwarfdump --uuid Payload/ShanLinExample.app/ShanLinExample

输出结果:

UUID: 271C3816-D14F-3FFE-93FA-D0A8F2912DF0 (armv7) Payload/ShanLinExample.app/ShanLinExample
UUID: F960888B-EF24-30E9-B844-732364819642 (arm64) Payload/ShanLinExample.app/ShanLinExample

对比UUID即可。

图例

3、.Crash文件分析过程

将Symbolicatecrash、dSYM文件、.crash文件都放在一个文件夹中,例如~/Desktop/CrashReport

先运行:

export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer

否则会报错:

Error: "DEVELOPER_DIR" is not defined at ./symbolicatecrash line 60.

输入命令:

./symbolicatecrash ShanLinExample-2016-06-14-133332.crash ShanLinExample.App.dSYM > report.log

则最终生成的report.log文件即为崩溃时的具体信息。


二、通过Xcode查看设备崩溃信息

可以将发生崩溃的设备连接Xcode,选择window-> devices -> 选择自己的手机 -> view device logs 就可以查看手机上所有的崩溃信息了。

image

只要手机上的应用是这台电脑安装打包的,这样的崩溃信息系统已经为我们符号化好了,只需要进去之后等一会就行。如果还是没有符号化完毕 ,可以选择文件,然后右击选择Re-Symbolicate就可以。

如果是使用其他电脑进行的打包,可以在这里面将Crash文件导出,自己通过命令行的方式进行解析。


三、使用 Apple 提供的 Crash 崩溃收集服务

1、上报错误信息

App上线以后苹果就会自动捕捉崩溃信息,当 App 出现 Crash 后iOS系统就会记录崩溃日志并上传到Apple的服务器。前提是需要用户同意 “与应用开发者共享”:

设置->隐私->诊断与用量->与应用开发者共享

2、查看崩溃次数

上线运行一段时间后就可以登录iTunes Connect查看。登录后点击 App 分析 --> 选择要查看的App --> 点击右下角的崩溃,就可以根据筛选条件确定Crash的版本和日期。

确定完版本和日期后并不能在iTunes Connect中查看崩溃日志。具体信息还要回到Xcode中完成。

3、回到 Xcode 查看

查看具体崩溃信息

Xcode打开App,选择Window->Organizer,选择右边的Crashes

Organizer
Crashes
崩溃信息

这里选择具体的线上版本,崩溃信息就出现了(此时需要联网)

image

UIKit 开头是应该是无法定位的错误,哪儿红儿哪一行就是错误信息。这里的错误实际是因为使用UIScrollview的Category进行键盘隐藏而产生的Crash。当使用中文手写键盘输入就会出现这种情况。

可定位的错误信息如下,点击箭头选择App打开就会打开Xcode,然后把当时的线程和堆栈呈现出来。


可定位错误
在项目中查看

在项目中查看最好恢复到发布时候的版本。代码保持一致性。有时候项目中查看定位并不准确,但是有这些当时崩溃的线程,还是有助于我们定位错误的。

注意: 官方提供的崩溃信息并不是实时的,只能查看两天之前的崩溃信息。需要实时的可以使用第三方工具。


四、第三方崩溃分析工具 Bugly

有很多第三方工具可以进行崩溃统计分析,个人比较推荐 Bugly(不推荐友盟,网易云捕和国外的 Crashlytics 都没有用过)。它的优势在于,可以直接将崩溃信息分析出来并且做好分类和汇总。当然完整的解析崩溃需要上传dSYMBugly后台,可以通过手动上传的方式,也可以按照 Bugly 的文档配置脚本进行上传。

image

这就是Bugly的页面,出错堆栈Bugly会帮我们解析好,并且会根据不同情况给一些解决建议。

Bugly有一个页面追踪功能,这是我认为非常有用的一个功能。这个功能会将用户在不同页面之间跳转的流程记录下来。这样对于复现bug是很有用的,可以根据用户页面跳转推测出用户大概操作流程,根据这个流程复现bug

image

Bugly还有日报功能,可以每天汇总一篇日报,并且发到团队每个人的邮箱和微信号上。

image

冲突

如果多个 Crash 收集框架存在时,往往会存在冲突。

不管是对于 Signal 捕获还是 NSException 捕获都会存在 handler 覆盖的问题,正确的做法应该是先判断是否有前者已经注册了 handler,如果有则应该把这个 handler 保存下来,在自己处理完自己的 handler 之后,再把这个 handler 抛出去,供前面的注册者处理。这里给出相应的 Demo,Demo 由@zerygao提供。

typedef void (*SignalHandler)(int signo, siginfo_t *info, void *context);

static SignalHandler previousSignalHandler = NULL;

+ (void)installSignalHandler {
    struct sigaction old_action;
    sigaction(SIGABRT, NULL, &old_action);
    if (old_action.sa_flags & SA_SIGINFO) {
        previousSignalHandler = old_action.sa_sigaction;
    }

    LDAPMSignalRegister(SIGABRT);
    // .......

}
static void LDAPMSignalRegister(int signal) {
    struct sigaction action;
    action.sa_sigaction = LDAPMSignalHandler;
    action.sa_flags = SA_NODEFER | SA_SIGINFO;
    sigemptyset(&action.sa_mask);
    sigaction(signal, &action, 0);
}
static void LDAPMSignalHandler(int signal, siginfo_t* info, void* context) {
    //  获取堆栈,收集堆栈
    ........

    LDAPMClearSignalRigister();

    // 处理前者注册的 handler
    if (previousSignalHandler) {
        previousSignalHandler(signal, info, context);
    }
}

上面的是一个处理 Signal handler 冲突的大概代码思路,下面是 NSException handler 的处理思路,两者大同小异。

static NSUncaughtExceptionHandler *previousUncaughtExceptionHandler;

static void LDAPMUncaughtExceptionHandler(NSException *exception) {
    // 获取堆栈,收集堆栈
    // ......
    //  处理前者注册的 handler
    if (previousUncaughtExceptionHandler) {
        previousUncaughtExceptionHandler(exception);
    }
}

+ (void)installExceptionHandler {
    previousUncaughtExceptionHandler = NSGetUncaughtExceptionHandler();
    NSSetUncaughtExceptionHandler(&LDAPMUncaughtExceptionHandler);
}

补充:来自iOS知识小集

1、自己设备上 Xcode 编译的包发生闪退:连上手机打开 Xcode,cmd+shift+2 呼出 Device 的 Window,如图1所示,然后点击 View Device Logs,然后选中对应时间段自己 app 的崩溃日志。如果此时对应的调用栈还没有符号化,可以选中日志后右键如图2所示 Re-Symbolicate Log 即可。

2、如果是打包服务器或者 Appstore 的包发生闪退:拷贝对应的包和 dSYM 到任意文件夹下,注意将 dSYM 解压以及 .ipa 里面的 .app 取出。然后按照情况1的方式处理即可,Xcode 会自动索引二进制及 dSYM。

  • 如果APP是自己电脑编译生成的,Xcode会根据spotlight自动找到对应的符号文件
  • 如果不是自己电脑编译生成的,只需要将.app和dSYM放入同一文件夹,然后手动生成索引,这样Xcode也能找到。在命令行中输入如下命令手动创建索引:
# mdimport ,导入文件到datastore(import file hierarchies into the metadata datastore)。
mdimport pathName

上面两种方式确保了Xcode能依据UUID找到地址对应的符号文件,这样,Xcode就能解析出崩溃日志。

3、如果拿到别的设备导出的未符号化的崩溃日志,可以将日志拖至下图所示的列表中,注意此时上面 tab 记得选 All Logs 而不是 This Device,然后参考情况2,找到崩溃日志对应的二进制包和 dSYM 文件,按照情况2处理即可。可能会遇到系统库的一些方法无法符号化的问题,只需要找到对应的设备连上电脑,让 Xcode 读取一遍该设备(同机型和系统版本的也可以)的符号表,然后再 Re-Symbolicate 一遍就行。


image

4、遇到线上用户崩溃,无法拿到完整崩溃日志,可以让用户到【设置->分析->分析数据】里面找到对应时间点的崩溃日志,然后截图,根据一个开源工具 dSYMTools,把崩溃栈的关键地址输入到文本框中即可解析出崩溃的那个方法,具体使用方法参考 answer-huang/dSYMTools: dSYM analyze

Ref

iOS开发技巧-崩溃分析

iOS查看线上App崩溃信息及第三方Crash监控

iOS Crash 捕获及堆栈符号化思路剖析

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • 什么是符号表? 符号表是内存地址与函数名、文件名、行号的映射表。符号表元素如下所示: <起始地址> <结束地址> ...
    深圳阳光阅读 12,045评论 28 5
  • 本文就捕获iOS Crash、Crash日志组成、Crash日志符号化、异常信息解读、常见的Crash五部分介绍。...
    xukuangbo_阅读 1,501评论 0 0
  • Determining Whether a Crash Report is Symbolicated(决定是否符号...
    helinyu阅读 1,354评论 0 1
  • 人生的悲伤,有一些是无法说出口的,比如“子欲养而亲不待”,我们都怕失去我们的亲人,比如,只要梦见父亲或者母亲去世,...
    e4b685b8fdc5阅读 139评论 1 2
  • 我喜欢数字7 是因为你对我说过 七年之后我们结婚
    北爱七年阅读 102评论 0 0