iOS安裝包瘦身小記
將IPA包修改後綴名為ZIP,解壓縮後,獲取payload中的App檔案,檢視App檔案的內容,你會發現該檔案主要包含以下內容
- Exectutable : 可執行檔案
-
Resources
:資原始檔
- 圖片資源:Assets.car /bundle/png/jpg 等
- 視訊/音訊資源:mp4/mp3 等
- 靜態網頁資源:html/css/js 等
- 檢視資源:xib/storyboard 等
- 其他:文字/字型/證書 等
-
Framework
:
- SwiftSupport: libSwiftxxx 等一系列 Swift 庫
- 其他依賴庫:Embeded Framework
-
Pulgins
:Application Extensions
- appex:其組成大致與 ipa 包組成一致
2、組成分析
- 一般來說,可執行檔案、圖片資源(asset.car)和動態庫的佔比最大,如果是Swift和OC混編,可執行檔案比純OC大很多
- 從優化的效果上看,優化圖片資源的ROI比較大,如果是首次優化,建議從圖片資源的優化開始。
- 專案中使用Swift,會增加安裝包大小,因為FrameWork中會加入為了支援 Swift 的動態庫集合,如果純Swift專案,不會引入這些東西。
二、資原始檔優化
理論上,資原始檔包括:圖片**、視訊 、**音訊和字型等;實際上,視訊和音訊檔案一般不會整合到安裝包中,在安裝包中的資原始檔主要是圖片。
1、優化手段1:App Slicing
- iOS9之後提供了App Thinning三件套:App Slicing 、On Demand Resouces 、Bitcode ;
App Thinning | 理想 | 現實 |
---|---|---|
App Slicing | 將App Bundle資源根據不同的裝置特性分為不同的版本。對於圖片資源,會根據裝置所需圖片解析度不同分發給對應裝置所需對應的圖片資源。 | 主要是圖片資源的Slicing,我們有自己的方案,沒有采用 |
On Demand Resources | App的資源只有要使用時才下載,如果其他資源需要空間這些資源可以被移除 | 更適合遊戲類App,專案沒有使用 |
Bitcode | Bitcode可以作為中間產物一起提交AppStore。包含Bitcode配置的程式將會在AppStore上被編譯和連結。Bitcode允許蘋果在後期重新優化我們程式的二進位制檔案,而不需要我們重新提交一個新的版本到AppStore上 | 使用BitCode的要求所有程式碼都支援BitCode,改動專案較大,沒有使用 |
說明:可以充分利用App Slicing實現圖片資源的瘦身
- 在專案中引入圖片時候,直接在Assets.xcassets 中新增就可以(資原始檔用Asset Catalog 管理),這樣能使用到App Slicing 功能,這樣當用戶從App Store上下載App時,可以只下載適用於其裝置的App架構版本和所需資源,從而減少App所佔的空間。
- 在實踐中發現,有的新同學在Assets.xcassets 中引入@1x的圖片,iPhone手機目前需要的@2x和@3x圖片,所以@1x的圖片顯然是不需要的。
- 在實踐中還發現,有的圖片資源遊離在Assets.xcassets之外,這些可以考慮是否可以放入Assets.xcassets 中(大部分情況下是可以放入的)
2、優化手段2:Xcode編譯項
-
因為絕大部分引入的圖片是PNG格式,Xcode 提供的給我們兩個編譯選項來幫助壓縮 PNG 資源:
-
Compress PNG Files:設定為YES,打包的時候自動對圖片進行無失真壓縮,使用的工具為pngcrush,壓縮比還是相當高的,比較流行的壓縮軟體ImageOptim 也是使用 pngcrush 進行壓縮 PNG 的。
-
Remove Text Medadata From PNG Files:設定為YES,能幫助我們移除 PNG 資源的文字字元,比如影象名稱、作者、版權、創作時間、註釋等資訊。
-
引入專案的PNG資源自動被 Xcode 進行壓縮了,但是如果是使用Bundle管理的資源,不會被Xcode壓縮,可以使用tinypng壓縮。
3、優化手段3:清理無用的資源
- 及時清理不使用的圖片資源 。使用類似LSUnusedResources 清理舊的圖片檔案。
- LSUnusedResources的思路是,先獲取圖片檔案(imageset, jpg, png, gif)集合A,然後搜尋程式碼檔案中所有字串名稱得到B,然後從A集合中排除集合B就得到未使用的圖片資源。
4、優化手段4:圖片檔案去重
- 遍歷圖片檔案,計算每個檔案的MD5值,然後以MD5值為key,檔案路徑存入key對應的陣列;
- 遍歷字典values,將value的陣列大小大於1的路徑輸出,這樣就找到重複圖片的路徑了。
5、優化手段5:更適合的圖片格式
- iconfont 代替專案中純色小圖示,也省去很多@2x和@3x的圖片切圖。
- PNG切圖的替換方案,如PDF向量圖來代替大部分簡單的png切圖 ;然後在程式碼中自己解碼並展示出來,一套PDF向量圖可以等效大部分2x和3x的png圖片;
- 網路圖片選擇壓縮比更好的圖片格式,如webp
說明:PNG切圖不可能被完全替換,在表現顏色豐富圖片時候,PNG效果很不錯,其他詳見淺談iOS圖片優化
三、可執行檔案優化
1、優化手段1:編譯器優化
-
Xcode 支援編譯器層面的一些優化優化選項,可以讓我們介於更快的編譯速度 、更小的二進位制大小 和更快的執行速度 之間自由選擇想要進行的優化粒度;
-
在Xcode中,使用Clang 來編譯Objective-C,可以在 Build Setting -> Apple Clang - Code Generation ->Optimization Level 設定,Release下為Fastest Smallest[-Os] 。編譯器會開啟除了會明顯增加包大小以外的所有優化選項;
-
在Xcode中,使用SwiftLang 來編譯Swift語言,同樣也是基於 LLVM 後端的。Xcode 9.3 版本之後可以在Build Setting ->Optimization Level 設定,Release下為Optimize for Speed[-O] ,這可能會增加安裝包大小
No optimization[-Onone]:不進行優化,能保證較快的編譯速度。 Optimize for Speed[-O]:編譯器將會對程式碼的執行效率進行優化,一定程度上會增加包大小。 Optimize for Size[-Osize]:編譯器會盡可能減少包的大小並且最小限度影響程式碼的執行效率 複製程式碼
說明:Xcode 9.3/Swift4.1編譯器不是特別穩定,特別是開啟 Osize 選項之後,編譯器很多情況下會莫名其妙的崩潰(Segmentation fault),目前放棄 [-Osize],選擇[-O]
2、優化手段2:去除符號資訊
-
可執行檔案中的符號:程式中的所有的變數、類、函式、列舉、變數和地址對映關係 ,以及一些在除錯的時候使用到的用於定位程式碼在原始碼中的位置的除錯符號,符號和斷點定位以及堆疊符號化有很重要的關係。
-
Strip Style表示的是我們需要去除的符號的型別的選項,可以在Build Setting ->Strip Style設定, Release下為All Symbols ,其分為三個選擇項:
All Symbols: 去除所有符號,一般是在主工程中開啟。 Non-Global Symbols: 去除一些非全域性的 Symbol(保留全域性符號,Debug Symbols 同樣會被去除),連結時會被重定向的那些符號不會被去除,此選項是靜態庫/動態庫的建議選項。 Debug Symbols: 去除除錯符號,去除之後將無法斷點除錯。 複製程式碼
說明:iOS 的除錯符號是DWARF 格式的,使用 Xcode 編譯打包的時候會先通過可執行檔案的 Debug Map 獲取到所有物件檔案的位置,然後使用dysmutil 來將物件檔案中的 DWARF 提取出來生成 dSYM 檔案。
-
Strip Linked Product去除不必要的符號資訊,去除了符號資訊之後我們就只能使用 dSYM 來進行符號化了,所以需要將 Debug Information Format 修改為 DWARF with dSYM file。Release下為YES。
-
Strip Linked Product 選項在Deployment Postprocessing 設定為 YES 的時候才生效,而在 Archive 的時候 Xcode 總是會把 Deployment Postprocessing 設定為 YES,Debug下,Deployment Postprocessing 設定為 NO。
-
Strip Debug Symbols During Copy將那些拷貝進專案包的三方庫、資源或者 Extension 的Debug Symbol 去除掉,在Build Settings -> Strip Debug Symbols During Copy設定,Release下設定為YES。
-
Cocoapods 管理的動態庫(use_framework!)的情況就相對要特殊一點,因為 Cocoapods 中的的動態庫是使用自己實現的指令碼 Pods-xxx-frameworks.sh 來實現拷貝的,所以並不會走 Xcode 的流程,當然也就不受 Strip Debug Symbols During Copy 的影響。當然 Cocoapods 是原始碼管理的,所以只需要將原始碼 Target 中的 Strip Linked Product 設定為 YES 即可。
-
Strip Swift Symbols能幫助我們移除相應 Target 中的所有的 Swift 符號,這個選項也是預設開啟的。Strip Swift symbols需要在打包的釋出選項中勾選(預設勾選),在Swift ABI 穩定之前,Swift 標準庫是會打進目標檔案的。