iOS 啟動連續(xù)閃退保護方案

引言

“如果某個實體表現(xiàn)出以下任何一種特性嘁锯,它就具備自主性:自我修復宪祥、自我保護、自我維護家乘、對目標的自我控制蝗羊、自我改進∪示猓” —— 凱文·凱利

iOS App 有時可能遇到啟動必 crash 的絕境:每次打開 App 都閃退耀找,無法正常使用App。

為了嘗試解決這個問題业崖,微信讀書開發(fā)了 iOS 連續(xù)閃退保護工具:GYBootingProtection野芒,檢測連續(xù)閃退,在連續(xù)閃退出現(xiàn)時双炕,嘗試自修復 App:

本文探討了連續(xù)閃退問題的產(chǎn)生原因狞悲、檢測、修復機制雄家,以及如何在你的項目中引入效诅、測試和使用?GYBootingProtection

連續(xù)閃退檢測

首先要檢測用戶 App 出現(xiàn)了連續(xù)閃退的情況趟济,有兩種檢測方法乱投,捕獲異常和計時器。

1. 捕獲異常

檢測連續(xù)閃退顷编,可以通過捕獲異常來實現(xiàn)戚炫,異常有以下種類:

Mach 異常:EXC_CRASH

UNIX 信號:SIGABRT

NSException 異常:應用層,通過 NSUncaughtExceptionHandler 捕獲

在念茜的漫談 iOS Crash 收集框架一文中詳細介紹了 Mach 異常和 Unix 信號捕獲 crash 的機制媳纬。簡單來說双肤,異常一般產(chǎn)生自 iOS 的微內核 Mach,然后在 BSD 層轉換成 UNIX SIGABRT 信號钮惠,以標準 POSIX 信號的形式提供給用戶茅糜。NSException 是使用者在處理 App 邏輯時,用編程的方法拋出素挽。

如何捕獲異常

通過以下方法捕獲異常:

利用 Mach API 捕獲 Mach 異常

通過 POSIX API 注冊 signal(SIGSEGV,signalHandler) 來捕獲 UNIX 異常信號

注冊 NSUncaughtExceptionHandler 來捕獲應用級異常

Crash 上報工具如 PLCrashReporter 通過注冊 Mach 異常 + UNIX信號 的 handler 達到檢測的目的蔑赘,對用戶提供了處理異常的接口。

如何檢測

可以利用 PLCrashReporter 這類工具來檢測連續(xù)閃退:

首先維護一個計數(shù)變量,表示連續(xù)閃退次數(shù)

在 PLCrashReporter 的 crash handler 中加入邏輯:如果啟動 5s 內 crash 使計數(shù)器加一

每次啟動時缩赛,如果連續(xù)閃退計數(shù) > n耙箍,則檢測到了連續(xù)閃退

啟動后,執(zhí)行一個定時任務酥馍,在 5s 后重置計數(shù)(如果 App 連續(xù)閃退則不會重置)

流程圖

優(yōu)缺點

通過 Mach 異常辩昆、Unix 信號、NSException 異常來檢測閃退旨袒,能獲得更多的 crash 上下文汁针,但由于 crash 收集框架多使用這些方法,可能會有這樣的風險:與第三方 crash 收集框架沖突導致漏檢測砚尽。另外扇丛,可能會與 App 已有的異常處理代碼產(chǎn)生耦合。

2. 計時器方法

除了通過捕獲異常的方式檢測連續(xù)閃退尉辑,還可以通過計數(shù)器方法來檢測:

維護一個計數(shù)變量,用于表示連續(xù)閃退的次數(shù)

在啟動 application:didFinishLaunchingWithOptions: 后使計數(shù)加一

接著使用 dispatch_after 方法在 5s 后清零計數(shù)较屿,如果 App 活不過 5 秒計數(shù)就不會被清零

如果發(fā)現(xiàn)計數(shù)變量 > n隧魄,表明 App 連續(xù) n 次連續(xù)閃退,啟動保護流程隘蝎,重置計數(shù)购啄。

當保護流程完成后,進入 App 正常啟動流程

流程圖

優(yōu)缺點

而計數(shù)器方法邏輯簡單嘱么,與原有的代碼耦合小狮含。雖然有誤報可能(在啟動后立即被 kill 掉,誤認為 crash)曼振,但是可以通過設置閾值來減小誤報的誤報率几迄。

綜上權衡,我們使用計時器方法檢測連續(xù)閃退冰评。

連續(xù)閃退修復

