1. 程式人生 > >iOS Crash 處理辦法

iOS Crash 處理辦法

在iOS開發除錯過程中以及上線之後,程式經常會出現崩潰的問題。簡單的崩潰還好說,複雜的崩潰就需要我們通過解析Crash檔案來分析了,解析Crash檔案在iOS開發中是比較常見的。

現在網上有很多關於解析崩潰資訊的部落格,但是大多質量參差不齊,或者有些細節沒有注意到。今天寫一篇部落格總結一下我對崩潰除錯的使用和技巧,如果有哪些錯誤或遺漏,還請指點,謝謝!

獲取崩潰資訊

在iOS中獲取崩潰資訊的方式有很多,比較常見的是使用友盟、百度等第三方分析工具,或者自己收集崩潰資訊並上傳公司伺服器。下面列舉一些我們常用的崩潰分析方式:

  • 使用友盟、百度等第三方崩潰統計工具。

  • 自己實現應用內崩潰收集,並上傳伺服器。

  • Xcode-Devices中直接檢視某個裝置的崩潰資訊。

  • 使用蘋果提供的Crash崩潰收集服務。

收集崩潰資訊

蘋果給我們提供了異常處理的類,NSException類。這個類可以建立一個異常物件,也可以通過這個類獲取一個異常物件。

這個類中我們最常用的還是一個獲取崩潰資訊的C函式,我們可以通過這個函式在程式發生異常的時候收集這個異常。

1 2 3 4 5 6 7 8 9 10 11 12 13 // 將系統提供的獲取崩潰資訊函式寫在這個方法中,以保證在程式開始執行就具有獲取崩潰資訊的功能 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 將下面C函式的函式地址當做引數 NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler); return YES; } // 設定一個C函式,用來接收崩潰資訊 void UncaughtExceptionHandler(NSException *exception){ // 可以通過exception物件獲取一些崩潰資訊,我們就是通過這些崩潰資訊來進行解析的,例如下面的symbols陣列就是我們的崩潰堆疊。 NSArray *symbols = [exception callStackSymbols]; NSString *reason = [exception reason];
NSString *name = [exception name]; }

我們也可以通過下面方法獲取崩潰統計的函式指標:

1 NSUncaughtExceptionHandler *handler = NSGetUncaughtExceptionHandler();

dSYM 符號集

進行崩潰分析,首先要弄懂一個概念,就是符號集。

  • 符號集是我們對ipa檔案進行打包之後,和.app檔案同級的字尾名為.dSYM的檔案,這個檔案必須使用Xcode進行打包才有。

  • 每一個.dSYM檔案都有一個UUID,和.app檔案中的UUID對應,代表著是一個應用。而.dSYM檔案中每一條崩潰資訊也有一個單獨的UUID,用來和程式的UUID進行校對。

  • 我們如果不使用.dSYM檔案獲取到的崩潰資訊都是不準確的。

  • 符號集中儲存著檔名、方法名、行號的資訊,是和可執行檔案的16進位制函式地址對應的,通過分析崩潰的.Crash檔案可以準確知道具體的崩潰資訊。

我們每次Archive一個包之後,都會隨之生成一個dSYM檔案。每次釋出一個版本,我們都需要備份這個檔案,以方便以後的除錯。進行崩潰資訊符號化的時候,必須使用當前應用打包的電腦所生成的dSYM檔案,其他電腦生成的檔案可能會導致分析不準確的問題。

blob.png

Archive

當程式崩潰的時候,我們可以獲得到崩潰的錯誤堆疊,但是這個錯誤堆疊都是0x開頭的16進位制地址,需要我們使用Xcode自帶的symbolicatecrash工具來將.Crash和.dSYM檔案進行符號化,就可以得到詳細崩潰的資訊。

崩潰分析

命令列解析Crash檔案

通過Mac自帶的命令列工具解析Crash檔案需要具備三個檔案

  • symbolicatecrash,Xcode自帶的崩潰分析工具,使用這個工具可以更精確的定位崩潰所在的位置,將0x開頭的地址替換為響應的程式碼和具體行數。

  • 我們打包時產生的dSYM檔案。

  • 崩潰時產生的Crash檔案。

我在解析崩潰資訊的時候,首先在桌面上建立一個Crash資料夾,然後將.Crash、.dSYM、symbolicatecrash放在這個資料夾中,這樣進入這個資料夾下,直接一行命令就解決了。

symbolicatecrash我們可以在下面路徑下可以找到,我用的是Xcode7,其他版本Xcode路徑不一樣,請自行Google。

