iOS安裝包瘦身小記

閒散心如月,風光好自知css

原文連接html

1、安裝包組成分析

一、組成狀況

​ 將IPA包修改後綴名爲ZIP,解壓縮後,獲取payload中的App文件,查看App文件的內容,你會發現該文件主要包含如下內容git

  • 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 包組成一致
二、組成分析
  • 通常來講,可執行文件、圖片資源(asset.car)和動態庫的佔比最大,若是是Swift和OC混編,可執行文件比純OC大不少
  • 從優化的效果上看,優化圖片資源的ROI比較大,若是是首次優化,建議從圖片資源的優化開始。
  • 項目中使用Swift,會增長安裝包大小,由於FrameWork中會加入爲了支持 Swift 的動態庫集合,若是純Swift項目,不會引入這些東西。

2、資源文件優化

​ 理論上,資源文件包括:圖片**、視頻、**音頻和字體等;實際上,視頻和音頻文件通常不會集成到安裝包中,在安裝包中的資源文件主要是圖片。github

一、優化手段1:App Slicing
  • iOS 9以後提供了App Thinning三件套:App SlicingOn Demand ResoucesBitcode
App Thinning 理想 現實
App Slicing 將App Bundle資源根據不一樣的設備特性分爲不一樣的版本。對於圖片資源,會根據設備所需圖片分辨率不一樣分發給對應設備所需對應的圖片資源。 主要是圖片資源的Slicing,咱們有本身的方案,沒有采用
On Demand Resources App的資源只有要使用時才下載,若是其餘資源須要空間這些資源能夠被移除 更適合遊戲類App,項目沒有使用
Bitcode Bitcode能夠做爲中間產物一塊兒提交AppStore。包含Bitcode配置的程序將會在AppStore上被編譯和連接。Bitcode容許蘋果在後期從新優化咱們程序的二進制文件,而不須要咱們從新提交一個新的版本到AppStore上 使用BitCode的要求全部代碼都支持BitCode,改動項目較大,沒有使用

說明:能夠充分利用App Slicing實現圖片資源的瘦身web

  • 在項目中引入圖片時候,直接在 Assets.xcassets中添加就能夠(資源文件用Asset Catalog管理),這樣能使用到App Slicing功能,這樣當用戶從App Store上下載App時,能夠只下載適用於其設備的App架構版本和所需資源,從而減小App所佔的空間。
  • 在實踐中發現,有的新同窗在Assets.xcassets中引入@1x的圖片,iPhone手機目前須要的@2x和@3x圖片,因此@1x的圖片顯然是不須要的。
  • 在實踐中還發現,有的圖片資源遊離在Assets.xcassets以外,這些能夠考慮是否能夠放入Assets.xcassets中(大部分狀況下是能夠放入的)
二、優化手段2:Xcode編譯項
  • 由於絕大部分引入的圖片是PNG格式,Xcode 提供的給咱們兩個編譯選項來幫助壓縮 PNG 資源:後端

  • Compress PNG Files:設置爲YES,打包的時候自動對圖片進行無損壓縮,使用的工具爲 pngcrush,壓縮比仍是至關高的,比較流行的壓縮軟件 ImageOptim 也是使用 pngcrush 進行壓縮 PNG 的。數組

  • Remove Text Medadata From PNG Files:設置爲YES,能幫助咱們移除 PNG 資源的文本字符,好比圖像名稱、做者、版權、創做時間、註釋等信息。bash

  • 引入項目的PNG資源自動被 Xcode 進行壓縮了,可是若是是使用Bundle管理的資源,不會被Xcode壓縮,可使用tinypng壓縮。網絡

三、優化手段3:清理無用的資源
  • 及時清理不使用的圖片資源。使用相似LSUnusedResources 清理舊的圖片文件。
  • LSUnusedResources的思路是,先獲取圖片文件(imageset, jpg, png, gif)集合A,而後搜索代碼文件中全部字符串名稱獲得B,而後從A集合中排除集合B就獲得未使用的圖片資源。
四、優化手段4:圖片文件去重
  • 遍歷圖片文件,計算每一個文件的MD5值,而後以MD5值爲key,文件路徑存入key對應的數組;
  • 遍歷字典values,將value的數組大小大於1的路徑輸出,這樣就找到重複圖片的路徑了。