檢測到連續(xù)閃退后映胁,接下來要嘗試對閃退進行修復,這里先分析可能的閃退原因甲雅,再結合微信讀書的例子說明修復流程解孙。

閃退原因

連續(xù)閃退,可能是 App 啟動關鍵路徑中執(zhí)行了必 crash 的代碼抛人,原因可能有:

數(shù)據(jù)庫損壞:在日常使用如異常退出弛姜、斷電,或者錯誤的操作(參考:sqlite corruption causes)妖枚。

文件損壞:處理文件時如果沒有?@try...catch廷臼,損壞文件會拋出?NSException?導致 crash

網(wǎng)絡返回數(shù)據(jù)處理異常:比如預期返回數(shù)組,但實際返回了字典,對字典對象執(zhí)行?-objectAtIndex?方法會產(chǎn)生?crash: unknow selector send to object中剩;忌穿,或返回破損的 Tar 包,在解壓失敗導致 crash结啼。

代碼 bug:當必 crash 的代碼出現(xiàn)在啟動關鍵路徑中掠剑,就會導致連續(xù)閃退。

針對 1郊愧,可以通過工具修復數(shù)據(jù)庫朴译,或者刪除 DB。針對2属铁,可以刪除文件來進行修復眠寿。對于 3 和 4,我們需要具體地分析 crash 案例焦蘑,通過 JSPatch 來進行修復盯拱。

微信讀書的修復流程

為了應對上述導致連續(xù)閃退的原因,微信讀書的修復流程為:

進入 didFinishLaunch 時檢查是否有連續(xù)閃退例嘱,無則執(zhí)行 5

彈 Toast 提示用戶是否修復狡逢,輕觸『修復』執(zhí)行2,否則執(zhí)行 5

嘗試下載并執(zhí)行 JSPatch 補丁

這里是為了解決上述第4點 - 代碼 bug 導致的閃退拼卵,使用 JSPatch?[github]可以進行熱修復奢浑。在 didFinishLaunching 時,會卡住界面發(fā)請求檢查是否有可用的 JSPatch 腳本腋腮,如果有則加載執(zhí)行雀彼,解決代碼 bug 導致的閃退。

嘗試刪除?Documents?/?Library?/?Caches?目錄下的所有文件

這里直接刪除了所有用戶數(shù)據(jù)即寡,適用于微信讀書這種所有數(shù)據(jù)都在云端徊哑,刪除后可以完全從云端恢復。如果你的 App 不屬于這種場景嘿悬,那么應該在 repairBlock 中自定義修復邏輯实柠,比如:

a. 不刪除文件,只修復數(shù)據(jù)庫

b. 修復前把用戶數(shù)據(jù)備份到云端

c. 收集 crash 樣本善涨,查明原因窒盐,定制 JSPatch 修復補丁并下發(fā)

退出微信讀書登錄狀態(tài)

進入原 didFinishLaunch

連續(xù)閃退檢測 + 保護流程如圖所示:

實現(xiàn)

檢測和連續(xù) crash 并修復需要修改原?-application:didFinishLaunchingWithOptions:?邏輯,有幾種方法:

直接修改?-application:didFinishLaunchingWithOptions:?方法钢拧。

新建一個?SubAppDelegate?類來繼承?AppDelegate蟹漓,覆蓋?-application:didFinishLaunchingWithOptions:?方法,然后把?main()?函數(shù)中的?AppDelegate?替換為?SubAppDelegate

新建一個?AppDelegate?擴展源内,然后用 method swizzle 的方法替換?-application:didFinishLaunchingWithOptions:?方法葡粒。

上述三種方案,對現(xiàn)有項目改動代價是 1 > 2 > 3。因此嗽交,我們使用對源碼修改代價最小的方案 3 來替換?-application:didFinishLaunchingWithOptions:卿嘲。

檢測的邏輯 GYBootingProtection 已經(jīng)處理好,修復的處理預留了接口夫壁,可以由用戶自定義拾枣,把自定義的修復流程傳入 repairBlock 即可。

使用

引入項目

下載?(github)?源碼 盒让,將?src?目錄下所有文件拖拽到你的 Xcode 項目

在?AppDelegate+GYBootingProtection.m?的?onBeforeBootingProtection?方法中添加檢測前需要執(zhí)行的代碼梅肤,比如設置crash上報:

1

2

3

4

5

6

7

8

9

10

