iOS 包體縮小棵红,包體瘦身 2.0

前言

隨著APP的業(yè)務(wù)迭代凶赁,需求累積的越來越多,APP內(nèi)引入的庫(kù)或是各種業(yè)務(wù)功能代碼也累積的越來越多逆甜,APP的包體不可避免的增大虱肄。包體太大對(duì)于APP的推廣,用戶的下載使用意愿都會(huì)有一定的影響交煞,所以說包體瘦身是項(xiàng)目中無可避免的一項(xiàng)性能優(yōu)化咏窿。

首要工作:建立監(jiān)管體系

包體瘦身,并不是一個(gè)單純的技術(shù)項(xiàng)素征,或者說并不是一個(gè)單次的性能優(yōu)化需求集嵌,包體瘦身應(yīng)該是一個(gè)長(zhǎng)期的固定的工作內(nèi)容萝挤,在進(jìn)行實(shí)際的瘦身前,首先應(yīng)該實(shí)現(xiàn)一個(gè)對(duì)當(dāng)前APP大小的完善的監(jiān)控體系根欧,可以按照各個(gè)業(yè)務(wù)模塊怜珍、資源等方式,把整體的大小詳細(xì)的記錄下來凤粗,并且應(yīng)該有一個(gè)長(zhǎng)期的監(jiān)管體系酥泛。

實(shí)現(xiàn)監(jiān)管只要依賴對(duì)打包時(shí)生成的link map 文件。link map 是編譯鏈接時(shí)可以生成的一個(gè)txt文件侈沪,它生成的目的就是幫助程序員分析包體大小揭璃。link map 記錄了每個(gè)方法在當(dāng)前的二進(jìn)制架構(gòu)下占據(jù)的空間。通過分析link map,我們可以了解每個(gè)類甚至每個(gè)方法占據(jù)了多少安裝包空間亭罪。此外瘦馍,link map 還可以分析引進(jìn)的第三方庫(kù)的代碼空間占比,作為一個(gè)性能考察點(diǎn)应役。

Link map File: 我們編寫的源碼需要經(jīng)過編譯情组、鏈接,最終生成一個(gè)可執(zhí)行文件箩祥。在編譯階段院崇,每個(gè)類會(huì)生成對(duì)應(yīng)的.o文件(目標(biāo)文件)。在鏈接階段袍祖,會(huì)把.o文件和動(dòng)態(tài)庫(kù)鏈接在一起底瓣。Link Map File就是這樣一個(gè)記錄鏈接相關(guān)信息的純文本文件,里面記錄了可執(zhí)行文件的路徑蕉陋、CPU架構(gòu)捐凭、目標(biāo)文件、符號(hào)等信息凳鬓。

在Symbols部分茁肠,我們可以把類編號(hào)相同的size加起來,算出每個(gè)類或庫(kù)占用的大小缩举。在Object files部分根據(jù)類的編號(hào)可以查出對(duì)應(yīng)的類垦梆。分析的結(jié)果對(duì)App安裝包瘦身會(huì)有一些幫助。github上有很多實(shí)現(xiàn)了這樣功能的開源工具仅孩,實(shí)現(xiàn)原理很簡(jiǎn)單托猩,如有需要可自行查找。

監(jiān)管體系的目標(biāo)是把包體大小可視化辽慕,把各個(gè)業(yè)務(wù)占用的大小和占比用圖標(biāo)的方式展示出來站刑,并且每次業(yè)務(wù)庫(kù)發(fā)版的時(shí)候都加上代碼增量的提醒,主工程集成打包的時(shí)候同樣提示整個(gè)APP的代碼增量提醒鼻百。此外绞旅,不斷的查看比對(duì)工程構(gòu)建出來的ipa包摆尝,也是一個(gè)重要且有必要的監(jiān)控步驟,通過iOS_Images_Extractor來查看Assets.car因悲,通過MachOView可以查看編譯后的mach-o可執(zhí)行文件堕汞。

包體優(yōu)化: 瘦身方案

當(dāng)有了監(jiān)控體系后,我們對(duì)自己APP的大小就有大致概況的了解晃琳。此時(shí)就進(jìn)入到瘦身這一步了讯检。這一步網(wǎng)上的各個(gè)資料相當(dāng)?shù)亩啵@里總結(jié)一些常用的方案卫旱。

