iOS崩潰捕捉和分析

主題: 如何捕捉發(fā)布版本ipa的崩潰, 并定位崩潰代碼

一怜森、 崩潰日志

  • 1 什么是崩潰日志
    iOS設(shè)備上的應(yīng)用閃退時(shí), 操作系統(tǒng)會(huì)聲稱一個(gè)崩潰日志, 保存在設(shè)備上强胰。
路徑是:  設(shè)置 -> 隱私 ->診斷與用量 ->診斷與用量數(shù)據(jù)蜕乡。在這里可以看到設(shè)備上所有的設(shè)備崩潰日志.
在“診斷與用量”界面,建議用戶選擇自動(dòng)發(fā)送,這樣可以每天自動(dòng)發(fā)送診斷和用量數(shù)據(jù)到itunes草娜,來(lái)幫助開(kāi)發(fā)者分析崩潰.
  • 2如何獲取崩潰日志
    2.1 連接設(shè)備獲取崩潰日志
    設(shè)備與電腦上的ITunes Store同步后, 會(huì)將崩潰日志保存在電腦上,崩潰日志保存在以下位置:
Mac OS X:   ~/Library/Logs/CrashReporter/MobileDevice/
可以看到所有和該電腦同步過(guò)的設(shè)備的崩潰日志(.crash文件)
iOS設(shè)備上的崩潰日志

2.2 通過(guò)Xcode獲取崩潰日志
打開(kāi)Xcode, 菜單欄上選擇Window ->Devices,選中設(shè)備痒筒,點(diǎn)擊View Device Logs -> All logs可以看到所有的崩潰日志宰闰。
選中某一個(gè)崩潰日志,點(diǎn)擊Export Log可導(dǎo)出崩潰日志(.crash文件)


Xcode 查看崩潰日志

2.3 通過(guò)iTunes Connect獲取使用者上傳的崩潰日志
登錄iTunes Connect, 選中APP, 點(diǎn)擊可供銷售的APP(即當(dāng)前最新版本), 在最下面選中額外信息下的崩潰報(bào)告, 可以看到所有iOS版本下的崩潰報(bào)告簿透。


iTunes Connect 崩潰日志

二移袍、iOS 崩潰日志分析

首先來(lái)看一份崩潰日志


iOS崩潰日志

(1)Incident Identifier: 是崩潰報(bào)告的唯一標(biāo)識(shí)符。
(2)CrashReporter Key: 是與設(shè)備標(biāo)識(shí)相對(duì)應(yīng)的唯一鍵值老充。雖然它不是真正的設(shè)備標(biāo)識(shí)符咐容,但也是一個(gè)非常有用的情報(bào):如果你看到100個(gè)崩潰日志的CrashReporter Key值都是相同的,或者只有少數(shù)幾個(gè)不同的CrashReport值蚂维,說(shuō)明這不是一個(gè)普遍的問(wèn)題戳粒,只發(fā)生在一個(gè)或少數(shù)幾個(gè)設(shè)備上。
(3)Hardware Model: 標(biāo)識(shí)設(shè)備類型虫啥。 如果很多崩潰日志都是來(lái)自相同的設(shè)備類型蔚约,說(shuō)明應(yīng)用只在某特定類型的設(shè)備上有問(wèn)題。上面的日志里涂籽,崩潰日志產(chǎn)生的設(shè)備是iPhone 6(但是顯示的是iPhone7,2? 暫時(shí)不清楚原因)苹祟。
(4)Process 是應(yīng)用名稱。中括號(hào)里面的數(shù)字是閃退時(shí)應(yīng)用的進(jìn)程ID评雌。
(5)Version: App版本號(hào)
最重要的兩部分
(1)Exception Type:EXC_CRASH (SIGABRT)
(2)Last Exception Backtrace(即發(fā)生崩潰的原因树枫,也是我們要研究的重點(diǎn))

Xcode會(huì)自動(dòng)符號(hào)化代碼, 翻譯成明文, 如下:

Crash Logs

可以看到發(fā)生崩潰的代碼位于[SCHomePageVC viewDidLoad]方法中第408行。
崩潰的代碼是[NSArrayM insertObject:atIndex:]景东。
找到該行代碼,可以看到崩潰日志中所描述的崩潰發(fā)生的位置砂轻,代碼都和時(shí)機(jī)代碼一致。


崩潰的代碼

崩潰的原因是: The object to add to the array's content. This value must not be nil.

三斤吐、如何通過(guò).crash文件反編譯得到明文的crash文件

步驟如下:
  • Step1: 在桌面上創(chuàng)建一個(gè)空的文件夾, 我將其命名為 DebugTest , 然后將三個(gè)文件放入該文件夾 "MyApp.app" , "MyApp.app.dSYM", "MyApp_2016_4_1.crash"搔涝。
  • Step2 : 打開(kāi)Applications文件夾,找到 symbolicatecrash 文件, Xcode和Xcode以上,文件位置
//終端中輸入以下命令:
cd /Applications/Xcode.app/Contents/SharedFrameworks/DTDeviceKitBase.framework/Versions/A/Resources

