iOS安裝包瘦身

記錄一次安裝包大小優(yōu)化的實(shí)踐烂完。
維持安裝包體積是一個(gè)持續(xù)的過(guò)程,建立預(yù)警機(jī)制,監(jiān)控每個(gè)版本的體積大小诫咱。

資源文件優(yōu)化
圖片資源優(yōu)化
  1. 推薦通過(guò)FengNiao清理無(wú)用的圖片資源 onevcat/FengNiao
  • swift開(kāi)發(fā)候味,支持幀動(dòng)畫(huà)圖片匹配刃唤,如image_%d
  • 命令行工具,可以給 Xcode 添加 Run Script负溪,在每次構(gòu)建的時(shí)候自動(dòng)檢測(cè)/清理未使用的資源

FengNiao 的基本原理是查找出項(xiàng)目中所有使用到的字符串和項(xiàng)目中所有的資源文件透揣,兩者進(jìn)行匹配(完全匹配和模式匹配,模式匹配支持帶數(shù)字資源的前綴/中綴/后綴匹配)川抡,計(jì)算差集就為未使用的資源辐真。

  1. 推薦通過(guò)ImageOptim進(jìn)行圖片壓縮 ImageOptim
  • 壓縮項(xiàng)目中的JPG格式圖片能明顯減少安裝包大小
  • 壓縮項(xiàng)目中Assets內(nèi)的PNG格式圖片無(wú)明顯作用,對(duì)于大圖甚至產(chǎn)生負(fù)優(yōu)化

Xcode會(huì)自動(dòng)壓縮Assets內(nèi)的PNG格式圖片崖堤,但是Bundle內(nèi)的圖片資源仍需手動(dòng)壓縮侍咱。
對(duì)于三方庫(kù)內(nèi)的Bundle內(nèi)的圖片建議放置于Assets中。

  1. 大圖優(yōu)化
  • 切分大圖密幔,將圖片背景楔脯、文案改為代碼實(shí)現(xiàn)
  • 動(dòng)效資源圖片采用雪碧圖的方式存儲(chǔ)
  • 部分無(wú)透明度且無(wú)法拆分的背景大圖,采用JPG格式并有損壓縮至設(shè)計(jì)師可以接受的范圍內(nèi)
  1. 圖標(biāo)優(yōu)化
  • 通過(guò)修改tintcolor復(fù)用單色重復(fù)圖標(biāo)
  • 通過(guò)旋轉(zhuǎn)復(fù)用圖標(biāo)
  1. 推薦使用On-Demand Resources On-Demand Resources Guide

將 App 中的無(wú)需立即用到資源放在 App Store 云端上胯甩,然后你需要把資源標(biāo)記為不同的Tag昧廷,需要的時(shí)候才去下載相應(yīng)Tag的圖片。如游戲中的不同關(guān)卡資源偎箫。

  1. 建議將webp作為項(xiàng)目圖片格式
  • 壓縮率高木柬。支持有損和無(wú)損2種方式,比如將 Gif 圖可以轉(zhuǎn)換為 Animated WebP淹办,有損模式下可以減小 64%眉枕,無(wú)損模式下可以減小 19%
  • 支持 Alpha 透明和 24-bit 顏色數(shù),不會(huì)像 PNG8 那樣因?yàn)樯什粔虺霈F(xiàn)毛邊
  • CUP 消耗和解碼時(shí)間上會(huì)比 PNG 高2倍
視頻/音頻資源遠(yuǎn)端化

建議將視頻與音頻文件放置在服務(wù)器怜森,客戶(hù)端按需下載或者使用流播放速挑。

HTML5遠(yuǎn)端化

建議將HTML5資源放置在服務(wù)器,客戶(hù)端可以使用離線(xiàn)緩存的方式來(lái)緩存網(wǎng)頁(yè)資源到本地副硅。


代碼優(yōu)化
  1. 掃描未使用代碼

基本思路是基于 clang AST姥宝,追溯到函數(shù)的調(diào)用層級(jí),記錄所有定義的方法/類(lèi)和所有調(diào)用的方法/類(lèi)恐疲,再取差集伶授。

基本思路是Mach-O 文件中的 (__DATA,__objc_classlist) 段表示所有定義的類(lèi)断序, (__DATA.__objc_classrefs) 段表示所有引用的類(lèi)(繼承關(guān)系是在 __DATA.__objc_superrefs 中);使用的方法和引用的方法也是類(lèi)似原理糜烹。因此我們使用 otool 等命令逆向可執(zhí)行文件中引用到的類(lèi)/方法和所有定義的類(lèi)/方法违诗,然后計(jì)算差集。

  • 基于源碼掃描 fui