五、優化手段5:更適合的圖片格式
  • iconfont代替項目中純色小圖標,也省去不少@2x和@3x的圖片切圖。
  • PNG切圖的替換方案,如PDF矢量圖來代替大部分簡單的png切圖;而後在代碼中本身解碼並展現出來,一套PDF矢量圖能夠等效大部分2x和3x的png圖片;
  • 網絡圖片選擇壓縮比更好的圖片格式,如webp

說明:PNG切圖不可能被徹底替換,在表現顏色豐富圖片時候,PNG效果很不錯,其餘詳見淺談iOS圖片優化架構

3、可執行文件優化

一、優化手段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:去除符號信息
  • 可執行文件中的符號:程序中的全部的變量、類、函數、枚舉、變量和地址映射關係,以及一些在調試的時候使用到的用於定位代碼在源碼中的位置的調試符號,符號和斷點定位以及堆棧符號化有很重要的關係。

  • 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 標準庫是會打進目標文件的。

三、優化手段3:BitCode
  • Bitcode能夠做爲中間產物一塊兒提交AppStore。包含Bitcode配置的程序將會在AppStore上被編譯和連接。Bitcode容許蘋果在後期從新優化咱們程序的二進制文件,而不須要咱們從新提交一個新的版本到AppStore上。

  • 開啓 BitCode 以後編譯器後端(Backend)的工做都由 Apple 接管了。因此假如之後蘋果推出了新的 CPU 架構或者之後 LLVM 推出了一系列優化,咱們也再也不須要爲其發佈新的安裝包了。

  • 工程開啓 BitCode 以後必需要求全部打進 Bundle 的 Binary 都須要支持 BitCode,也就是說咱們依賴的靜態庫和動態庫都是含有 BitCode 的,否則就會打包失敗。對於 Cocoapods 等源碼管理工具來管理的依賴庫來講操做會比較簡單,咱們只須要開啓 Pods 工程中的 BitCode 就行。可是對於一些三方的閉源庫,咱們就無能爲力了。

  • 開啓 BitCode 以後,因爲最終的可執行文件是 Apple 自動生成的,同時產生新的符號表文件,因此咱們使用本來打包生成的 dSYM 符號化文件是沒法完成符號化的。因此咱們須要在上傳至 App Store 時須要勾選 Include app symbols for your application to receive symboilcated crash logs from Apple:勾選以後 Apple 會給咱們生成 dSYM,而後就能夠在 Xcode -> Organizer 或者 iTunes Connect 中下載對應的 dSYM 來進行符號化了。

四、優化手段4:清除無用代碼
  • Dead Code Stripping:Xcode 默認會開啓此選項,C/C++/Swift 等靜態語言編譯器會在 link 的時候移除未使用的代碼,可是對於 Objective-C 等動態語言是無效的。由於 Objective-C 是創建在運行時上面的,底層暴露給編譯器的都是 Runtime 源碼編譯結果,全部的部分應該都是會被判別爲有效代碼。

  • 掃描查找無用代碼:基本思路都是查找已經使用的方法/類和全部的類/方法,而後從全部的類/方法當中剔除已經使用的方法/類剩下的基本都是無用的類/方法,可是因爲 Objective-C 是動態語言,可使用字符串來調用類和方法,因此檢查結果通常都不是特別準確,須要二次確認。目前市面上的掃描的思路大體能夠分爲 3 種:

    • 基於 Clang 掃描
    • 基於可執行文件掃描
    • 基於源碼掃描
  • 及時下線不須要的功能,如完成使命的ABTest代碼、被產品拋棄的功能代碼等。

  • 移除不須要的系統庫和第三方庫。

五、優化手段5:代碼重構
  • 功能合併:類似功能的代碼,只需維護一份就能夠了。如定製通用UI組件,你們能夠有相似需求,能夠給通用UI組件的開發提,不必本身單獨實現。

End

一、優化以後
  • 保持良好的開發習慣。及時清理無用代碼和無效庫

  • 持續關注安裝包大小的變化,

  • 按期Review安裝包大小變化

  • 建議預警機制,監控每一個版本的體積大小,體積圖片忽然變大,要去找緣由。

二、參考資料

iOS App 瘦身實踐總結

iOS 安裝包瘦身(上篇)

iOS 安裝包瘦身(下篇)

相關文章
相關標籤/搜索