- (void)onBeforeBootingProtection {

[GYBootingProtection setLogger:^(NSString*msg) {

// setup logger

NSLog(@"%@", msg);

? }];


[GYBootingProtection setReportBlock:^(NSIntegercrashCounts) {

// setup crash report

? }];

}

在?onBootingProtection?方法中添加修復邏輯,比如刪除文件:

1

2

3

4

5

6

7

- (void)onBootingProtection {

// 檢查 JSPatch 更新

...

// 刪除 Documents Library Caches 目錄下所有文件

[GYBootingProtection deleteAllFilesUnderDocumentsLibraryCaches];

? ...

}

如需執(zhí)行異步的修復邏輯邑茄,在?onBootingProtectionWithCompletion:?方法添加修復邏輯姨蝴,并在完成修復后調用 completion :

1

2

3

4

5

6

7

8

- (void)onBootingProtectionWithCompletion:(BoolCompletionBlock)completion {

[selfonBootingProtection];

// 異步修復

[selfasyncRepairWithCompletion:^(void) {

// 正常啟動流程

if(completion) completion();

? }];

}

測試

首先制造連續(xù)閃退場景:

啟動后 5 秒內,雙擊 Home 通過上劃手勢 kill 掉 App肺缕,重復多次左医。(也可以在代碼里人為制造crash)

當連續(xù)閃退超過 5 次時,會提示用戶修復:

用戶輕觸修復同木,App 重置初始狀態(tài)炒辉,連續(xù)閃退問題解決:

源碼

https://github.com/liuslevis/GYBootingProtection


https://wereadteam.github.io/2016/05/23/GYBootingProtection/

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市泉手,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌偶器,老刑警劉巖斩萌,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異屏轰,居然都是意外死亡颊郎,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門霎苗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來姆吭,“玉大人,你說我怎么就攤上這事唁盏∧诶辏” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵厘擂,是天一觀的道長昆淡。 經(jīng)常有香客問我,道長刽严,這世上最難降的妖魔是什么昂灵? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上眨补,老公的妹妹穿的比我還像新娘管削。我一直安慰自己,他們只是感情好撑螺,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布含思。 她就那樣靜靜地躺著,像睡著了一般实蓬。 火紅的嫁衣襯著肌膚如雪茸俭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天安皱,我揣著相機與錄音调鬓,去河邊找鬼。 笑死酌伊,一個胖子當著我的面吹牛腾窝,可吹牛的內容都是我干的。 我是一名探鬼主播居砖,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼虹脯,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了奏候?” 一聲冷哼從身側響起循集,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蔗草,沒想到半個月后咒彤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡咒精,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年镶柱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片模叙。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡歇拆,死狀恐怖,靈堂內的尸體忽然破棺而出范咨,到底是詐尸還是另有隱情故觅,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布渠啊,位于F島的核電站逻卖,受9級特大地震影響,放射性物質發(fā)生泄漏昭抒。R本人自食惡果不足惜评也,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一炼杖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧盗迟,春花似錦坤邪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至邮弹,卻和暖如春黔衡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背腌乡。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工盟劫, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人与纽。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓侣签,卻偏偏與公主長得像,于是被迫代替她去往敵國和親急迂。 傳聞我的和親對象是個殘疾皇子影所,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內容

  • 引言 “如果某個實體表現(xiàn)出以下任何一種特性,它就具備自主性:自我修復僚碎、自我保護猴娩、自我維護、對目標的自我控制勺阐、自我改...
    Arthurcsh閱讀 1,874評論 0 3
  • 引言 “如果某個實體表現(xiàn)出以下任何一種特性胀溺,它就具備自主性:自我修復、自我保護皆看、自我維護、對目標的自我控制背零、自我改...
    隨身9把刀閱讀 818評論 1 3
  • 連續(xù)閃退檢測 首先要檢測用戶 App 出現(xiàn)了連續(xù)閃退的情況腰吟,有兩種檢測方法,捕獲異常和計時器徙瓶。 1. 捕獲異常 檢...
    驚仙閱讀 7,931評論 2 3
  • 1. crash的類型 crash一般產(chǎn)生自 iOS 的微內核 Mach毛雇,然后在 BSD 層轉換成 UNIX SI...
    oncezou閱讀 3,285評論 0 1
  • 今天心情很好,狀態(tài)也很好侦镇,我覺得是光合作用灵疮。是種特別的力量,當然偶爾也需要陰天來舒緩煩躁壳繁。 我有點理想化的想法:不...
    WoodSage閱讀 159評論 0 1