基本思路是對(duì)源碼文件進(jìn)行字符串匹配疮蹦。例如將 A *a诸迟、[A xxx]、NSStringFromClass("A")愕乎、objc_getClass("A") 等歸類(lèi)為使用的類(lèi)阵苇,@interface A : B 歸類(lèi)為定義的類(lèi),然后計(jì)算差集感论。

  • 通過(guò) AppCode 查找無(wú)用代碼 AppCode

查找出 AppCode 中無(wú)用的類(lèi)绅项、無(wú)用的方法甚至是無(wú)用的 import ,但是無(wú)法掃描通過(guò)字符串拼接方式來(lái)創(chuàng)建的類(lèi)和調(diào)用的方法比肄。

  1. Cocoapods 中的優(yōu)化選項(xiàng)配置

Cocoapods 的 project 文件在每次 pod install 或者 pod update 會(huì)重置快耿,所以需要 hook pod install 來(lái)設(shè)置 Pods 中每個(gè) Target 的編譯選項(xiàng):

post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings['ENABLE_BITCODE'] = 'YES'
      config.build_settings['STRIP_INSTALLED_PRODUCT'] = 'YES'
      config.build_settings['SWIFT_COMPILATION_MODE'] = 'wholemodule'
      config.build_settings['SWIFT_VERSION'] = '5.0'
      if config.name == 'Debug'
        config.build_settings['SWIFT_OPTIMIZATION_LEVEL'] = '-Onone'
        config.build_settings['GCC_OPTIMIZATION_LEVEL'] = '0'
        config.build_settings['COPY_PHASE_STRIP'] = 'NO'
        config.build_settings['DEPLOYMENT_POSTPROCESSING'] = 'NO'
        config.build_settings['GCC_GENERATE_DEBUGGING_SYMBOLS'] = 'YES'
      else
        config.build_settings['SWIFT_OPTIMIZATION_LEVEL'] = '-Osize'
        config.build_settings['GCC_OPTIMIZATION_LEVEL'] = 's'
        config.build_settings['COPY_PHASE_STRIP'] = 'YES'
        config.build_settings['DEPLOYMENT_POSTPROCESSING'] = 'YES'
        config.build_settings['GCC_GENERATE_DEBUGGING_SYMBOLS'] = 'NO'
      end
    end
  end
end
  1. 靜態(tài)庫(kù)瘦身

發(fā)布版本中刪除 i386、x86_64 是模擬器的指令集芳绩,只保留 armv7 和 arm64

  • 靜態(tài)庫(kù)指令集信息查看:lipo -info libname.a(或者libname.framework/libname)
  • 靜態(tài)庫(kù)拆分:lipo 靜態(tài)庫(kù)文件路徑 -thin CPU架構(gòu) -output 拆分后的靜態(tài)庫(kù)文件路徑
  • 靜態(tài)庫(kù)合并:lipo -create 靜態(tài)庫(kù)1文件路徑 靜態(tài)庫(kù)2文件路徑... 靜態(tài)庫(kù)n文件路徑 -output 合并后的靜態(tài)庫(kù)文件徑

4.iOS的指令集

  • 如果項(xiàng)目可以?xún)H支持iphone5s及以上設(shè)備掀亥,去除armv7/armv7s支持
arm64:iPhone6s | iphone6s plus|iPhone6| iPhone6 plus|iPhone5S | iPad Air| iPad mini2(iPad mini with Retina Display)
armv7s:iPhone5|iPhone5C|iPad4(iPad with Retina Display)
armv7:iPhone4|iPhone4S|iPad|iPad2|iPad3(The New iPad)|iPad mini|iPod Touch 3G|iPod Touch4

i386是針對(duì)intel通用微處理器32位處理器
x86_64是針對(duì)x86架構(gòu)的64位處理器

模擬器32位處理器測(cè)試需要i386架構(gòu),
模擬器64位處理器測(cè)試需要x86_64架構(gòu)妥色,
真機(jī)32位處理器需要armv7,或者armv7s架構(gòu)搪花,
真機(jī)64位處理器需要arm64架構(gòu)。