然后你會(huì)發(fā)現(xiàn)symbolicatecrash文件和措,長(zhǎng)這個(gè)樣子庄呈,將其拷貝到DebugTest文件夾中

symbolicatecrash

到這一步,你的DebugTest目錄機(jī)構(gòu)應(yīng)該是這樣
(1MyAPP.app
(2)MyApp.app.dSYM
(3)MyApp_2016_4_1.crash
(4)symbolicatecrash

  • Step3: 在終端中輸入以下3條命令
//第一條命令(其中Yourname 應(yīng)該是你的用戶名)
 cd /Users/Yourname/Desktop/DebugTest
// 第二條命令
export DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer"
//第三條命令(二選一)
(Xcode6.3和之前版本輸入以下命令)
./symbolicatecrash -A -v MYApp_2016-4-1.crash MyApp.app.dSYM
(Xcode6.4和之前版本輸入以下命令)
./symbolicatecrash  -v MYApp_2016-4-1.crash MyApp.app.dSYM

然后用控制臺(tái)打開(kāi)你的MyApp_2016_4_1.crash文件, 你就會(huì)看到編譯后的crash文件, 同Xcode看到的崩潰日志一致派阱。通過(guò)查看崩潰日志诬留,可以輕易的找到崩潰原因并修正。

Crash Logs

四、如何在程序崩潰時(shí)手動(dòng)捕捉到崩潰

   當(dāng)我們debug的時(shí)候, 發(fā)生崩潰后可以在控制臺(tái)上看到崩潰的堆棧信息和崩潰日志文兑。上面三種方法都是我們獲取.crash文件后解析的辦法, 那么如果用戶不發(fā)送崩潰日志到iTunes Connect時(shí)傀广,我們?nèi)绾潍@取崩潰信息呢?(盡可能的獲取崩潰信息有助于熱修復(fù)時(shí)定位代碼)彩届。當(dāng)然伪冰,友盟支持搜集崩潰日志,那我們是否也可以在程序崩潰時(shí)樟蠕,將崩潰信息寫(xiě)入本地贮聂,APP再次啟動(dòng)時(shí),將崩潰信息上傳到我們的服務(wù)器寨辩。這里就要用到apple的一個(gè)函數(shù):NSSetUncaughtExceptionHandler吓懈。上代碼:
//application didFinishLaunchingWithOptions中調(diào)用 [self catchCrashLogs];
  
- (void)catchCrashLogs{
    NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
}
void UncaughtExceptionHandler(NSException *exception){
    if (exception ==nil)return;
    NSArray *array = [exception callStackSymbols];
    NSString *reason = [exception reason];
    NSString *name  = [exception name];
    NSDictionary *dict = @{@"appException":@{@"exceptioncallStachSymbols":array,@"exceptionreason":reason,@"exceptionname":name}};
    if([SDFileToolClass writeCrashFileOnDocumentsException:dict]){
        NSLog(@"Crash logs write ok!");
    }
}
//寫(xiě)入緩存中: 以下提供三個(gè)API,分別是:寫(xiě)入靡狞,獲取耻警,清空
NSString * const SDCrashFileDirectory = @"SDMapHomeCrashFileDirectory"; //你的項(xiàng)目中自定義文件夾名
+ (NSString *)sd_getCachesPath{
    return [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
}
+ (BOOL)writeCrashFileOnDocumentsException:(NSDictionary *)exception{
    NSString *time = [[NSDate date] formattedDateWithFormat:@"yyyyMMddHHmmss" locale:[NSLocale currentLocale]];
    NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
    NSString *crashname = [NSString stringWithFormat:@"%@_%@Crashlog.plist",time,infoDictionary[@"CFBundleName"]];
    NSString *crashPath = [[self sd_getCachesPath] stringByAppendingPathComponent:SDCrashFileDirectory];
    NSFileManager *manager = [NSFileManager defaultManager];
    //設(shè)備信息
    NSMutableDictionary *deviceInfos = [NSMutableDictionary dictionary];
    [deviceInfos setObject:[infoDictionary objectForKey:@"DTPlatformVersion"] forKey:@"DTPlatformVersion"];
    [deviceInfos setObject:[infoDictionary objectForKey:@"CFBundleShortVersionString"] forKey:@"CFBundleShortVersionString"];
    [deviceInfos setObject:[infoDictionary objectForKey:@"UIRequiredDeviceCapabilities"] forKey:@"UIRequiredDeviceCapabilities"];
    
    BOOL isSuccess = [manager createDirectoryAtPath:crashPath withIntermediateDirectories:YES attributes:nil error:nil];
    if (isSuccess) {
        NSLog(@"文件夾創(chuàng)建成功");
        NSString *filepath = [crashPath stringByAppendingPathComponent:crashname];
        NSMutableDictionary *logs = [NSMutableDictionary dictionaryWithContentsOfFile:filepath];
        if (!logs) {
            logs = [[NSMutableDictionary alloc] init];
        }
        //日志信息
        NSDictionary *infos = @{@"Exception":exception,@"DeviceInfo":deviceInfos};
        [logs setObject:infos forKey:[NSString stringWithFormat:@"%@_crashLogs",infoDictionary[@"CFBundleName"]]];
        BOOL writeOK = [logs writeToFile:filepath atomically:YES];
        NSLog(@"write result = %d,filePath = %@",writeOK,filepath);
        return writeOK;
    }else{
        return NO;
    }
}
+ (nullable NSArray *)sd_getCrashLogs{
     NSString *crashPath = [[self sd_getCachesPath] stringByAppendingPathComponent:SDCrashFileDirectory];
     NSFileManager *manager = [NSFileManager defaultManager];
     NSArray *array = [manager contentsOfDirectoryAtPath:crashPath error:nil];
     NSMutableArray *result = [NSMutableArray array];
    if (array.count == 0) return nil;
    for (NSString *name in array) {
        NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:[crashPath stringByAppendingPathComponent:name]];
        [result addObject:dict];
    }
    return result;
}
+ (BOOL)sd_clearCrashLogs{
     NSString *crashPath = [[self sd_getCachesPath] stringByAppendingPathComponent:SDCrashFileDirectory];
    NSFileManager *manager = [NSFileManager defaultManager];
    if (![manager fileExistsAtPath:crashPath]) return YES; //如果不存在,則默認(rèn)為刪除成功
    NSArray *contents = [manager contentsOfDirectoryAtPath:crashPath error:NULL];
    if (contents.count == 0) return YES;
    NSEnumerator *enums = [contents objectEnumerator];
    NSString *filename;
    BOOL success = YES;
    while (filename = [enums nextObject]) {
        if(![manager removeItemAtPath:[crashPath stringByAppendingPathComponent:filename] error:NULL]){
            success = NO;
            break;
        }
    }
    return success;
}

