iOS 應用包大小瘦身解決辦法

本文是借鑒 戴銘老師 iOS開發高手課 內容總結。

App 的安裝包主要是由資源和可執行文件組成的。

App瘦身:無用圖片、代碼刪除 + 圖片壓縮

目錄

1、蘋果?App Thinning 功能介紹

2、刪除無用圖片 方法?

3、谷歌Webp圖片資源壓縮

4、騰訊公司開發的iSparta? 工具進行圖片壓縮。

5、代碼瘦身:對可執行文件的瘦身方法。(人工查找)

6、LinkMap 結合 Mach-O 找無用代碼

7、通過 AppCode 找出無用代碼

8、通過 ObjC 的 runtime 源碼,我們可以找到怎么判斷一個類是否初始化過的函數


1、充分利用 蘋果官方自帶 App Thinning 功能

1、iOS設備屏幕尺寸、分辨率越來越多,需要更多的資源匹配不同的尺寸和分辨率。而App Thinning會選擇可用于當前設備的資源內容進行下載。iPhone6只會下載2x圖片,iPhone6plus只會下載3x圖片。并且下載適合自己設備的指令集架構文件。

2、App Thinning 有三種方式:

? ? ? ?App Slicing:會在iTunes Connect上傳App后,對App進行切割,創建不同的變體,適用不同的設備

? ? ? ?On-Demand Resources:主要為游戲關卡場景服務的。它會根據用戶的關卡進度下載隨后幾個關卡的資源,并且已經過關的資源也會被刪掉,這樣可以減少初裝App的包大小

? ? ? Bitcode:是針對特定設備進行包大小優化,優化不明顯。

3、使用:Xcode 和 App Store已經幫我們完成大部分工作。我們通過Xcode添加 xcassets目錄,然后將圖片添加到這個目錄既可。添加2x 和 3x分辨率圖片。


2、無用圖片資源優化:刪除無用圖片 和 圖片資源壓縮

1、刪除無用圖片:?

? ? ? ?1> 通過find 命令獲取App安裝包中所有的資源文件。比如 find /Users/..../工程文件

? ? ? ?2>設置用到的資源的類型,比如jpg、gif、png、webp

? ? ? ?3>使用正則匹配在源碼中找出使用到的資源名,比如 pattern = @"@"(.+?)""

? ? ? ?4>使用find命令找到的所有資源文件,再去掉代碼中使用到的資源文件,剩下的就是無用資源了

? ? ? ?5>對于按照規則設置的資源名,我們需要在匹配使用資源的正則表達式里添加相應的規則,比如 @"imgge_%d"

? ? ? ?6>確認無用資源后,就可以對這些無用資源執行刪除操作了。這個刪除操作,你可以使用NSFileManager系統類提供的功能來完成。


2、使用開源的工具來完成以上操作:LSUnusedResources??特別是對于使用編號規則的圖片來說,可以通過直接添加規則來處理。使用方式也很簡單


LSUnusedResources使用


3、谷歌Webp圖片資源壓縮:對于 App 來說,圖片資源總會在安裝包里占個大頭兒。對它們最好的處理,就是在不損失圖片質量的前提下盡可能地作壓縮。目前比較好的壓縮方案是,將圖片轉成 WebP。WebP 是 Google 公司的一個開源項目。

1、WebP特點:

? ? ? ? ? 1>WebP 壓縮率高,而且肉眼看不出差異,同時支持有損和無損兩種壓縮模式。比如,將 Gif 圖轉為 Animated WebP ,有損壓縮模式下可減少 64% 大小,無損壓縮模式下可減少 19% 大小。

? ? ? ? ? 2>WebP 支持 Alpha 透明和 24-bit 顏色數,不會像 PNG8 那樣因為色彩不夠而出現毛邊。

2、圖片轉成 WebP 操作:

Google 公司在開源 WebP 的同時,還提供了一個圖片壓縮工具 cwebp?來將其他圖片轉成 WebP。cwebp 使用起來也很簡單,只要根據圖片情況設置好參數就行。


cwebp 語法如下:cwebp [options] input_file -o output_file.webp

比如,你要選擇無損壓縮模式的話,可以使用如下所示的命令:cwebp -lossless original.png -o new.webp


其中,-lossless 表示的是,要對輸入的 png 圖像進行無損編碼,轉成 WebP 圖片。不使用 -lossless ,則表示有損壓縮。


在 cwebp 語法中,還有一個比較關鍵的參數 -q float。圖片色值在不同情況下,可以選擇用 -q 參數來進行設置,在不損失圖片質量情況下進行最大化壓縮:

? ? ? ? ? ? ? ? ? 小于 256 色適合無損壓縮,壓縮率高,參數使用 -lossless -q 100;

