~ read.

遭遇Crash文件战----教你如何搞定iOS崩溃日志

请叫我背景

最近在提交应用到App Store的时候,竟然被拒了两次。那时候心里的想法是,尼玛完蛋了,要被老板开除了,我是不是要失业了。于是乎那两周几乎毛脑子都是为什么Apple你这么狠心,我们明明相爱了那么多年,你竟然就这样抛弃了我。我不想活了,不要拦着我,我要分分钟切腹给你看。然后内心的纠结并没有什么卵用。而关于第一次被拒我这里就不说了,正对第二次被拒稍微进行拓展。

崩溃被拒

第二次被拒这是因为一个崩溃而被拒的。在我刚看到崩溃的时候就想着,小case,崩溃的bug还是比较好解决的,至少好定位,相对第一次那种没有说明具体原因被拒好查多了。关键是Apple的审核人员还提供了crash的文件给我。在我洋洋得意的下载并且打开苹果方面放给我的崩溃日志的时候,尼玛我又蒙逼了,里面完全没有我熟悉的代码以及行数的显示什么的,跟我所熟知的类型(见下图)完全不一样啊,熟悉的配方,熟悉的味道明明在后面是有大概的错误方法调用的堆栈信息的说。

crash正常文件

特么苹果给我的是一对内存地址的样式(见下图)啊!!!!!!!特么只有一对地址的位置信息,特么你告诉我这怎么看,这怎么看,你过来看我打不打死你!

Crash From Apple

然后我特么自己想重新苹果审核人员重现的Bug特么一直就是重现不了,没办法最后只能去找找看下有没有办法反编译这种加密的崩溃日志。然后我在研究官方文档的时候我看到了一句话叫做:

Symbolication - resolving backtrace addresses to source code methods and lines - requires the application binary that was uploaded to the App Store and the .dSYM file that was generated when that binary was built. This must be an exact match - otherwise, you might get a partially symbolicated crash report.

里面有提到通过上传的二级制文件以及.dSYM文件可以标识化这种只含有追溯地址的崩溃日志,即将我看不懂的这种加密的崩溃日志,转换成我稍微熟悉一点的堆栈信息的崩溃日志。废话不多说,直接说如何做吧。

解密地址堆栈

解密这种地址的崩溃日志只需几步就能搞定了。只要准备好对应的.app的二进制文件以及产生二进制文件的dSYM文件。将"加密"的崩溃日志与这两个文件放置在同一个目录,准备工作就做好了。

  • 第一步,找到DTDeviceKitBase.framework文件所在,不同版本的Xcode这个文件所放的目录都不大一样。下面提供两个参考的路径:
Xcode 6以前:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/PrivateFrameworks/DTDeviceKitBase.framework  
Xcode 6以后(包括):/Applications/Xcode.app/Contents/SharedFrameworks/DTDeviceKitBase.framework  
  • 第二步,建立命令别名,以Xcode 7为例,运行如下命令:
alias symbolicate="/Applications/Xcode.app/Contents/SharedFrameworks/DTDeviceKitBase.framework/Versions/A/Resources/symbolicatecrash -v"  
  • 第三步,更新DEVELOPER_DIR的环境变量,因为如果不跟新的话,在反编译的过程中会出现报错的情况
export DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer"  
  • 第四步,标识化"加密"的崩溃日志,让其变为非地址堆栈的崩溃日志。首先先用cd命令切换到到你准备的.app二进制文件以及dSYM文件所在目录,然后运行如下命令
symbolicate -o "反编译后文件名" "需要反编译的文件" "项目名.app"  

其中反编译后的文件后缀可以用.crash、.txt等文件名,不过我个人喜欢用.crash后缀名,因为可以用系统自带的控制台(Console)来查看,项目名则为你建立项目的时候取的名字。这样你反编译后的文件就产生了,至少崩溃日志是可以看懂了(见文章的第一张图)。

如何查看崩溃日志

好了,获得是人类可读语言的崩溃日志后,或者是从别人手机到处崩溃日志后,下一步就是查看了。下面就正对一个程序猿该如何看稍微说说。

崩溃日志头

Incident Identifier: 635A20F0-BC79-4724-AE45-D49097085250  
CrashReporter Key:   21a348fcc69b56e9f74e9b0078c8d7bbc0ace04a  
Hardware Model:      xxx  
Process:             crashDemo [3131]  
Path:                /private/var/mobile/Containers/Bundle/Application/B2B0DDAE-2E1B-422E-AA4D-99C2578C99E6/crashDemo.app/crashDemo  
Identifier:          com.demo.crashDemo  
Version:             2443 (1.4.2)  
Code Type:           ARM-64 (Native)  
Parent Process:      launchd [1]  
Date/Time:           2015-11-24 17:57:00.00 -0800  
Launch Time:         2015-11-24 17:56:44.44 -0800  
OS Version:          iOS 9.1 (13B143)  
Report Version:      105  
Exception Type:  EXC_CRASH (SIGABRT)  
Exception Codes: 0x0000000000000000, 0x0000000000000000  
Exception Note:  EXC_CORPSE_NOTIFY  
Triggered by Thread:  0  

首先正对这个崩溃日志头,程序猿级别的童鞋只要关注几点就好了。 Process:是在Info.plist文件中key为CFBundleExecutable所填写的名字,首先先确认这个,别到时候发现尼玛这不是自己的崩溃日志 Version:这个则是要关注的第二个点,就是这个崩溃日志产生的版本,因为对于中大型公司来说的话,一般有可能多个版本并行的情况,针对崩溃日志一定要看清楚是哪个版本,这个是由Info.plist文件中的CFBundleVersionCFBundleVersionString组成 OS Version:这个字段则是说我这个崩溃日志是在什么系统上面产生的,iOS 8还是iOS 9?这个总得知道吧,因为有可能你用到了被停用的接口啊,或者是太新的接口在老版本上不兼容啊等问题 'Exception Type':说明崩溃产生的原因,具体的详情可以查看苹果官网
'Triggered by Thread':这个说明在哪个线程上崩溃的,这个一定得看要不然下面一堆堆栈信息完全就不知道看哪个了

崩溃日志的堆栈信息

然后就是找到对应的崩溃堆栈信息来说的话,去找对应的崩溃函数,还是用上方的第一张图来举例:

崩溃日志

其实如果是自己写的代码一眼就能看出来问题所在了,因为能从这个堆栈中找到问题所在。一般这个调用都是从上往下看,最上面的出现你熟悉的代码一般就是问题所在了,如果上图中[JsonUtil dataRequest:Key:Delegate:Info:] (JsonUtil.m:166)一眼就能看出来这个是我的代码,然后我去分析这行代码周围的代码很快就能找到问题所在了。至于其他的就没什么好看了。

结束语

其实除了从苹果审核人员那里获得崩溃日志外,我们还可能通过从测试人员的手机里拷贝出来。一般通过iTunes的同步功能就能讲手机中的崩溃日志拷贝到电脑里面来查看(如下图)。如果是Mac的话目录应该是在/Users/chipsea/Library/Logs/CrashReporter/MobileDevice目录下能看到同步的到的崩溃日志,然后根据日志进行修改Bug吧。最后去屎吧八阿哥!

同步按钮

comments powered by Disqus