Well done!

五、結(jié)論: 為了更好的分析崩潰原因甸怕,在每次上架APP的時(shí)候甘穿,應(yīng)該保留對(duì)應(yīng)的app文件和dsym文件。

六梢杭、參考鏈接:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末温兼,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子武契,更是在濱河造成了極大的恐慌募判,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件咒唆,死亡現(xiàn)場(chǎng)離奇詭異届垫,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)全释,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)装处,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人恨溜,你說(shuō)我怎么就攤上這事符衔。” “怎么了糟袁?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)躺盛。 經(jīng)常有香客問(wèn)我项戴,道長(zhǎng),這世上最難降的妖魔是什么槽惫? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任周叮,我火速辦了婚禮辩撑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘仿耽。我一直安慰自己合冀,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布项贺。 她就那樣靜靜地躺著君躺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪开缎。 梳的紋絲不亂的頭發(fā)上棕叫,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音奕删,去河邊找鬼俺泣。 笑死,一個(gè)胖子當(dāng)著我的面吹牛完残,可吹牛的內(nèi)容都是我干的伏钠。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼谨设,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼贝润!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起铝宵,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤打掘,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后鹏秋,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體尊蚁,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年侣夷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了横朋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡百拓,死狀恐怖琴锭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情衙传,我是刑警寧澤决帖,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站蓖捶,受9級(jí)特大地震影響地回,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一刻像、第九天 我趴在偏房一處隱蔽的房頂上張望畅买。 院中可真熱鬧,春花似錦细睡、人聲如沸谷羞。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)湃缎。三九已至,卻和暖如春萌京,著一層夾襖步出監(jiān)牢的瞬間雁歌,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工知残, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留靠瞎,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓求妹,卻偏偏與公主長(zhǎng)得像乏盐,于是被迫代替她去往敵國(guó)和親逮诲。 傳聞我的和親對(duì)象是個(gè)殘疾皇子纫溃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 寫(xiě)在前面:本文會(huì)在最開(kāi)頭將蘋(píng)果官方的文檔Understanding and Analyzing Applicati...
    小小外星人閱讀 25,637評(píng)論 23 130
  • 當(dāng)一個(gè)應(yīng)用發(fā)生崩潰時(shí)會(huì)產(chǎn)生一份崩潰報(bào)告(Crash Report),該報(bào)告可以幫助我們了解崩潰的產(chǎn)生原因谣膳。該文檔講...
    杰嗒嗒的阿杰閱讀 11,056評(píng)論 0 27
  • 作為一名應(yīng)用開(kāi)發(fā)者净神,你是否有過(guò)如下經(jīng)歷? 為確保你的應(yīng)用正確無(wú)誤何吝,在將其提交到應(yīng)用商店之前,你必定進(jìn)行了大量的測(cè)試...
    姚姚先生閱讀 575評(píng)論 0 1
  • 前言 崩潰是讓發(fā)人員比較頭痛的事情鹃唯,app崩潰了爱榕,說(shuō)明代碼寫(xiě)的有問(wèn)題,這時(shí)如何快速定位到崩潰的地方很重要坡慌。調(diào)試階段...
    進(jìn)無(wú)盡閱讀 1,974評(píng)論 0 9
  • 該文章屬于劉小壯原創(chuàng)黔酥,轉(zhuǎn)載請(qǐng)注明:劉小壯[http://www.reibang.com/u/2de707c93d...
    劉小壯閱讀 37,519評(píng)論 45 122