總的來說人灼,優(yōu)化的方向主要有四個(gè),資源的優(yōu)化顾翼,Xcode配置項(xiàng)投放,Mach-o文件的優(yōu)化以及業(yè)務(wù)層面的原生功能下線

資源優(yōu)化

主要是圖片資源和代碼源文件。

圖片資源主要優(yōu)化方向是:

  • 圖片壓縮

    • 使用更小的圖片格式适贸。常見的各種小Icon,尤其需要多種顏色的圖片采用 iconfont灸芳;webp也可以作為動(dòng)圖使用

    • 對(duì)PNG無損壓縮,對(duì)于包體優(yōu)化機(jī)會(huì)是沒意義的拜姿。因?yàn)閄code在打包時(shí)會(huì)先把PNG圖片解壓成Bitmap烙样,然后自行進(jìn)行圖片壓縮處理,所以圖片壓縮 只能采用有損壓縮的方式蕊肥,對(duì)圖片的源文件進(jìn)行處理谒获。例如頭條分享的方式:RGB with palette

  • 圖片云端下載

    • On Demand Resource
  • 無用圖片刪除,重復(fù)圖片篩選

  • Pods資源管理

    • 業(yè)務(wù)Pods庫(kù)中的資源不用resources_bundle的形式引入到主工程壁却,而是直接用resources方式集成究反,因?yàn)锳PPLE 在構(gòu)建 Assets.car時(shí)有優(yōu)化處理(比如:將若干張小圖片自動(dòng)合并為一張 Packed Image)

    • 錯(cuò)誤的使用cocoapods會(huì)帶來的圖片重復(fù)合并問題,簡(jiǎn)單來說就是Pod庫(kù)中的圖片資源既被當(dāng)做的了零散的PNG資源在主工程中儒洛,又被打進(jìn)了Assets.car的壓縮包中,這樣同一份文件就被引入了兩份狼速。這個(gè)問題最徹底的解決方案是通過解壓IPA以及包內(nèi)的Assets.car琅锻,通過工具對(duì)得到的所有資源圖做對(duì)比排查。
      正確的podspec舉例:s.resources = "Pods/Resources/xxx.xcassets"

      使用 https://github.com/devcxm/iOS-Images-Extractor 來解壓.car 壓縮包

無用代碼清理

無用代碼一般是指 無用類 和 無用方法向胡。業(yè)務(wù)迭代過程中恼蓬,難免會(huì)有業(yè)務(wù)下線的情況,雖然可以從業(yè)務(wù)層面即使下架僵芹,但是代碼層面的查找更詳細(xì)处硬,精確。

MachO文件中的__DATA段中有 objc_classrefsobjc_selrefs段拇派,分別近似于“被使用的類的集合”和“被使用的方法的集合”,同時(shí)也含有所有的類和方法的集合荷辕,通過取差集的方式可以篩選出未被使用的類和方法凿跳。

重復(fù)代碼

重復(fù)代碼是指功能類似的甚至是直接COPY的代碼,項(xiàng)目中的工具類往往是重災(zāi)區(qū)疮方。重復(fù)代碼最好使用第三方工具來排查控嗜,例如 PMD

Xcode 配置項(xiàng)