編譯優(yōu)化
  1. Clang/LLVM 編譯器優(yōu)化選項(xiàng)
    Xcode ?? Build Setting ??Apple Clang - Code Generation ?? Optimization Level 設(shè)置為Fastest Smallest[-Os]
  • None[-O0]
    Debug 默認(rèn)級(jí)別嘹害,不進(jìn)行任何優(yōu)化撮竿,直接將源代碼編譯到執(zhí)行文件中,結(jié)果不進(jìn)行任何重排笔呀,編譯時(shí)比較長(zhǎng)倚聚。主要用于調(diào)試程序,可以進(jìn)行設(shè)置斷點(diǎn)凿可、改變變量 、計(jì)算表達(dá)式等調(diào)試工作授账。
  • Fast[-O,O1]
    最常用的優(yōu)化級(jí)別枯跑,不考慮速度和文件大小權(quán)衡問(wèn)題。與-O0級(jí)別相比白热,它生成的文件更小敛助,可執(zhí)行的速度更快,編譯時(shí)間更少屋确。
  • Faster[-O2]
    在-O1級(jí)別基礎(chǔ)上再進(jìn)行優(yōu)化纳击,增加指令調(diào)度的優(yōu)化续扔。與-O1級(jí)別相,它生成的文件大小沒(méi)有變大焕数,編譯時(shí)間變長(zhǎng)了纱昧,編譯期間占用的內(nèi)存更多了,但程序的運(yùn)行速度有所提高堡赔。
  • Fastest[-O3]
    在-O2和-O1級(jí)別上進(jìn)行優(yōu)化识脆,該級(jí)別可能會(huì)提高程序的運(yùn)行速度,但是也會(huì)增加文件的大小善已。
  • Fastest Smallest[-Os]
    Release 默認(rèn)級(jí)別灼捂。這種級(jí)別用于在有限的內(nèi)存和磁盤(pán)空間下生成盡可能小的文件。由于使用了很好的緩存技術(shù)换团,它在某些情況下也會(huì)有很快的運(yùn)行速度悉稠。
  • Fastest, Aggressive Optimization[-Ofast]
    它是一種更為激進(jìn)的編譯參數(shù), 它以點(diǎn)浮點(diǎn)數(shù)的精度為代價(jià)。
  1. Swift Compiler - Code Generation
    Xcode -> Build Setting ->Swift Compiler - Code Generation -> Optimization Level 設(shè)置為Optimize for Size[-Osize]
  • No optimization[-Onone]:不進(jìn)行優(yōu)化艘包,能保證較快的編譯速度的猛。
  • Optimize for Speed[-O]:編譯器將會(huì)對(duì)代碼的執(zhí)行效率進(jìn)行優(yōu)化,一定程度上會(huì)增加包大小辑甜。
  • Optimize for Size[-Osize]:編譯器會(huì)盡可能減少包的大小并且最小限度影響代碼的執(zhí)行效率衰絮。
  1. Deployment
    Xcode ?? Build Setting ?? Deployment
  • Strip Linked Product & Deployment Postprocessing
    Strip Linked Product設(shè)置為YES,Deployment Postprocessing設(shè)置為NO

在 Archive 的時(shí)候 Xcode 總是會(huì)把 Deployment Postprocessing 設(shè)置為 YES 磷醋。所以我們可以打開(kāi) Strip Linked Product 并且把 Deployment Postprocessing 設(shè)置為 NO猫牡,而不用擔(dān)心調(diào)試的時(shí)候會(huì)影響斷點(diǎn)和符號(hào)化,同時(shí)打包的時(shí)候又會(huì)自動(dòng)去除符號(hào)信息邓线。

  • Strip Linked Product/Strip Debug Symbols During
    僅在Release環(huán)境設(shè)置為YES

與 Strip Linked Product 類(lèi)似淌友,但是這個(gè)是將那些拷貝進(jìn)項(xiàng)目包的三方庫(kù)、資源或者 Extension 的 Debug Symbol 去除掉骇陈,同樣也是使用的 strip 命令震庭。這個(gè)選項(xiàng)沒(méi)有前置條件,所以我們只需要在 Release 模式下開(kāi)啟你雌,不然就不能對(duì)三方庫(kù)進(jìn)行斷點(diǎn)調(diào)試和符號(hào)化了

去掉不必要的符號(hào)信息器联,可以減少可執(zhí)行文件大小,但去除了符號(hào)信息之后我們就只能使用 dSYM 來(lái)進(jìn)行符號(hào)化婿崭。

  1. Link-Time Optimization
    Xcode ?? Build Setting ??Apple Clang - Code Generation ??Link-Time Optimization設(shè)置為Incremental