1 /Applications/Xcode.app/Contents/SharedFrameworks/DTDeviceKitBase.framework/Versions/A/Resources/symbolicatecrash

然後Window->Organizer->Archives中,選中archive的版本右擊,選擇Show in Finder就可以獲取dSYM檔案了。

blob.png

dSYM檔案

將.Crash、.dSYM、symbolicatecrash三個檔案都放在我們在桌面建立的Crash資料夾中。

blob.png

Crash資料夾

開啟命令列工具,進入崩潰資料夾中

cd /Users/username/Desktop/崩潰資料夾

使用命令解析Crash檔案

./symbolicatecrash ./*.crash ./*.app.dSYM > symbol.crash

如果上面命令不成功,使用命令檢查一下環境變數

xcode-select -print-path

返回結果:

/Applications/Xcode.app/Contents/Developer/

如果不是上面的結果,需要使用下面命令設定一下匯出的環境變數,然後重複上面解析的操作。

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

解析完成後會生成一個新的.Crash檔案,這個檔案中就是崩潰詳細資訊。圖中紅色標註的部分就是我們程式碼崩潰的部分。

blob.png

解析完成的結果

注意,以下情況不會有崩潰資訊產生:

  • 記憶體訪問錯誤(不是野指標錯誤)

  • 低記憶體,當程式記憶體使用過多會造成系統低記憶體的問題,系統會將程式記憶體回收

  • 因為某種原因觸發看門狗機制

通過Xcode檢視裝置崩潰資訊

除了上面的系統分析工具來進行分析,如果是我們自己直接使用手機連線崩潰或者崩潰之後連線手機,選擇window-> devices -> 選擇自己的手機 -> view device logs 就可以檢視我們的崩潰資訊了。

blob.png

view device logs

只要手機上的應用是這臺電腦安裝打包的,這樣的崩潰資訊系統已經為我們符號化好了,我們只需要進去之後等一會就行(不要相信這裡面的進度重新整理,並不準確),如果還是沒有符號化完畢 ,我們選擇檔案,然後右擊選擇Re-Sysbomlicate就可以。

如果是使用其他電腦進行的打包,我們可以在這裡面將Crash檔案匯出,自己通過命令列的方式進行解析。

使用第三方崩潰分析工具

現在有很多第三方工具都可以進行崩潰統計分析,使用比較多的是友盟崩潰統計,友盟崩潰統計被整合在友盟SDK中,具體用法直接看官方文件是最好的方法,下面列出友盟崩潰統計文件地址。

在這裡我並不推薦友盟這個第三方,而是推薦一個更好用的第三方—bugHD。這個第三方和友盟的最大區別就是可以直接將崩潰資訊分析結合dSYM分析好,在web網頁上展現出來,而且還可以統計崩潰數、崩潰裝置、系統版本等。

下面是我公司使用bugHD統計的一些崩潰情況

blob.png

bugHD

在bugHD伺服器已經幫我們使用dSYM將崩潰符號化完成。我們可以通過點選某條崩潰,檢視詳細崩潰堆疊,以及崩潰裝置分佈和系統分佈。

blob.png

詳細分佈

蘋果自帶崩潰統計工具

蘋果在Xcode中為我們集成了崩潰統計功能,在Window->Organizer->Crashes中可以看到

blob.png

Crashes

蘋果自帶的崩潰統計工具並不推薦用,如果想要使用這個功能,需要使用者在iPhone中進行設定

設定->隱私->診斷與用量->診斷與用量資料(iOS8一下在通用中設定)

選擇自動傳送,並與開發者共享即可

第三方工具惡意覆蓋

崩潰收集統計函式應該只進行一次呼叫,如果用第三方的話也最好只用一個第三方,這樣我們獲取崩潰統計資訊的途徑也是唯一的。

第三方統計工具並不是用的越多越好,使用多個崩潰收集第三方會導致NSSetUncaughtExceptionHandler()函式指標的惡意覆蓋,導致有些第三方不能收到崩潰資訊。

現在很多第三方崩潰收集工具為了確保自己能最大可能的收集到崩潰資訊,會對NSSetUncaughtExceptionHandler()函式指標的惡意覆蓋。因為這個函式是將函式地址當做引數傳遞,所以只要重複呼叫就會被覆蓋,這樣就不能保證崩潰收集的穩定性。

我們解析崩潰資訊時,看到崩潰堆疊只有main.m檔案中的崩潰,並且可以確定不是因為main.m檔案中的bug導致的崩潰,就基本可以確定是NSSetUncaughtExceptionHandler()函式指標被惡意覆蓋。

blob.png

被惡意覆蓋的崩潰堆疊