Xcode 有一些的配置項(xiàng)能夠帶來非常明顯的收益,不過需要結(jié)合項(xiàng)目的實(shí)際情況骡显,不能盲目使用疆栏。

  • LTO,即Link Time Optimization

    蘋果在2016年的WWDC What’s new in LLVM中詳細(xì)介紹了這一功能惫谤。

    LTO 帶來的優(yōu)化有:
    (1)將一些函數(shù)內(nèi)聯(lián)化
    (2)去除了一些無用代碼
    (3)對(duì)程序有全局的優(yōu)化作用

    LTO 的缺點(diǎn):
    會(huì)降低編譯鏈接的速度壁顶,因此只建議在打正式包時(shí)開啟;
    開啟了LTO之后溜歪,link map的可讀性明顯降低若专,多出了很多數(shù)字開頭的“類”(LTO的全局優(yōu)化導(dǎo)致的),導(dǎo)致我們還經(jīng)常需要手動(dòng)關(guān)閉LTO打包來閱讀link map痹愚。

  • Compress PNG Files (COMPRESS_PNG_FILES)

  • Optimization (ASSETCATALOG_COMPILER_OPTIMIZATION) 設(shè)置為space

  • Optimization Level, Release 環(huán)境設(shè)置為: Fastest, Smallest[-Os]富岳,這個(gè)是Xcode默認(rèn)的設(shè)置,這里可以設(shè)置為Oz(Smallest,Aggressive Size Optimizations[-Oz])

    Oz 是 Xcode 11 新增的編譯優(yōu)化選項(xiàng)拯腮。WWDC 2019 《What's New in Clang and LLVM》[3] 中對(duì) Oz 有過介紹窖式。Oz 的核心原理是對(duì)重復(fù)的連續(xù)機(jī)器指令外聯(lián)成函數(shù)進(jìn)行復(fù)用,和“內(nèi)聯(lián)函數(shù)”的原理正好相反动壤。因此萝喘,開啟 Oz,能減小二進(jìn)制的大小琼懊,但同時(shí)理論上會(huì)帶來執(zhí)行效率的額外消耗阁簸。對(duì)性能(CPU)敏感的代碼使用需要評(píng)估。

    蘋果給的參考數(shù)據(jù)是 4.5% 的包體積收益哼丈。

  • EXPORTED_SYMBOLS_FILE.

    Xcode Build Settings 中的 EXPORTED_SYMBOLS_FILE 配置启妹,控制著 Mach-O 中 __LINKEDIT 段中 Export Info 的信息。動(dòng)態(tài)鏈接器 dyld 在做符號(hào)綁定時(shí)醉旦,會(huì)讀取被綁定的動(dòng)態(tài)庫(kù)或可執(zhí)行文件的 Export Info 信息饶米,得到一個(gè)符號(hào)對(duì)應(yīng)的實(shí)際調(diào)用地址。如果正在被綁定的符號(hào)车胡,在目標(biāo)動(dòng)態(tài)庫(kù)的 Export Info 中缺失檬输,dyld 則會(huì)拋出異常,表現(xiàn)為 App 崩潰匈棘。

  • Build Settings中去掉異常支持丧慈,Enable C++ Exceptions和Enable Objective-C Exceptions設(shè)置為NO,Other C Flags添加-fno-exceptions

    注意:Enable C++ Excptions和Enable Objective-C Exceptions是指項(xiàng)目支持對(duì)錯(cuò)誤的異常處理主卫,比如try catch逃默、throw之類的鹃愤;所以如果項(xiàng)目中使用的有類似的異常處理的,這個(gè)關(guān)閉了之后會(huì)報(bào)錯(cuò)(Cannot use '@try' with Objective-C exceptions disabled)笑旺。包括宏定義中使用的有try{}昼浦、@finally{}之類的,比如@strongify等筒主,如果關(guān)閉了最后打包的時(shí)候也會(huì)報(bào)錯(cuò)关噪。

    -fno-exceptions的意思是禁用異常機(jī)制,參考gcc乌妙,同樣使兔,當(dāng)項(xiàng)目中有try thorw的時(shí)候,就不要設(shè)置這個(gè)選項(xiàng)為NO

  • Build Settings -> Architectures藤韵,Release下設(shè)置為arm64虐沥。去除32位。

  • Build Settings -> Generate Debug Symbols設(shè)置為NO泽艘。關(guān)閉生成調(diào)試符號(hào)欲险,關(guān)閉后無法生成DSYM,不建議關(guān)閉匹涮。

MACH-O 處理

1天试、二進(jìn)制段壓縮

Mach-O 文件占據(jù)了 Install Size 中很大一部分比例,但并不是文件中的每個(gè)段/節(jié)在程序啟動(dòng)的第一時(shí)間都要被用到然低∠裁浚可以在構(gòu)建過程中將 Mach-O 文件中的這部分段/節(jié)壓縮,然后只要在這些段被使用到之前將其解壓到內(nèi)存中雳攘,就能達(dá)到了減少包大小的效果带兜,同時(shí)也能保證程序正常運(yùn)行。由于蘋果的一些限制吨灭,我們目前只壓縮了 __TEXT,__gcc_except_tab__TEXT,__objc_methtype兩個(gè)節(jié)刚照,然后在 _dyld_register_func_for_add_image 的回調(diào)中對(duì)它進(jìn)行解壓。該方案累計(jì)優(yōu)化了 3.5 MB Install Size喧兄。

