app上架后,通过崩溃统计平台,可以看到用户的崩溃日志,有了崩溃日志,和该发布包对应的dSYM文件,我们就可以定位到发生崩溃的代码。那么第一步,就是找到对应包体的dSYM文件,并确认与崩溃日志的对应关系。
通过UUID确认对应关系
如果是通过Xcode的Archive打包,可通过以下路径找到dSYM文件:
$ cd ~/Library/Developer/Xcode/Archives/yyyy-mm-dd/appname.xcarchive/dSYMs
在终端进入dSYM文件所在路径,运行以下命令(dSYM文件的路径是xcarchive/dSYMs/):
$ dwarfdump --uuid YourApp.app.dSYM
你将得到以下结果,它们分别对应32位、64位处理器的机子(iphone5S之前的机器为32位机):
$ UUID: FDCFADE2-9A18-3631-80F4-84601BFB47C7 (armv7) YourApp.app.dSYM/Contents/Resources/DWARF/YourApp
$ UUID: 3393365E-FB29-381C-AE01-F14ABB8E458A (arm64) YourApp.app.dSYM/Contents/Resources/DWARF/YourApp
而崩溃日志的UUID位于日志中Binary Images第一行尖括号内。如下面所示,
Binary Images:
0x1029b0000 - 0x10394bfff +YourApp arm64 <8309e255de663204b3e9ddd4138e3111>
/var/containers/Bundle/Application/AFD507CF-5D16-4518-BD70-D725FF0CFA84/YourApp.app/YourApp
UUID一旦对应上了,就进入下一步,符号化。像上面举的例子,UUID就没对应上,不能进行符号化。
局部符号化
所谓局部符号化,就是对崩溃日志中的某一个崩溃地址进行符号化,与全局符号化相对应。这里我们需要两个地址,一个是二进制镜像运行时加载的地址(后面简称段地址),一个是崩溃代码所在的调用栈地址。
以上面的崩溃日志片段为例,“Binary Images:”后面跟着的 0x1029b0000 为段地址,结合下面截取的崩溃日志片段,崩溃时的调用栈地址是0x0000000102c124c4。
Last Exception Backtrace:
0 CoreFoundation 0x000000018184b164 0x181708000 + 1323364
1 libobjc.A.dylib 0x0000000180a94528 0x180a8c000 + 34088
2 CoreFoundation 0x00000001817e3c9c 0x181708000 + 900252
3 CoreFoundation 0x0000000181718b0c 0x181708000 + 68364
4 YourApp 0x0000000102c124c4 0x1029b0000 + 2499780
这里使用的是atos工具,一个可以把地址转换为函数名(包括行号)的工具, atos 语法:
atos -arch arm64 -o ‘dysm文件路径’ -l 段地址 调用栈地址1 调用栈地址2
按照上面的例子,此处命令应为:
$ atos -arch arm64 -o '~/.../xxx.xcarchive/dSYMs/YourApp.app.dSYM/Contents/Resources/DWARF/YourApp' -l 0x1029b0000 0x0000000102c124c4
该命令使用的参数:
- -arch —— 所运行设备的架构,有arm64,armv7
- -o —— 符号文件或者含有调试符号的可执行文件(debug编译所产生的可执行文件默认是包含调试符号的)。
- -l —— 二进制镜像运行时加载的地址,这里也称段地址
- 最后跟着的就是需要符号化的调用栈地址
终端输出:
$ main (in YourApp) (main.m:16)
注意:
0x1029b0000 + 2499780 = 0x0000000102c124c4
全局符号化
使用以上方法进行符号化的范围有限,效率太低,有没有一次性对整个崩溃日志进行符号化的操作,当然是有的,Xcode本身就有提供这么一个工具。首先,找到这个工具,命令如下:
$ find /Applications/Xcode.app -name symbolicatecrash -type f
我的机子安装的是Xcode版本是9.3,终端输出如下,这里我使用的是最后一个路径的symbolicatecrash工具:
$ /Applications/Xcode.app/Contents/Developer/Platforms/WatchSimulator.platform/Developer/Library/PrivateFrameworks/DVTFoundation.framework/symbolicatecrash
$ /Applications/Xcode.app/Contents/Developer/Platforms/AppleTVSimulator.platform/Developer/Library/PrivateFrameworks/DVTFoundation.framework/symbolicatecrash
$ /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/PrivateFrameworks/DVTFoundation.framework/symbolicatecrash
$ /Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash
方法一
对这个工具的使用,有两种方法,一种是把symbolicatecrash、YourApp.app.dSYM、*.crash文件放到一个文件夹里面,还有一种,就是直接使用原始路径下的symbolicatecrash,但每次都输入那么长一串路径确实不方便,这里建议先对symbolicatecrash设置一个使用的alias,命令如下:
$ alias symbolicatecrash="/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash"
然后再执行:
$ export 'DEVELOPER_DIR'="/Applications/Xcode.app/Contents/Developer"
如果不执行此命令,进行下面的操作时会报以下错误:
$ Error: "DEVELOPER_DIR" is not defined at /Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash line 69.
设置完这一切之后,在终端切换到YourApp.app.dSYM、*.crash文件所在路径下,就可以使用以下命令进行符号化了(-o也可改为>):
symbolicatecrash 崩溃日志 dSYM文件 -o 输出文件
实际操作如下(符号化后的崩溃日志将写入该路径下的processed.crash中):
$ symbolicatecrash ./*.crash ./YourApp.app.dSYM -o processed.crash
方法二
如果设置alias失败,可以使用方法二,把symbolicatecrash复制到操作路径下,执行以下命令:
$ ./symbolicatecrash ./*.crash ./YourApp.app.dSYM -o processed.crash
批量符号化
前面提到Xcode提供了符号化工具,那么我们可以直接使用Xcode进行符号化吗,答案当然是可以的。
如果是本机编译的包,那么打开Xcode->Window->Devices and Simulators,选择Devices->View Device Logs,找到我们需要分析的crash文件,一般情况下,这时候Xcode已经替你自动符号化好了。如果没有,可以右键crash文件,选择Re-Symbolicate Log。
如果非本设备的crash文件,可以把crash文件拖进去DeviceLogs列表,其他操作同上。
如果是非机编译的包,我们需要把对应的dSYM文件放入某个文件夹下,然后执行手动索引命令 “mdimport 文件夹路径“,如:
$ mdimport ~/CrashAnalyze
再回去Xcode看,就可以看到符号化好的crash文件了。借助这个方法,我们可以把所有版本的.dSYM文件,都放入该路径下,然后把崩溃日志集体拖入Xcode中,这样就可以实现批量符号化了,大大提供了工作效率。
注意:
进行该操作时,我只是创建了个空的CrashAnalyze文件夹,忘记把dSYM文件放进去,执行了mdimport命令之后,竟然也实现了自动符号化,原因不明。
自动符号化
现在更流行的,也是更适合团队项目质量管控的做法,是使用crash report管理系统来管理crash,譬如国外的Crashlytics,还有国内的Bugtags。这些只要引入该第三方的SDK,进行启动时注册,然后在管理平台进行版本管理就可以了,此处就不进行详述了。