Link-Time Optimization 是 LLVM 編譯器的一個(gè)特性拨拓,用于在 link 中間代碼時(shí),對(duì)全局代碼進(jìn)行優(yōu)化氓栈。這個(gè)優(yōu)化是自動(dòng)完成的渣磷,因此不需要修改現(xiàn)有的代碼;這個(gè)優(yōu)化也是高效的授瘦,因?yàn)榭梢栽谌忠暯窍聝?yōu)化代碼醋界。
開(kāi)啟這個(gè)優(yōu)化后竟宋,一方面減少了匯編代碼的體積,一方面提高了代碼的運(yùn)行效率.

  • 多余代碼去除(Dead code elimination):如果一段代碼分布在多個(gè)文件中形纺,但是從來(lái)沒(méi)有被使用丘侠,普通的 -O3 優(yōu)化方法不能發(fā)現(xiàn)跨中間代碼文件的多余代碼,因此是一個(gè)“局部?jī)?yōu)化”挡篓。但是Link-Time Optimization 技術(shù)可以在 link 時(shí)發(fā)現(xiàn)跨中間代碼文件的多余代碼婉陷。
  • 跨過(guò)程優(yōu)化(Interprocedural analysis and optimization):這是一個(gè)相對(duì)廣泛的概念。舉個(gè)例子來(lái)說(shuō)官研,如果一個(gè) if 方法的某個(gè)分支永不可能執(zhí)行秽澳,那么在最后生成的二進(jìn)制文件中就不應(yīng)該有這個(gè)分支的代碼。
  • 內(nèi)聯(lián)優(yōu)化(Inlining optimization):內(nèi)聯(lián)優(yōu)化形象來(lái)說(shuō)戏羽,就是在匯編中不使用 “call func_name” 語(yǔ)句担神,直接將外部方法內(nèi)的語(yǔ)句“復(fù)制”到調(diào)用者的代碼段內(nèi)。這樣做的好處是不用進(jìn)行調(diào)用函數(shù)前的壓棧始花、調(diào)用函數(shù)后的出棧操作妄讯,提高運(yùn)行效率與棧空間利用率
  1. Asset Catalog Compiler
    Xcode ?? Build Setting ??Asset Catalog Compiler ??Optimization設(shè)置為space

參考資料:
App Thinning in Xcode
網(wǎng)易云安裝包瘦身
微信安裝包瘦身
iOS 瘦身之道

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末酷宵,一起剝皮案震驚了整個(gè)濱河市亥贸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌浇垦,老刑警劉巖炕置,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異男韧,居然都是意外死亡朴摊,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)此虑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)甚纲,“玉大人,你說(shuō)我怎么就攤上這事朦前〗楦耍” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵韭寸,是天一觀的道長(zhǎng)春哨。 經(jīng)常有香客問(wèn)我,道長(zhǎng)棒仍,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任臭胜,我火速辦了婚禮莫其,結(jié)果婚禮上癞尚,老公的妹妹穿的比我還像新娘。我一直安慰自己乱陡,他們只是感情好浇揩,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著憨颠,像睡著了一般胳徽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上爽彤,一...
    開(kāi)封第一講書(shū)人閱讀 52,475評(píng)論 1 312
  • 那天养盗,我揣著相機(jī)與錄音审葬,去河邊找鬼蟋定。 笑死,一個(gè)胖子當(dāng)著我的面吹牛犁苏,可吹牛的內(nèi)容都是我干的嚷节。 我是一名探鬼主播聂儒,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼硫痰!你這毒婦竟也來(lái)了衩婚?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤效斑,失蹤者是張志新(化名)和其女友劉穎非春,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體鳍悠,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡税娜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了藏研。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片敬矩。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蠢挡,靈堂內(nèi)的尸體忽然破棺而出弧岳,到底是詐尸還是另有隱情,我是刑警寧澤业踏,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布禽炬,位于F島的核電站,受9級(jí)特大地震影響勤家,放射性物質(zhì)發(fā)生泄漏腹尖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一伐脖、第九天 我趴在偏房一處隱蔽的房頂上張望热幔。 院中可真熱鬧乐设,春花似錦、人聲如沸绎巨。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)场勤。三九已至戈锻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間和媳,已是汗流浹背格遭。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留窗价,地道東北人如庭。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像撼港,于是被迫代替她去往敵國(guó)和親坪它。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • 安裝包過(guò)大帝牡,不利于市場(chǎng)人員做推廣往毡,最近做了 iOS 安裝包瘦身的技術(shù)研究和實(shí)踐。iOS APP經(jīng)過(guò)編譯靶溜,打包文件中...
    iLees閱讀 1,384評(píng)論 0 5
  • 我被婚鬧了罩息! 我不是伴娘嗤详,我只是以同學(xué)的身份來(lái)參加婚禮,竟然莫名其妙的被婚鬧了瓷炮! 01 小A是我們宿舍第一個(gè)要準(zhǔn)備...
    瀟灑喵喵閱讀 1,085評(píng)論 2 0
  • 我記不清簡(jiǎn)書(shū)在我的手機(jī)待了多長(zhǎng)時(shí)間葱色,唯一的意識(shí)就是它待了很久,但我很少打開(kāi)它娘香,每天瀏覽的也就是那幾個(gè)固定的軟...
    顧予濃啊閱讀 177評(píng)論 0 1