2无畔、__TEXT 段代碼遷移

安裝包經(jīng)過壓縮后的 Download Size 若超過 200 MB,在蜂窩網(wǎng)絡(luò)下載 App 就會(huì)受到限制繁莹,這對(duì)新增會(huì)有較大影響。在 2020 年下半年特幔,我們探索實(shí)踐了 __TEXT 段遷移技術(shù):在鏈接階段使用 -rename_section 選項(xiàng)將 __TEXT,__text 遷移到 __BD_TEXT,__text咨演,減少蘋果對(duì)可執(zhí)行文件的加密范圍,提升可執(zhí)行文件的壓縮效率蚯斯,從而減少 Download Size薄风。

使用該方案我們最終減少了 60 MB 的 Download Size 以及 2 MB 的 Install Size饵较。詳細(xì)的原理可以參考:《今日頭條優(yōu)化實(shí)踐:iOS 包大小二進(jìn)制優(yōu)化,一行代碼減少 60 MB 下載大小》

業(yè)務(wù)層面的原生功能下線

推進(jìn)產(chǎn)品進(jìn)行低收益需求下線

APP隨著多個(gè)版本的迭代遭赂,可能有很多冗余需求循诉,低收益甚至是零收益的需求隱藏在APP內(nèi),可以推動(dòng)產(chǎn)品撇他,也可以內(nèi)部代碼審查茄猫,去尋找代碼量大但是可下線的需求。

動(dòng)態(tài)化

把代碼文件當(dāng)做資源放到云端困肩,在APP啟動(dòng)的合適時(shí)機(jī)去判斷是否需要下載划纽,可以使用一些動(dòng)態(tài)化的語(yǔ)言來實(shí)現(xiàn)這個(gè)功能。不過有一些功能會(huì)要求在本地存放一些兜底文件锌畸,如果說兜底文件的大小本身過大的話勇劣,動(dòng)態(tài)化在包體瘦身方面的作用就是負(fù)的了。是否要采用動(dòng)態(tài)化實(shí)現(xiàn)某些功能潭枣,還是需要具體問題具體分析比默。

參考
https://www.infoq.cn/article/XUJL32hTDKYqAKz0hkMM
https://mp.weixin.qq.com/s?__biz=MzI1MzYzMjE0MQ==&mid=2247484366&idx=1&sn=5a2d0e981c733e9eaec274b835600e67&chksm=e9d0c82cdea7413ada372bb936541c2a49de664b38daa6137c179ab6177231fa8b00ddf9acbc&scene=21#wechat_redirect

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市盆犁,隨后出現(xiàn)的幾起案子命咐,更是在濱河造成了極大的恐慌,老刑警劉巖蚣抗,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侈百,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡翰铡,警方通過查閱死者的電腦和手機(jī)钝域,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來锭魔,“玉大人例证,你說我怎么就攤上這事∶耘酰” “怎么了织咧?”我有些...
    開封第一講書人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)漠秋。 經(jīng)常有香客問我笙蒙,道長(zhǎng),這世上最難降的妖魔是什么庆锦? 我笑而不...
    開封第一講書人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任捅位,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘艇搀。我一直安慰自己尿扯,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開白布焰雕。 她就那樣靜靜地躺著衷笋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪矩屁。 梳的紋絲不亂的頭發(fā)上辟宗,一...
    開封第一講書人閱讀 51,443評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音档插,去河邊找鬼慢蜓。 笑死,一個(gè)胖子當(dāng)著我的面吹牛郭膛,可吹牛的內(nèi)容都是我干的晨抡。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼则剃,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼耘柱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起棍现,我...
    開封第一講書人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤调煎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后己肮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體邢笙,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡她肯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年蒲列,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了膛锭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡艘绍,死狀恐怖赤拒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情诱鞠,我是刑警寧澤挎挖,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站航夺,受9級(jí)特大地震影響蕉朵,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜阳掐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一始衅、第九天 我趴在偏房一處隱蔽的房頂上張望堪伍。 院中可真熱鬧,春花似錦觅闽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至彻亲,卻和暖如春孕锄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背苞尝。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工畸肆, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人宙址。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓轴脐,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親抡砂。 傳聞我的和親對(duì)象是個(gè)殘疾皇子大咱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

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