描述
模拟器和真机调试运行正常,但是导出ipa包安装运行出现奔溃。记录一下提醒一下遇到同样问题的人少走弯路。
思路
首先遇到问题,头脑要保持清醒。思考为什么会出现这样的问题?
- 模拟器和真机调试运行正常,模拟器和真机调试是在
DeBug
模式下运行的 - 导出
ipa包
的环境是Release
模式下
所以可以重点是在Release模式下查看崩溃信息才能定位问题。
查看ipa包崩溃日志
手机数据线连接电脑,借助克魔助手就可以看,Xcode
-> Window
-> Devices and Simulator
进入后,选择【View Device Logs】
日志文件看的好难受,好像也没有办法定位具体问题,接着分析
刚才不是分析在Release
模式下出现的问题嘛,所以可以直接将本地调试的Dudeg
的模式修改为Relese
模式,然后运行。
默认是Debug
模式,选择Release
模式,然后本地调试的时候就和导出的ipa环境一致啦。
同时记得要勾选 【Zombie Ojects】,可以定位出野指针和僵尸对象。然后运行Xcode,可以定位到具体问题啦,同时控制台也输出了使用的对象提前释放导致的问题。
简单查看手机崩溃信息几种方式
方式1:手机设置查看崩溃日志
步骤:【设置】-> 【隐私】 -> 【分析与改进】-> 【分析数据】
方式2: Xocde工具
手机数据线连接电脑,借助Xcode就可以看,Xcode
-> Window
-> Devices and Simulator
,具体和上面一致,请参照上图示例。
方式3: 第三方软件克魔助手
通过数据线连接 iOS 手机和电脑
在iOS应用开发过程中,调试日志和奔溃日志是开发者必不可少的工具。然而,使用Xcode Console等工具查看日志可能不够方便,而且处理奔溃日志也相当繁琐。克魔助手的出现为开发者带来了极大的便利,本文将详细介绍其功能和使用方法。 克魔助手会提供两种日志,一种是实时的,一种的是崩溃的。(由于崩溃日志的环境很麻烦,目前只展示实时日志操作步骤)
环境配置
- 电脑一台(台式和笔记本都OK)
- iPhone 手机一台
- 下载克魔助手
- 下载爱思助手或者itunes驱动
实时日志
克魔助手提供了实时日志功能,能够在电脑上实时查看设备的日志信息。 下面是操作步骤:
1.先将 iPhone 通过数据线连接上电脑,iOS 手机上一定要信任这次连接
2.在电脑上打开克魔助手-实时日志。
3.因为你已经通过数据线连接了电脑和手机,所以此时在控制台的左侧工具栏里会显示你的设备,如果此时直接点击 开始日志那将输出的是此设备的所有日志,那么如果想要查看某一App的日志查看起来是非常繁琐的,那我就需要对App继续筛选过滤再输出。
4.选择需要查看iPhone里面的App(可以通过 command+ 空格,搜索应用),然后点击 开始日志,将会输出关于此App的所有日志
5.如果需要对App里面的关键字继续过滤处理,可关键字那直接输入后点击清空日志,再点击空白处即可过滤成功
6.当你过滤出来了错误信息后,你可以将这些错误日志存储起来,形成一个 errorlog 提交给到开发,点击 导出日志即可生成一个文件夹。
奔溃日志分析
克魔助手还提供了奔溃日志分析查看模块,可以方便地导出和查看iOS设备上的奔溃日志,并对其进行符号化、格式化和分析。 操作如下:
1.选择需要查看的奔溃日志。
2.点击“导出日志”,即可生成一个包含奔溃日志的文件夹,便于提交给开发团队进行分析。
PS:数据连接时,先将 iPhone 通过数据线连接上电脑,iOS 手机上一定要信任这次连接,(开启WiFi调试时,无需数据线)
方式四:控制台资源库
可以看到所有和该电脑同步过的设备的崩溃日志(.crash文件)
输入下方的文件地址:
~/Library/Logs/CrashReporter/MobileDevice
找到自己手机设备的日志信息
开发程序过程也会出现程序crash的情况,那么这时生成的文件目录为:
~/Library/Logs/DiagnosticReports/
线上崩溃日志
线上监听crash的几种方式
方式1: 三方平台的SDK
例如:腾讯Bugly、crashlytics、友盟SDK
方式2: 自己实现异常监听,然后提交后台
自己实现异常监听的方式稍微复杂点,需要异步监听任务,不能影响到主进程的任务体验
常见的造成的崩溃的情况
1.数组越界
在取数据索引时越界,App 会发生崩溃。还有一种情况,就是给数组添加了 nil 会崩溃
2.多线程问题
在子线程中进行 UI 更新可能会发生崩溃。多个线程进行数据的读取操作,因为处理时机不一致,比如有一个线程在置空数据的同时另一个线程在读取这个数据,可能会出现崩溃情况。
3.主线程无响应
如果主线程超过系统规定的时间无响应,就会被 Watchdog 杀掉。这时,崩溃问题对应的异常编码是 0x8badf00d。
4.野指针
野指针指向一个已删除的对象访问内存区域时,会出现野指针崩溃。野指针问题是需要我们重点关注的,因为它是导致 App 崩溃的最常见,也是最难定位的一种情况
信号可捕捉 | 信号不可捕捉 |
KVO问题 | 后台任务超时 |
NSNotification线程问题 | 内存打爆 |
数组越界 | 主线程卡顿超阀值 |
野指针 | .... |
信号可捕获的崩溃日志收集
打开 Xcode 的菜单选择 Product -> Archive
然后,在提交时选上“Upload your app’s symbols to receive symbolicated reports from Apple”,以后你就可以直接在 Xcode 的 Archive 里看到符号化后的崩溃日志了。
但是这种查看日志的方式,每次都是纯手工的操作,而且时效性较差。所以,目前很多公司的崩溃日志监控系统,都是通过克魔助手这样的第三方开源库捕获崩溃日志,然后上传到自己服务器上进行整体监控的。
信号捕获的原理
在崩溃日志里,你经常会看到下面这段说明:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
它表示的是,EXC_BAD_ACCESS
这个异常会通过 SIGSEGV
信号发现有问题的线程。虽然信号的种类有很多,但是都可以通过注册 signalHandler
来捕获到。
其实现代码,如下所示:
void registerSignalHandler(void) { signal(SIGSEGV, handleSignalException); signal(SIGFPE, handleSignalException); signal(SIGBUS, handleSignalException); signal(SIGPIPE, handleSignalException); signal(SIGHUP, handleSignalException); signal(SIGINT, handleSignalException); signal(SIGQUIT, handleSignalException); signal(SIGABRT, handleSignalException); signal(SIGILL, handleSignalException); } void handleSignalException(int signal) { NSMutableString *crashString = [[NSMutableString alloc]init]; void* callstack[128]; int i, frames = backtrace(callstack, 128); char** traceChar = backtrace_symbols(callstack, frames); for (i = 0; i <frames; ++i) { [crashString appendFormat:@"%s\n", traceChar[i]]; } NSLog(crashString); }
上面这段代码对各种信号都进行了注册,捕获到异常信号后,在处理方法 handleSignalException
里通过 backtrace_symbols
方法就能获取到当前的堆栈信息。堆栈信息可以先保存在本地,下次启动时再上传到崩溃监控服务器就可以了。
信号不可捕获的崩溃日志收集
App 退到后台后,即使代码逻辑没有问题也很容易出现崩溃。而且,这些崩溃往往是因为系统强制杀掉了某些进程导致的,而系统强杀抛出的信号还由于系统限制无法被捕获到。
iOS 后台保活的 5 种方式
- Background Mode
- Background Fetch
- Silent Push
- PushKit
- Background Task (App 退后台后,默认都会使用这种方式)
采集过程原理
Background Task 这种方式,就是系统提供了beginBackgroundTaskWithExpirationHandler 方法来延长后台执行时间,可以解决你退后台后还需要一些时间去处理一些任务的诉求。
- (void)applicationDidEnterBackground:(UIApplication *)application { self.backgroundTaskIdentifier = [application beginBackgroundTaskWithExpirationHandler:^( void) { //你的任务逻辑 [self yourTask]; }]; }
在这段代码中,yourTask 任务最多执行 3 分钟,3 分钟内 yourTask 运行完成,你的 App 就会挂起。 如果 yourTask 在 3 分钟之内没有执行完的话,系统会强制杀掉进程,从而造成崩溃,这就是为什么 App 退后台容易出现崩溃的原因。
采用 Background Task 方式时,我们可以根据 beginBackgroundTaskWithExpirationHandler 会让后台保活 3 分钟这个阈值,先设置一个计时器,在接近 3 分钟时判断后台程序是否还在执行。如果还在执行的话,我们就可以判断该程序即将后台崩溃,进行上报、记录,以达到监控的效果。
崩溃日志分析
我们采集到的崩溃日志,主要包含的信息为:进程信息、基本信息、异常信息、线程回溯。
- 进程信息:崩溃进程的相关信息,比如崩溃报告唯一标识符、唯一键值、设备标识;
- 基本信息:崩溃发生的日期、iOS 版本;
- 异常信息:异常类型、异常编码、异常的线程;
- 线程回溯:崩溃时的方法调用栈。
一些被系统杀掉的情况,我们可以通过异常编码来分析。
常见的就是如下三种: - 0x8badf00d,表示 App 在一定时间内无响应而被 watchdog 杀掉的情况。
- 0xdeadfa11,表示 App 被用户强制退出。
- 0xc00010ff,表示 App 因为运行造成设备温度太高而被杀掉。