? ? ? ? ? ? ? ? ? 大于 256 色使用 75% 有損壓縮,參數使用 -q 75;

? ? ? ? ? ? ? ? ? 遠大于 256 色使用 75% 以下壓縮率,參數 -q 50 -m 6。


4、騰訊公司開發的iSparta? 工具進行圖片壓縮。

1、優點:iSpart 是一個 GUI 工具,操作方便快捷,可以實現 PNG 格式轉 WebP,同時提供批量處理和記錄操作配置的功能。如果是其他格式的圖片要轉成 WebP 格式的話,需要先將其轉成 PNG 格式,再轉成 WebP 格式。

圖片壓縮完了并不是結束,我們還需要在 ?「顯示圖片」時使用 libwebp 進行解析。這里有一個 iOS 工程使用 ?libwebp 的范例,你可以點擊 這個鏈接?查看。或者使用?pod 'SDWebImageWebPCoder' ?框架或者 ?YYimage 框架。Webp圖片加載使用方法

2、缺點:WebP 在 CPU 消耗和解碼時間上會比 PNG 高兩倍。所以,我們有時候還需要在性能和體積上做取舍。

? ? ? 建議:如果圖片大小超過了 100KB,你可以考慮使用 WebP;而小于 100KB 時,你可以使用網頁工具 TinyPng?或者 GUI 工具 ImageOptim?進行圖片壓縮。這兩個工具的壓縮率沒有 WebP 那么高,不會改變圖片壓縮方式,所以解析時對性能損耗也不會增加。

iSpart工具界面
webp圖片加載使用


5、代碼瘦身:對可執行文件的瘦身方法。

1、可執行文件就是 Mach-O 文件,其大小是由代碼量決定的。通常情況下,對可執行文件進行瘦身,就是 ?「找到并刪除無用代碼」的過程。

2、思路:

? ? ? ? ? ?1>首先,找出方法和類的全集;

? ? ? ? ? ?2>然后,找到使用過的方法和類;

? ? ? ? ? ?3>接下來,取二者的差集得到無用代碼;

? ? ? ? ? ?4>最后,由人工確認無用代碼可刪除后,進行刪除即可。


6、LinkMap 結合 Mach-O 找無用代碼

1、怎么快速找到方法和類的全集:我們可以通過分析 LinkMap 來獲得所有的代碼類和方法的信息。獲取 LinkMap 可以通過將 Build Setting 里的 Write Link Map File 設置為 Yes,然后指定 Path to Link Map File 的路徑就可以得到每次編譯后的 LinkMap 文件了。

LinkMap 文件獲取方法

2、LinkMap 文件分為三部分:Object File、Section 和 Symbols。

其中:1>Object File 包含了代碼工程的所有文件;

? ? ? ? ? ? 2>Section 描述了代碼段在生成的 Mach-O 里的偏移位置和大??;

? ? ? ? ? ? 3>Symbols 會列出每個方法、類、block,以及它們的大小。

通過 LinkMap ,你不光可以統計出所有的方法和類,還能夠清晰地看到代碼所占包大小的具體分布,進而有針對性地進行代碼優化。

3、得到了代碼的全集信息以后,我們還需要找到已使用的方法和類,這樣才能獲取到差集,找出無用代碼。所以接下來,我們要 通過 Mach-O 取到使用過的方法和類。

iOS 的方法都會通過 objc_msgSend 來調用。而,objc_msgSend 在 Mach-O 文件里是通過 __objc_selrefs 這個 section 來獲取 selector 這個參數的。

所以,__objc_selrefs 里的方法一定是被調用了的。__objc_classrefs 里是被調用過的類,__objc_superrefs 是調用過 super 的類。通過 __objc_classrefs 和 __objc_superrefs,我們就可以找出使用過的類和子類。那么,Mach-O 文件的 __objc_selrefs、__objc_classrefs 和 __objc_superrefs 怎么查看呢?

我們可以使用 MachOView?這個軟件來查看 Mach-O 文件里的信息。MachOView 同時也是一款開源軟件,如果你對源碼感興趣的話,可以點擊這個地址查看。

具體的查看方法,我將通過一個案例和你展開。

? ? ? ? ? ? ? ? ?1>首先,我們需要編譯一個 App。

? ? ? ? ? ? ? ? ?2>然后,將生成的 DemoXXX.app 包解開,取出DemoXXX。

? ? ? ? ? ? ? ? ?3>最后,我們就可以使用 MachOView 來查看 Mach-O 里的信息了。

Link-Map
MachOView 軟件打開樣本

可以看到 __objc_selrefs、__objc_classrefs 和、__objc_superrefs 這三個 section。但是,這種查看方法并不是完美的,還會有些問題。原因在于, Objective-C 是門動態語言,方法調用可以寫成在運行時動態調用,這樣就無法收集全所有調用的方法和類。所以,我們通過這種方法找出的無用方法和類就只能作為參考,還需要二次確認。

(缺點:這里只能看到已調用的方法,得去工程里查找為調用的方法,比較麻煩。建議結合 下面 的APPCode方法來進行過濾 找到 未使用的方法、類)


7、通過 AppCode 找出無用代碼(當代碼量過百萬行時 AppCode 的靜態分析會“歇菜”。但是,如果工程量不是很大的話,我還是建議你直接使用 AppCode 來做分析。)

1、AppCode 做分析的方法很簡單,直接在 「AppCode 里選擇 Code->Inspect Code 」就可以進行靜態分析。

AppCode 來做靜態分析
Unused code 里看到所有無用代碼

2、接下來,說一下這些無用代碼的主要類型。

? ? ? ? 1>無用類:Unused class 是無用類,Unused import statement 是無用類引入聲明,Unused property 是無用的屬性;

? ? ? ? ?2>無用方法:Unused method 是無用的方法,Unused parameter 是無用參數,Unused instance variable 是無用的實例變量,Unused local variable 是無用的局部變量,Unused value 是無用的值;

? ? ? ? ?3>無用宏:Unused macro 是無用的宏。

? ? ? ? ?4>無用全局:Unused global declaration 是無用全局聲明。?

【這里結合 上面工具 來進行篩選 ——> 沒有用到的無用類、方法?!浚?!

3、APPCode靜態檢查的問題:

? ? ? ? ?1>JSONModel 里定義了未使用的協議會被判定為無用協議;

? ? ? ? ? 2>如果子類使用了父類的方法,父類的這個方法不會被認為使用了;

? ? ? ? ? 3>通過點的方式使用屬性,該屬性會被認為沒有使用;使用 performSelector 方式調用的方法也檢查不出來,比如 self performSelector:@selector(arrivalRefreshTime);?

? ? ? ? ? ?4>運行時聲明類的情況檢查不出來。比如通過 NSClassFromString 方式調用的類會被查出為沒有使用的類,比如 layerClass = NSClassFromString(@“SMFloatLayer”)。還有以[[self class] accessToken] 這樣不指定類名的方式使用的類,會被認為該類沒有被使用。像 UITableView 的自定義的 Cell 使用 registerClass,這樣的情況也會認為這個 Cell 沒有被使用。

基于以上種種原因,使用 AppCode 檢查出來的無用代碼,還需要人工二次確認才能夠安全刪除掉。


4、即使你使用 LinkMap 結合 Mach-O 或者 AppCode 的方式,通過靜態檢查已經找到并刪除了無用的代碼,那么就能說包里完全沒有無用的代碼了嗎?

實際上,在 App 的不斷迭代過程中,新人不斷接手、業務功能需求不斷替換,會留下很多無用代碼。這些代碼在執行靜態檢查時會被用到,但是線上可能連這些老功能的入口都沒有了,更是沒有機會被用戶用到。也就是說,這些無用功能相關的代碼也是可以刪除的。

8、通過 ObjC 的 runtime 源碼,我們可以找到怎么判斷一個類是否初始化過的函數

1、isInitialized 的結果會保存到元類的 class_rw_t 結構體的 flags 信息里,flags 的 1<<29 位記錄的就是這個類是否初始化了的信息。而 flags 的其他位記錄的信息,你可以參看 objc runtime 的源碼,

2、lags 采用位方式記錄布爾值的方式,易于擴展、所用存儲空間小、檢索性能也好。所以,經常閱讀優秀代碼,特別有助于提高我們自己的代碼質量。

既然能夠在運行中看到類是否初始化了,那么我們就能夠找出有哪些類是沒有初始化的,即找到在真實環境中沒有用到的類并清理掉。


總結:對于上線時間不長的新 App 和那些代碼量不大的 App 來說,做些資源上的優化,再結合使用 AppCode 就能夠有很好的收益。而且把這些流程加入工作流后,日常工作量也不會太大。但是,對于代碼量大,而且業務需求迭代時間很長的 App 來說,包大小的瘦身之路依然任道重遠,這個領域的研究還有待繼續完善。LinkMap 加 Mach-O 取差集的結果也只能作為參考,每次人工確認的成本是非常大的,只適合突擊和應急清理時使用。最后日常采用的方案,可能還是用運行時檢查類的方式,這種大粒度檢查的方式精度雖然不高,但是人工工作量會小很多。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,882評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,208評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,746評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,666評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,477評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,960評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,047評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,200評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,726評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,617評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,807評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,327評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,049評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,425評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,674評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,432評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,769評論 2 372

推薦閱讀更多精彩內容